5 * Copyright (C) 2013 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 #include <sys/types.h>
38 #include "dbus_helpers.h"
41 #define AGENT_INTERFACE "net.connman.Agent"
42 #define VPN_AGENT_INTERFACE "net.connman.vpn.Agent"
44 static DBusConnection *agent_connection;
46 struct agent_input_data {
47 const char *attribute;
50 connmanctl_input_func_t func;
54 struct agent_input_data *input;
61 GDBusMethodFunction pending_function;
64 static void request_input_ssid_return(char *input, void *user_data);
65 static void request_input_passphrase_return(char *input, void *user_data);
66 static void request_input_string_return(char *input, void *user_data);
75 REQUEST_INPUT_MAX = 6,
78 static struct agent_input_data agent_input_handler[] = {
79 { "Name", false, "Hidden SSID name? ", request_input_ssid_return },
80 { "Identity", false, "EAP username? ", request_input_string_return },
81 { "Passphrase", false, "Passphrase? ",
82 request_input_passphrase_return },
83 { "WPS", false, "WPS PIN (empty line for pushbutton)? " ,
84 request_input_string_return },
85 { "Username", false, "WISPr username? ", request_input_string_return },
86 { "Password", false, "WISPr password? ", request_input_string_return },
90 static struct agent_data agent_request = {
95 static struct agent_input_data vpnagent_input_handler[] = {
96 { "OpenConnect.Cookie", false, "OpenConnect Cookie? ",
97 request_input_string_return },
98 { "Username", false, "VPN username? ", request_input_string_return },
99 { "Password", false, "VPN password? ", request_input_string_return },
103 static struct agent_data vpn_agent_request = {
104 vpnagent_input_handler,
108 static int confirm_input(char *input)
115 for (i = 0; input[i] != '\0'; i++)
116 if (isspace(input[i]) == 0)
119 if (strcasecmp(&input[i], "yes") == 0 ||
120 strcasecmp(&input[i], "y") == 0)
123 if (strcasecmp(&input[i], "no") == 0 ||
124 strcasecmp(&input[i], "n") == 0)
130 static char *strip_path(char *path)
132 char *name = strrchr(path, '/');
141 static char *agent_path(void)
143 static char *path = NULL;
146 path = g_strdup_printf("/net/connman/connmanctl%d", getpid());
151 static void pending_message_remove(struct agent_data *request)
153 if (request->message != NULL) {
154 dbus_message_unref(request->message);
155 request->message = NULL;
158 if (request->reply != NULL) {
159 dbus_message_unref(request->reply);
160 request->reply = NULL;
164 static void pending_command_complete(char *message)
166 struct agent_data *next_request = NULL;
167 DBusMessage *pending_message;
168 GDBusMethodFunction pending_function;
170 __connmanctl_save_rl();
172 fprintf(stdout, "%s", message);
174 __connmanctl_redraw_rl();
176 if (__connmanctl_is_interactive() == true)
177 __connmanctl_command_mode();
179 __connmanctl_agent_mode("", NULL, NULL);
181 if (agent_request.message != NULL)
182 next_request = &agent_request;
183 else if (vpn_agent_request.message != NULL)
184 next_request = &vpn_agent_request;
186 if (next_request == NULL)
189 pending_message = next_request->message;
190 pending_function = next_request->pending_function;
191 next_request->pending_function = NULL;
193 pending_function(agent_connection, next_request->message,
196 dbus_message_unref(pending_message);
199 static bool handle_message(DBusMessage *message, struct agent_data *request,
200 GDBusMethodFunction function)
202 if (agent_request.pending_function == NULL &&
203 vpn_agent_request.pending_function == NULL)
206 request->message = dbus_message_ref(message);
207 request->pending_function = function;
212 static DBusMessage *agent_release(DBusConnection *connection,
213 DBusMessage *message, void *user_data)
215 struct agent_data *request = user_data;
217 if (handle_message(message, request, agent_release) == false)
220 g_dbus_unregister_interface(connection, agent_path(),
222 request->registered = false;
224 pending_message_remove(request);
226 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
227 pending_command_complete("Agent unregistered by ConnMan\n");
229 pending_command_complete("VPN Agent unregistered by ConnMan "
232 if (__connmanctl_is_interactive() == false)
235 return dbus_message_new_method_return(message);
238 static DBusMessage *agent_cancel(DBusConnection *connection,
239 DBusMessage *message, void *user_data)
241 struct agent_data *request = user_data;
243 if (handle_message(message, request, agent_cancel) == false)
246 pending_message_remove(request);
248 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
249 pending_command_complete("Agent request cancelled by "
252 pending_command_complete("VPN Agent request cancelled by "
255 return dbus_message_new_method_return(message);
258 static void request_browser_return(char *input, void *user_data)
260 struct agent_data *request = user_data;
262 switch (confirm_input(input)) {
264 g_dbus_send_reply(agent_connection, request->message,
268 g_dbus_send_error(agent_connection, request->message,
269 "net.connman.Agent.Error.Canceled", NULL);
275 pending_message_remove(request);
276 pending_command_complete("");
279 static DBusMessage *agent_request_browser(DBusConnection *connection,
280 DBusMessage *message, void *user_data)
282 struct agent_data *request = user_data;
283 DBusMessageIter iter;
286 if (handle_message(message, request, agent_request_browser) == false)
289 dbus_message_iter_init(message, &iter);
291 dbus_message_iter_get_basic(&iter, &service);
292 dbus_message_iter_next(&iter);
293 dbus_message_iter_get_basic(&iter, &url);
295 __connmanctl_save_rl();
296 fprintf(stdout, "Agent RequestBrowser %s\n", strip_path(service));
297 fprintf(stdout, " %s\n", url);
298 __connmanctl_redraw_rl();
300 request->message = dbus_message_ref(message);
301 __connmanctl_agent_mode("Connected (yes/no)? ",
302 request_browser_return, request);
307 static void report_error_return(char *input, void *user_data)
309 struct agent_data *request = user_data;
311 switch (confirm_input(input)) {
313 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
314 g_dbus_send_error(agent_connection, request->message,
315 "net.connman.Agent.Error.Retry", NULL);
317 g_dbus_send_error(agent_connection, request->message,
318 "net.connman.vpn.Agent.Error.Retry",
322 g_dbus_send_reply(agent_connection, request->message,
329 pending_message_remove(request);
330 pending_command_complete("");
333 static DBusMessage *agent_report_error(DBusConnection *connection,
334 DBusMessage *message, void *user_data)
336 struct agent_data *request = user_data;
337 DBusMessageIter iter;
338 char *path, *service, *error;
340 if (handle_message(message, request, agent_report_error) == false)
343 dbus_message_iter_init(message, &iter);
345 dbus_message_iter_get_basic(&iter, &path);
346 service = strip_path(path);
348 dbus_message_iter_next(&iter);
349 dbus_message_iter_get_basic(&iter, &error);
351 __connmanctl_save_rl();
352 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
353 fprintf(stdout, "Agent ReportError %s\n", service);
355 fprintf(stdout, "VPN Agent ReportError %s\n", service);
356 fprintf(stdout, " %s\n", error);
357 __connmanctl_redraw_rl();
359 request->message = dbus_message_ref(message);
360 __connmanctl_agent_mode("Retry (yes/no)? ", report_error_return,
366 static void request_input_next(struct agent_data *request)
370 for (i = 0; request->input[i].attribute != NULL; i++) {
371 if (request->input[i].requested == true) {
372 if(request->input[i].func != NULL)
373 __connmanctl_agent_mode(request->input[i].prompt,
374 request->input[i].func,
377 request->input[i].requested = false;
382 dbus_message_iter_close_container(&request->iter, &request->dict);
384 g_dbus_send_message(agent_connection, request->reply);
385 request->reply = NULL;
387 pending_message_remove(request);
388 pending_command_complete("");
390 __connmanctl_redraw_rl();
393 static void request_input_append(struct agent_data *request,
394 const char *attribute, char *value)
396 __connmanctl_dbus_append_dict_entry(&request->dict, attribute,
397 DBUS_TYPE_STRING, &value);
400 static void request_input_ssid_return(char *input,
403 struct agent_data *request = user_data;
409 if (len > 0 && len <= 32) {
410 request->input[SSID].requested = false;
411 request_input_append(request, request->input[SSID].attribute,
414 request_input_next(request);
418 static void request_input_passphrase_return(char *input, void *user_data)
420 struct agent_data *request = user_data;
423 /* TBD passphrase length checking */
428 if (len == 0 && request->input[WPS].requested == false)
431 request->input[PASSPHRASE].requested = false;
434 request_input_append(request,
435 request->input[PASSPHRASE].attribute, input);
437 request->input[WPS].requested = false;
440 request_input_next(request);
443 static void request_input_string_return(char *input, void *user_data)
445 struct agent_data *request = user_data;
448 for (i = 0; request->input[i].attribute != NULL; i++) {
449 if (request->input[i].requested == true) {
450 request_input_append(request,
451 request->input[i].attribute, input);
452 request->input[i].requested = false;
457 request_input_next(request);
460 static DBusMessage *agent_request_input(DBusConnection *connection,
461 DBusMessage *message, void *user_data)
463 struct agent_data *request = user_data;
464 DBusMessageIter iter, dict, entry, variant;
465 char *service, *str, *field;
466 DBusMessageIter dict_entry, field_entry, field_value;
467 char *argument, *value, *attr_type;
471 if (handle_message(message, request, agent_request_input) == false)
474 dbus_message_iter_init(message, &iter);
476 dbus_message_iter_get_basic(&iter, &str);
477 service = strip_path(str);
479 dbus_message_iter_next(&iter);
480 dbus_message_iter_recurse(&iter, &dict);
482 __connmanctl_save_rl();
483 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
484 fprintf(stdout, "Agent RequestInput %s\n", service);
486 fprintf(stdout, "VPN Agent RequestInput %s\n", service);
487 __connmanctl_dbus_print(&dict, " ", " = ", "\n");
488 fprintf(stdout, "\n");
490 dbus_message_iter_recurse(&iter, &dict);
492 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
494 dbus_message_iter_recurse(&dict, &entry);
496 dbus_message_iter_get_basic(&entry, &field);
498 dbus_message_iter_next(&entry);
500 dbus_message_iter_recurse(&entry, &variant);
501 dbus_message_iter_recurse(&variant, &dict_entry);
503 while (dbus_message_iter_get_arg_type(&dict_entry)
504 == DBUS_TYPE_DICT_ENTRY) {
505 dbus_message_iter_recurse(&dict_entry, &field_entry);
507 dbus_message_iter_get_basic(&field_entry, &argument);
509 dbus_message_iter_next(&field_entry);
511 dbus_message_iter_recurse(&field_entry, &field_value);
513 if (strcmp(argument, "Type") == 0) {
514 dbus_message_iter_get_basic(&field_value,
516 attr_type = g_strdup(value);
519 dbus_message_iter_next(&dict_entry);
522 for (i = 0; request->input[i].attribute != NULL; i++) {
523 if (strcmp(field, request->input[i].attribute) == 0) {
524 request->input[i].requested = true;
532 dbus_message_iter_next(&dict);
535 request->reply = dbus_message_new_method_return(message);
536 dbus_message_iter_init_append(request->reply, &request->iter);
538 dbus_message_iter_open_container(&request->iter, DBUS_TYPE_ARRAY,
539 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
540 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
541 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
544 request_input_next(request);
549 static const GDBusMethodTable agent_methods[] = {
550 { GDBUS_ASYNC_METHOD("Release", NULL, NULL, agent_release) },
551 { GDBUS_ASYNC_METHOD("Cancel", NULL, NULL, agent_cancel) },
552 { GDBUS_ASYNC_METHOD("RequestBrowser",
553 GDBUS_ARGS({ "service", "o" },
555 NULL, agent_request_browser) },
556 { GDBUS_ASYNC_METHOD("ReportError",
557 GDBUS_ARGS({ "service", "o" },
559 NULL, agent_report_error) },
560 { GDBUS_ASYNC_METHOD("RequestInput",
561 GDBUS_ARGS({ "service", "o" },
562 { "fields", "a{sv}" }),
563 GDBUS_ARGS({ "fields", "a{sv}" }),
564 agent_request_input) },
568 static int agent_register_return(DBusMessageIter *iter, const char *error,
571 DBusConnection *connection = user_data;
574 g_dbus_unregister_interface(connection, agent_path(),
576 fprintf(stderr, "Error registering Agent: %s\n", error);
580 agent_request.registered = true;
581 fprintf(stdout, "Agent registered\n");
586 int __connmanctl_agent_register(DBusConnection *connection)
588 char *path = agent_path();
591 if (agent_request.registered == true) {
592 fprintf(stderr, "Agent already registered\n");
596 agent_connection = connection;
598 if (g_dbus_register_interface(connection, path,
599 AGENT_INTERFACE, agent_methods,
600 NULL, NULL, &agent_request,
602 fprintf(stderr, "Error: Failed to register Agent callbacks\n");
606 result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
607 CONNMAN_PATH, "net.connman.Manager", "RegisterAgent",
608 agent_register_return, connection,
609 DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
611 if (result != -EINPROGRESS) {
612 g_dbus_unregister_interface(connection, agent_path(),
615 fprintf(stderr, "Error: Failed to register Agent\n");
621 static int agent_unregister_return(DBusMessageIter *iter, const char *error,
625 fprintf(stderr, "Error unregistering Agent: %s\n", error);
629 agent_request.registered = false;
630 fprintf(stdout, "Agent unregistered\n");
635 int __connmanctl_agent_unregister(DBusConnection *connection)
637 char *path = agent_path();
640 if (agent_request.registered == false) {
641 fprintf(stderr, "Agent not registered\n");
645 g_dbus_unregister_interface(connection, agent_path(), AGENT_INTERFACE);
647 result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
648 CONNMAN_PATH, "net.connman.Manager", "UnregisterAgent",
649 agent_unregister_return, NULL,
650 DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
652 if (result != -EINPROGRESS)
653 fprintf(stderr, "Error: Failed to unregister Agent\n");
658 static const GDBusMethodTable vpn_agent_methods[] = {
659 { GDBUS_ASYNC_METHOD("Release", NULL, NULL, agent_release) },
660 { GDBUS_ASYNC_METHOD("Cancel", NULL, NULL, agent_cancel) },
661 { GDBUS_ASYNC_METHOD("ReportError",
662 GDBUS_ARGS({ "service", "o" },
664 NULL, agent_report_error) },
665 { GDBUS_ASYNC_METHOD("RequestInput",
666 GDBUS_ARGS({ "service", "o" },
667 { "fields", "a{sv}" }),
668 GDBUS_ARGS({ "fields", "a{sv}" }),
669 agent_request_input) },
673 static int vpn_agent_register_return(DBusMessageIter *iter, const char *error,
676 DBusConnection *connection = user_data;
679 g_dbus_unregister_interface(connection, agent_path(),
680 VPN_AGENT_INTERFACE);
681 fprintf(stderr, "Error registering VPN Agent: %s\n", error);
685 vpn_agent_request.registered = true;
686 fprintf(stdout, "VPN Agent registered\n");
691 int __connmanctl_vpn_agent_register(DBusConnection *connection)
693 char *path = agent_path();
696 if (vpn_agent_request.registered == true) {
697 fprintf(stderr, "VPN Agent already registered\n");
701 agent_connection = connection;
703 if (g_dbus_register_interface(connection, path,
704 VPN_AGENT_INTERFACE, vpn_agent_methods,
705 NULL, NULL, &vpn_agent_request,
707 fprintf(stderr, "Error: Failed to register VPN Agent "
712 result = __connmanctl_dbus_method_call(connection, VPN_SERVICE,
713 VPN_PATH, "net.connman.vpn.Manager", "RegisterAgent",
714 vpn_agent_register_return, connection,
715 DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
717 if (result != -EINPROGRESS) {
718 g_dbus_unregister_interface(connection, agent_path(),
719 VPN_AGENT_INTERFACE);
721 fprintf(stderr, "Error: Failed to register VPN Agent\n");
727 static int vpn_agent_unregister_return(DBusMessageIter *iter,
728 const char *error, void *user_data)
731 fprintf(stderr, "Error unregistering VPN Agent: %s\n", error);
735 vpn_agent_request.registered = false;
736 fprintf(stdout, "VPN Agent unregistered\n");
741 int __connmanctl_vpn_agent_unregister(DBusConnection *connection)
743 char *path = agent_path();
746 if (vpn_agent_request.registered == false) {
747 fprintf(stderr, "VPN Agent not registered\n");
751 g_dbus_unregister_interface(connection, agent_path(),
752 VPN_AGENT_INTERFACE);
754 result = __connmanctl_dbus_method_call(connection, VPN_SERVICE,
755 VPN_PATH, "net.connman.vpn.Manager", "UnregisterAgent",
756 vpn_agent_unregister_return, NULL,
757 DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
759 if (result != -EINPROGRESS)
760 fprintf(stderr, "Error: Failed to unregister VPN Agent\n");