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 { "OpenConnect.ServerCert", false,
99 "OpenConnect server certificate hash? ",
100 request_input_string_return },
101 { "OpenConnect.VPNHost", false, "OpenConnect VPN server? ",
102 request_input_string_return },
103 { "Username", false, "VPN username? ", request_input_string_return },
104 { "Password", false, "VPN password? ", request_input_string_return },
108 static struct agent_data vpn_agent_request = {
109 vpnagent_input_handler,
113 static int confirm_input(char *input)
120 for (i = 0; input[i] != '\0'; i++)
121 if (isspace(input[i]) == 0)
124 if (strcasecmp(&input[i], "yes") == 0 ||
125 strcasecmp(&input[i], "y") == 0)
128 if (strcasecmp(&input[i], "no") == 0 ||
129 strcasecmp(&input[i], "n") == 0)
135 static char *strip_path(char *path)
137 char *name = strrchr(path, '/');
146 static char *agent_path(void)
148 static char *path = NULL;
151 path = g_strdup_printf("/net/connman/connmanctl%d", getpid());
156 static void pending_message_remove(struct agent_data *request)
158 if (request->message) {
159 dbus_message_unref(request->message);
160 request->message = NULL;
163 if (request->reply) {
164 dbus_message_unref(request->reply);
165 request->reply = NULL;
169 static void pending_command_complete(char *message)
171 struct agent_data *next_request = NULL;
172 DBusMessage *pending_message;
173 GDBusMethodFunction pending_function;
175 __connmanctl_save_rl();
177 fprintf(stdout, "%s", message);
179 __connmanctl_redraw_rl();
181 if (__connmanctl_is_interactive() == true)
182 __connmanctl_command_mode();
184 __connmanctl_agent_mode("", NULL, NULL);
186 if (agent_request.message)
187 next_request = &agent_request;
188 else if (vpn_agent_request.message)
189 next_request = &vpn_agent_request;
194 pending_message = next_request->message;
195 pending_function = next_request->pending_function;
196 next_request->pending_function = NULL;
198 pending_function(agent_connection, next_request->message,
201 dbus_message_unref(pending_message);
204 static bool handle_message(DBusMessage *message, struct agent_data *request,
205 GDBusMethodFunction function)
207 if (!agent_request.pending_function &&
208 !vpn_agent_request.pending_function)
211 request->message = dbus_message_ref(message);
212 request->pending_function = function;
217 static DBusMessage *agent_release(DBusConnection *connection,
218 DBusMessage *message, void *user_data)
220 struct agent_data *request = user_data;
222 if (handle_message(message, request, agent_release) == false)
225 g_dbus_unregister_interface(connection, agent_path(),
227 request->registered = false;
229 pending_message_remove(request);
231 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
232 pending_command_complete("Agent unregistered by ConnMan\n");
234 pending_command_complete("VPN Agent unregistered by ConnMan "
237 if (__connmanctl_is_interactive() == false)
240 return dbus_message_new_method_return(message);
243 static DBusMessage *agent_cancel(DBusConnection *connection,
244 DBusMessage *message, void *user_data)
246 struct agent_data *request = user_data;
248 if (handle_message(message, request, agent_cancel) == false)
251 pending_message_remove(request);
253 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
254 pending_command_complete("Agent request cancelled by "
257 pending_command_complete("VPN Agent request cancelled by "
260 return dbus_message_new_method_return(message);
263 static void request_browser_return(char *input, void *user_data)
265 struct agent_data *request = user_data;
267 switch (confirm_input(input)) {
269 g_dbus_send_reply(agent_connection, request->message,
273 g_dbus_send_error(agent_connection, request->message,
274 "net.connman.Agent.Error.Canceled", NULL);
280 pending_message_remove(request);
281 pending_command_complete("");
284 static DBusMessage *agent_request_browser(DBusConnection *connection,
285 DBusMessage *message, void *user_data)
287 struct agent_data *request = user_data;
288 DBusMessageIter iter;
291 if (handle_message(message, request, agent_request_browser) == false)
294 dbus_message_iter_init(message, &iter);
296 dbus_message_iter_get_basic(&iter, &service);
297 dbus_message_iter_next(&iter);
298 dbus_message_iter_get_basic(&iter, &url);
300 __connmanctl_save_rl();
301 fprintf(stdout, "Agent RequestBrowser %s\n", strip_path(service));
302 fprintf(stdout, " %s\n", url);
303 __connmanctl_redraw_rl();
305 request->message = dbus_message_ref(message);
306 __connmanctl_agent_mode("Connected (yes/no)? ",
307 request_browser_return, request);
312 static void report_error_return(char *input, void *user_data)
314 struct agent_data *request = user_data;
316 switch (confirm_input(input)) {
318 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
319 g_dbus_send_error(agent_connection, request->message,
320 "net.connman.Agent.Error.Retry", NULL);
322 g_dbus_send_error(agent_connection, request->message,
323 "net.connman.vpn.Agent.Error.Retry",
327 g_dbus_send_reply(agent_connection, request->message,
334 pending_message_remove(request);
335 pending_command_complete("");
338 static DBusMessage *agent_report_error(DBusConnection *connection,
339 DBusMessage *message, void *user_data)
341 struct agent_data *request = user_data;
342 DBusMessageIter iter;
343 char *path, *service, *error;
345 if (handle_message(message, request, agent_report_error) == false)
348 dbus_message_iter_init(message, &iter);
350 dbus_message_iter_get_basic(&iter, &path);
351 service = strip_path(path);
353 dbus_message_iter_next(&iter);
354 dbus_message_iter_get_basic(&iter, &error);
356 __connmanctl_save_rl();
357 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
358 fprintf(stdout, "Agent ReportError %s\n", service);
360 fprintf(stdout, "VPN Agent ReportError %s\n", service);
361 fprintf(stdout, " %s\n", error);
362 __connmanctl_redraw_rl();
364 request->message = dbus_message_ref(message);
365 __connmanctl_agent_mode("Retry (yes/no)? ", report_error_return,
371 static DBusMessage *agent_report_peer_error(DBusConnection *connection,
372 DBusMessage *message, void *user_data)
374 struct agent_data *request = user_data;
375 char *path, *peer, *error;
376 DBusMessageIter iter;
378 if (handle_message(message, request,
379 agent_report_peer_error) == false)
382 dbus_message_iter_init(message, &iter);
384 dbus_message_iter_get_basic(&iter, &path);
385 peer = strip_path(path);
387 dbus_message_iter_next(&iter);
388 dbus_message_iter_get_basic(&iter, &error);
390 __connmanctl_save_rl();
391 fprintf(stdout, "Agent ReportPeerError %s\n", peer);
392 fprintf(stdout, " %s\n", error);
393 __connmanctl_redraw_rl();
395 request->message = dbus_message_ref(message);
396 __connmanctl_agent_mode("Retry (yes/no)? ",
397 report_error_return, request);
401 static void request_input_next(struct agent_data *request)
405 for (i = 0; request->input[i].attribute; i++) {
406 if (request->input[i].requested == true) {
407 if (request->input[i].func)
408 __connmanctl_agent_mode(request->input[i].prompt,
409 request->input[i].func,
412 request->input[i].requested = false;
417 dbus_message_iter_close_container(&request->iter, &request->dict);
419 g_dbus_send_message(agent_connection, request->reply);
420 request->reply = NULL;
422 pending_message_remove(request);
423 pending_command_complete("");
425 __connmanctl_redraw_rl();
428 static void request_input_append(struct agent_data *request,
429 const char *attribute, char *value)
431 __connmanctl_dbus_append_dict_entry(&request->dict, attribute,
432 DBUS_TYPE_STRING, &value);
435 static void request_input_ssid_return(char *input,
438 struct agent_data *request = user_data;
444 if (len > 0 && len <= 32) {
445 request->input[SSID].requested = false;
446 request_input_append(request, request->input[SSID].attribute,
449 request_input_next(request);
453 static void request_input_passphrase_return(char *input, void *user_data)
455 struct agent_data *request = user_data;
458 /* TBD passphrase length checking */
463 if (len == 0 && request->input[WPS].requested == false)
466 request->input[PASSPHRASE].requested = false;
469 request_input_append(request,
470 request->input[PASSPHRASE].attribute, input);
472 request->input[WPS].requested = false;
475 request_input_next(request);
478 static void request_input_string_return(char *input, void *user_data)
480 struct agent_data *request = user_data;
483 for (i = 0; request->input[i].attribute; i++) {
484 if (request->input[i].requested == true) {
485 request_input_append(request,
486 request->input[i].attribute, input);
487 request->input[i].requested = false;
492 request_input_next(request);
495 static void parse_agent_request(struct agent_data *request,
496 DBusMessageIter *iter)
498 DBusMessageIter dict, entry, variant, dict_entry;
499 DBusMessageIter field_entry, field_value;
500 char *field, *argument, *value;
501 char *attr_type = NULL;
504 dbus_message_iter_recurse(iter, &dict);
506 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
508 dbus_message_iter_recurse(&dict, &entry);
510 dbus_message_iter_get_basic(&entry, &field);
512 dbus_message_iter_next(&entry);
514 dbus_message_iter_recurse(&entry, &variant);
515 dbus_message_iter_recurse(&variant, &dict_entry);
517 while (dbus_message_iter_get_arg_type(&dict_entry)
518 == DBUS_TYPE_DICT_ENTRY) {
519 dbus_message_iter_recurse(&dict_entry, &field_entry);
521 dbus_message_iter_get_basic(&field_entry, &argument);
523 dbus_message_iter_next(&field_entry);
525 dbus_message_iter_recurse(&field_entry, &field_value);
527 if (strcmp(argument, "Type") == 0) {
528 dbus_message_iter_get_basic(&field_value,
530 attr_type = g_strdup(value);
533 dbus_message_iter_next(&dict_entry);
536 for (i = 0; request->input[i].attribute; i++) {
537 if (strcmp(field, request->input[i].attribute) == 0) {
538 request->input[i].requested = true;
546 dbus_message_iter_next(&dict);
550 static DBusMessage *agent_request_input(DBusConnection *connection,
551 DBusMessage *message, void *user_data)
553 struct agent_data *request = user_data;
554 DBusMessageIter iter, dict;
557 if (handle_message(message, request, agent_request_input) == false)
560 dbus_message_iter_init(message, &iter);
562 dbus_message_iter_get_basic(&iter, &str);
563 service = strip_path(str);
565 dbus_message_iter_next(&iter);
566 dbus_message_iter_recurse(&iter, &dict);
568 __connmanctl_save_rl();
569 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
570 fprintf(stdout, "Agent RequestInput %s\n", service);
572 fprintf(stdout, "VPN Agent RequestInput %s\n", service);
573 __connmanctl_dbus_print(&dict, " ", " = ", "\n");
574 fprintf(stdout, "\n");
576 parse_agent_request(request, &iter);
578 request->reply = dbus_message_new_method_return(message);
579 dbus_message_iter_init_append(request->reply, &request->iter);
581 dbus_message_iter_open_container(&request->iter, DBUS_TYPE_ARRAY,
582 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
583 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
584 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
587 request_input_next(request);
592 static void request_authorization_return(char *input, void *user_data)
594 struct agent_data *request = user_data;
596 switch (confirm_input(input)) {
598 request->reply = dbus_message_new_method_return(
600 dbus_message_iter_init_append(request->reply, &request->iter);
602 dbus_message_iter_open_container(&request->iter,
604 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
605 DBUS_TYPE_STRING_AS_STRING
606 DBUS_TYPE_VARIANT_AS_STRING
607 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
609 dbus_message_iter_close_container(&request->iter,
611 g_dbus_send_message(agent_connection, request->reply);
612 request->reply = NULL;
615 g_dbus_send_error(agent_connection, request->message,
616 "net.connman.Agent.Error.Rejected", NULL);
619 g_dbus_send_error(agent_connection, request->message,
620 "net.connman.Agent.Error.Canceled", NULL);
624 pending_message_remove(request);
625 pending_command_complete("");
629 agent_request_peer_authorization(DBusConnection *connection,
630 DBusMessage *message, void *user_data)
632 struct agent_data *request = user_data;
633 DBusMessageIter iter, dict;
638 if (handle_message(message, request, agent_request_peer_authorization)
642 dbus_message_iter_init(message, &iter);
644 dbus_message_iter_get_basic(&iter, &str);
645 peer = strip_path(str);
647 dbus_message_iter_next(&iter);
648 dbus_message_iter_recurse(&iter, &dict);
650 __connmanctl_save_rl();
651 fprintf(stdout, "Agent RequestPeerAuthorization %s\n", peer);
652 __connmanctl_dbus_print(&dict, " ", " = ", "\n");
653 fprintf(stdout, "\n");
655 parse_agent_request(request, &iter);
657 for (input = false, i = 0; request->input[i].attribute; i++) {
658 if (request->input[i].requested == true) {
665 request->message = dbus_message_ref(message);
666 __connmanctl_agent_mode("Accept connection (yes/no)? ",
667 request_authorization_return, request);
671 request->reply = dbus_message_new_method_return(message);
672 dbus_message_iter_init_append(request->reply, &request->iter);
674 dbus_message_iter_open_container(&request->iter, DBUS_TYPE_ARRAY,
675 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
676 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
677 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
680 request_input_next(request);
685 static const GDBusMethodTable agent_methods[] = {
686 { GDBUS_ASYNC_METHOD("Release", NULL, NULL, agent_release) },
687 { GDBUS_ASYNC_METHOD("Cancel", NULL, NULL, agent_cancel) },
688 { GDBUS_ASYNC_METHOD("RequestBrowser",
689 GDBUS_ARGS({ "service", "o" },
691 NULL, agent_request_browser) },
692 { GDBUS_ASYNC_METHOD("ReportError",
693 GDBUS_ARGS({ "service", "o" },
695 NULL, agent_report_error) },
696 { GDBUS_ASYNC_METHOD("ReportPeerError",
697 GDBUS_ARGS({ "peer", "o" },
699 NULL, agent_report_peer_error) },
700 { GDBUS_ASYNC_METHOD("RequestInput",
701 GDBUS_ARGS({ "service", "o" },
702 { "fields", "a{sv}" }),
703 GDBUS_ARGS({ "fields", "a{sv}" }),
704 agent_request_input) },
705 { GDBUS_ASYNC_METHOD("RequestPeerAuthorization",
706 GDBUS_ARGS({ "peer", "o" },
707 { "fields", "a{sv}" }),
708 GDBUS_ARGS({ "fields", "a{sv}" }),
709 agent_request_peer_authorization) },
713 static int agent_register_return(DBusMessageIter *iter, int errnum,
714 const char *error, void *user_data)
716 DBusConnection *connection = user_data;
719 g_dbus_unregister_interface(connection, agent_path(),
721 fprintf(stderr, "Error registering Agent: %s\n", error);
725 agent_request.registered = true;
726 fprintf(stdout, "Agent registered\n");
731 static void append_path(DBusMessageIter *iter, void *user_data)
733 const char *path = user_data;
735 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
738 int __connmanctl_agent_register(DBusConnection *connection)
740 char *path = agent_path();
743 if (agent_request.registered == true) {
744 fprintf(stderr, "Agent already registered\n");
748 agent_connection = connection;
750 if (!g_dbus_register_interface(connection, path,
751 AGENT_INTERFACE, agent_methods,
752 NULL, NULL, &agent_request, NULL)) {
753 fprintf(stderr, "Error: Failed to register Agent callbacks\n");
757 result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
758 CONNMAN_PATH, "net.connman.Manager", "RegisterAgent",
759 agent_register_return, connection, append_path, path);
761 if (result != -EINPROGRESS) {
762 g_dbus_unregister_interface(connection, agent_path(),
765 fprintf(stderr, "Error: Failed to register Agent\n");
771 static int agent_unregister_return(DBusMessageIter *iter, int errnum,
772 const char *error, void *user_data)
775 fprintf(stderr, "Error unregistering Agent: %s\n", error);
779 agent_request.registered = false;
780 fprintf(stdout, "Agent unregistered\n");
785 int __connmanctl_agent_unregister(DBusConnection *connection)
787 char *path = agent_path();
790 if (agent_request.registered == false) {
791 fprintf(stderr, "Agent not registered\n");
795 g_dbus_unregister_interface(connection, agent_path(), AGENT_INTERFACE);
797 result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
798 CONNMAN_PATH, "net.connman.Manager", "UnregisterAgent",
799 agent_unregister_return, NULL, append_path, path);
801 if (result != -EINPROGRESS)
802 fprintf(stderr, "Error: Failed to unregister Agent\n");
807 static const GDBusMethodTable vpn_agent_methods[] = {
808 { GDBUS_ASYNC_METHOD("Release", NULL, NULL, agent_release) },
809 { GDBUS_ASYNC_METHOD("Cancel", NULL, NULL, agent_cancel) },
810 { GDBUS_ASYNC_METHOD("ReportError",
811 GDBUS_ARGS({ "service", "o" },
813 NULL, agent_report_error) },
814 { GDBUS_ASYNC_METHOD("RequestInput",
815 GDBUS_ARGS({ "service", "o" },
816 { "fields", "a{sv}" }),
817 GDBUS_ARGS({ "fields", "a{sv}" }),
818 agent_request_input) },
822 static int vpn_agent_register_return(DBusMessageIter *iter, int errnum,
823 const char *error, void *user_data)
825 DBusConnection *connection = user_data;
828 g_dbus_unregister_interface(connection, agent_path(),
829 VPN_AGENT_INTERFACE);
830 fprintf(stderr, "Error registering VPN Agent: %s\n", error);
834 vpn_agent_request.registered = true;
835 fprintf(stdout, "VPN Agent registered\n");
840 int __connmanctl_vpn_agent_register(DBusConnection *connection)
842 char *path = agent_path();
845 if (vpn_agent_request.registered == true) {
846 fprintf(stderr, "VPN Agent already registered\n");
850 agent_connection = connection;
852 if (!g_dbus_register_interface(connection, path,
853 VPN_AGENT_INTERFACE, vpn_agent_methods,
854 NULL, NULL, &vpn_agent_request, NULL)) {
855 fprintf(stderr, "Error: Failed to register VPN Agent "
860 result = __connmanctl_dbus_method_call(connection, VPN_SERVICE,
861 VPN_PATH, "net.connman.vpn.Manager", "RegisterAgent",
862 vpn_agent_register_return, connection, append_path,
865 if (result != -EINPROGRESS) {
866 g_dbus_unregister_interface(connection, agent_path(),
867 VPN_AGENT_INTERFACE);
869 fprintf(stderr, "Error: Failed to register VPN Agent\n");
875 static int vpn_agent_unregister_return(DBusMessageIter *iter, int errnum,
876 const char *error, void *user_data)
879 fprintf(stderr, "Error unregistering VPN Agent: %s\n", error);
883 vpn_agent_request.registered = false;
884 fprintf(stdout, "VPN Agent unregistered\n");
889 int __connmanctl_vpn_agent_unregister(DBusConnection *connection)
891 char *path = agent_path();
894 if (vpn_agent_request.registered == false) {
895 fprintf(stderr, "VPN Agent not registered\n");
899 g_dbus_unregister_interface(connection, agent_path(),
900 VPN_AGENT_INTERFACE);
902 result = __connmanctl_dbus_method_call(connection, VPN_SERVICE,
903 VPN_PATH, "net.connman.vpn.Manager", "UnregisterAgent",
904 vpn_agent_unregister_return, NULL, append_path, path);
906 if (result != -EINPROGRESS)
907 fprintf(stderr, "Error: Failed to unregister VPN Agent\n");