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 { "OpenConnect.SecondPassword", false, "VPN one-time password? ",
104 request_input_string_return },
105 { "Username", false, "VPN username? ", request_input_string_return },
106 { "Password", false, "VPN password? ", request_input_string_return },
110 static struct agent_data vpn_agent_request = {
111 vpnagent_input_handler,
115 static int confirm_input(char *input)
122 for (i = 0; input[i] != '\0'; i++)
123 if (isspace(input[i]) == 0)
126 if (strcasecmp(&input[i], "yes") == 0 ||
127 strcasecmp(&input[i], "y") == 0)
130 if (strcasecmp(&input[i], "no") == 0 ||
131 strcasecmp(&input[i], "n") == 0)
137 static char *strip_path(char *path)
139 char *name = strrchr(path, '/');
148 static char *agent_path(void)
150 static char *path = NULL;
153 path = g_strdup_printf("/net/connman/connmanctl%d", getpid());
158 static void pending_message_remove(struct agent_data *request)
160 if (request->message) {
161 dbus_message_unref(request->message);
162 request->message = NULL;
165 if (request->reply) {
166 dbus_message_unref(request->reply);
167 request->reply = NULL;
171 static void pending_command_complete(char *message)
173 struct agent_data *next_request = NULL;
174 DBusMessage *pending_message;
175 GDBusMethodFunction pending_function;
177 __connmanctl_save_rl();
179 fprintf(stdout, "%s", message);
181 __connmanctl_redraw_rl();
183 if (__connmanctl_is_interactive() == true)
184 __connmanctl_command_mode();
186 __connmanctl_agent_mode("", NULL, NULL);
188 if (agent_request.message)
189 next_request = &agent_request;
190 else if (vpn_agent_request.message)
191 next_request = &vpn_agent_request;
196 pending_message = next_request->message;
197 pending_function = next_request->pending_function;
198 next_request->pending_function = NULL;
200 pending_function(agent_connection, next_request->message,
203 dbus_message_unref(pending_message);
206 static bool handle_message(DBusMessage *message, struct agent_data *request,
207 GDBusMethodFunction function)
209 if (!agent_request.pending_function &&
210 !vpn_agent_request.pending_function)
213 request->message = dbus_message_ref(message);
214 request->pending_function = function;
219 static DBusMessage *agent_release(DBusConnection *connection,
220 DBusMessage *message, void *user_data)
222 struct agent_data *request = user_data;
224 if (handle_message(message, request, agent_release) == false)
227 g_dbus_unregister_interface(connection, agent_path(),
229 request->registered = false;
231 pending_message_remove(request);
233 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
234 pending_command_complete("Agent unregistered by ConnMan\n");
236 pending_command_complete("VPN Agent unregistered by ConnMan "
239 if (__connmanctl_is_interactive() == false)
242 return dbus_message_new_method_return(message);
245 static DBusMessage *agent_cancel(DBusConnection *connection,
246 DBusMessage *message, void *user_data)
248 struct agent_data *request = user_data;
250 if (handle_message(message, request, agent_cancel) == false)
253 pending_message_remove(request);
255 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
256 pending_command_complete("Agent request cancelled by "
259 pending_command_complete("VPN Agent request cancelled by "
262 return dbus_message_new_method_return(message);
265 static void request_browser_return(char *input, void *user_data)
267 struct agent_data *request = user_data;
269 switch (confirm_input(input)) {
271 g_dbus_send_reply(agent_connection, request->message,
275 g_dbus_send_error(agent_connection, request->message,
276 "net.connman.Agent.Error.Canceled", NULL);
282 pending_message_remove(request);
283 pending_command_complete("");
286 static DBusMessage *agent_request_browser(DBusConnection *connection,
287 DBusMessage *message, void *user_data)
289 struct agent_data *request = user_data;
290 DBusMessageIter iter;
293 if (handle_message(message, request, agent_request_browser) == false)
296 dbus_message_iter_init(message, &iter);
298 dbus_message_iter_get_basic(&iter, &service);
299 dbus_message_iter_next(&iter);
300 dbus_message_iter_get_basic(&iter, &url);
302 __connmanctl_save_rl();
303 fprintf(stdout, "Agent RequestBrowser %s\n", strip_path(service));
304 fprintf(stdout, " %s\n", url);
305 __connmanctl_redraw_rl();
307 request->message = dbus_message_ref(message);
308 __connmanctl_agent_mode("Connected (yes/no)? ",
309 request_browser_return, request);
314 static void report_error_return(char *input, void *user_data)
316 struct agent_data *request = user_data;
318 switch (confirm_input(input)) {
320 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
321 g_dbus_send_error(agent_connection, request->message,
322 "net.connman.Agent.Error.Retry", NULL);
324 g_dbus_send_error(agent_connection, request->message,
325 "net.connman.vpn.Agent.Error.Retry",
329 g_dbus_send_reply(agent_connection, request->message,
336 pending_message_remove(request);
337 pending_command_complete("");
340 static DBusMessage *agent_report_error(DBusConnection *connection,
341 DBusMessage *message, void *user_data)
343 struct agent_data *request = user_data;
344 DBusMessageIter iter;
345 char *path, *service, *error;
347 if (handle_message(message, request, agent_report_error) == false)
350 dbus_message_iter_init(message, &iter);
352 dbus_message_iter_get_basic(&iter, &path);
353 service = strip_path(path);
355 dbus_message_iter_next(&iter);
356 dbus_message_iter_get_basic(&iter, &error);
358 __connmanctl_save_rl();
359 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
360 fprintf(stdout, "Agent ReportError %s\n", service);
362 fprintf(stdout, "VPN Agent ReportError %s\n", service);
363 fprintf(stdout, " %s\n", error);
364 __connmanctl_redraw_rl();
366 request->message = dbus_message_ref(message);
367 __connmanctl_agent_mode("Retry (yes/no)? ", report_error_return,
373 static DBusMessage *agent_report_peer_error(DBusConnection *connection,
374 DBusMessage *message, void *user_data)
376 struct agent_data *request = user_data;
377 char *path, *peer, *error;
378 DBusMessageIter iter;
380 if (handle_message(message, request,
381 agent_report_peer_error) == false)
384 dbus_message_iter_init(message, &iter);
386 dbus_message_iter_get_basic(&iter, &path);
387 peer = strip_path(path);
389 dbus_message_iter_next(&iter);
390 dbus_message_iter_get_basic(&iter, &error);
392 __connmanctl_save_rl();
393 fprintf(stdout, "Agent ReportPeerError %s\n", peer);
394 fprintf(stdout, " %s\n", error);
395 __connmanctl_redraw_rl();
397 request->message = dbus_message_ref(message);
398 __connmanctl_agent_mode("Retry (yes/no)? ",
399 report_error_return, request);
403 static void request_input_next(struct agent_data *request)
407 for (i = 0; request->input[i].attribute; i++) {
408 if (request->input[i].requested == true) {
409 if (request->input[i].func)
410 __connmanctl_agent_mode(request->input[i].prompt,
411 request->input[i].func,
414 request->input[i].requested = false;
419 dbus_message_iter_close_container(&request->iter, &request->dict);
421 g_dbus_send_message(agent_connection, request->reply);
422 request->reply = NULL;
424 pending_message_remove(request);
425 pending_command_complete("");
427 __connmanctl_redraw_rl();
430 static void request_input_append(struct agent_data *request,
431 const char *attribute, char *value)
433 __connmanctl_dbus_append_dict_entry(&request->dict, attribute,
434 DBUS_TYPE_STRING, &value);
437 static void request_input_ssid_return(char *input,
440 struct agent_data *request = user_data;
446 if (len > 0 && len <= 32) {
447 request->input[SSID].requested = false;
448 request_input_append(request, request->input[SSID].attribute,
451 request_input_next(request);
455 static void request_input_passphrase_return(char *input, void *user_data)
457 struct agent_data *request = user_data;
460 /* TBD passphrase length checking */
465 if (len == 0 && request->input[WPS].requested == false)
468 request->input[PASSPHRASE].requested = false;
471 request_input_append(request,
472 request->input[PASSPHRASE].attribute, input);
474 request->input[WPS].requested = false;
477 request_input_next(request);
480 static void request_input_string_return(char *input, void *user_data)
482 struct agent_data *request = user_data;
485 for (i = 0; request->input[i].attribute; i++) {
486 if (request->input[i].requested == true) {
487 request_input_append(request,
488 request->input[i].attribute, input);
489 request->input[i].requested = false;
494 request_input_next(request);
497 static void parse_agent_request(struct agent_data *request,
498 DBusMessageIter *iter)
500 DBusMessageIter dict, entry, variant, dict_entry;
501 DBusMessageIter field_entry, field_value;
502 char *field, *argument, *value;
503 char *attr_type = NULL;
506 dbus_message_iter_recurse(iter, &dict);
508 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
510 dbus_message_iter_recurse(&dict, &entry);
512 dbus_message_iter_get_basic(&entry, &field);
514 dbus_message_iter_next(&entry);
516 dbus_message_iter_recurse(&entry, &variant);
517 dbus_message_iter_recurse(&variant, &dict_entry);
519 while (dbus_message_iter_get_arg_type(&dict_entry)
520 == DBUS_TYPE_DICT_ENTRY) {
521 dbus_message_iter_recurse(&dict_entry, &field_entry);
523 dbus_message_iter_get_basic(&field_entry, &argument);
525 dbus_message_iter_next(&field_entry);
527 dbus_message_iter_recurse(&field_entry, &field_value);
529 if (strcmp(argument, "Type") == 0) {
530 dbus_message_iter_get_basic(&field_value,
532 attr_type = g_strdup(value);
535 dbus_message_iter_next(&dict_entry);
538 for (i = 0; request->input[i].attribute; i++) {
539 if (strcmp(field, request->input[i].attribute) == 0) {
540 request->input[i].requested = true;
548 dbus_message_iter_next(&dict);
552 static DBusMessage *agent_request_input(DBusConnection *connection,
553 DBusMessage *message, void *user_data)
555 struct agent_data *request = user_data;
556 DBusMessageIter iter, dict;
559 if (handle_message(message, request, agent_request_input) == false)
562 dbus_message_iter_init(message, &iter);
564 dbus_message_iter_get_basic(&iter, &str);
565 service = strip_path(str);
567 dbus_message_iter_next(&iter);
568 dbus_message_iter_recurse(&iter, &dict);
570 __connmanctl_save_rl();
571 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
572 fprintf(stdout, "Agent RequestInput %s\n", service);
574 fprintf(stdout, "VPN Agent RequestInput %s\n", service);
575 __connmanctl_dbus_print(&dict, " ", " = ", "\n");
576 fprintf(stdout, "\n");
578 parse_agent_request(request, &iter);
580 request->reply = dbus_message_new_method_return(message);
581 dbus_message_iter_init_append(request->reply, &request->iter);
583 dbus_message_iter_open_container(&request->iter, DBUS_TYPE_ARRAY,
584 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
585 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
586 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
589 request_input_next(request);
594 static void request_authorization_return(char *input, void *user_data)
596 struct agent_data *request = user_data;
598 switch (confirm_input(input)) {
600 request->reply = dbus_message_new_method_return(
602 dbus_message_iter_init_append(request->reply, &request->iter);
604 dbus_message_iter_open_container(&request->iter,
606 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
607 DBUS_TYPE_STRING_AS_STRING
608 DBUS_TYPE_VARIANT_AS_STRING
609 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
611 dbus_message_iter_close_container(&request->iter,
613 g_dbus_send_message(agent_connection, request->reply);
614 request->reply = NULL;
617 g_dbus_send_error(agent_connection, request->message,
618 "net.connman.Agent.Error.Rejected", NULL);
621 g_dbus_send_error(agent_connection, request->message,
622 "net.connman.Agent.Error.Canceled", NULL);
626 pending_message_remove(request);
627 pending_command_complete("");
631 agent_request_peer_authorization(DBusConnection *connection,
632 DBusMessage *message, void *user_data)
634 struct agent_data *request = user_data;
635 DBusMessageIter iter, dict;
640 if (handle_message(message, request, agent_request_peer_authorization)
644 dbus_message_iter_init(message, &iter);
646 dbus_message_iter_get_basic(&iter, &str);
647 peer = strip_path(str);
649 dbus_message_iter_next(&iter);
650 dbus_message_iter_recurse(&iter, &dict);
652 __connmanctl_save_rl();
653 fprintf(stdout, "Agent RequestPeerAuthorization %s\n", peer);
654 __connmanctl_dbus_print(&dict, " ", " = ", "\n");
655 fprintf(stdout, "\n");
657 parse_agent_request(request, &iter);
659 for (input = false, i = 0; request->input[i].attribute; i++) {
660 if (request->input[i].requested == true) {
667 request->message = dbus_message_ref(message);
668 __connmanctl_agent_mode("Accept connection (yes/no)? ",
669 request_authorization_return, request);
673 request->reply = dbus_message_new_method_return(message);
674 dbus_message_iter_init_append(request->reply, &request->iter);
676 dbus_message_iter_open_container(&request->iter, DBUS_TYPE_ARRAY,
677 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
678 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
679 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
682 request_input_next(request);
687 static const GDBusMethodTable agent_methods[] = {
688 { GDBUS_ASYNC_METHOD("Release", NULL, NULL, agent_release) },
689 { GDBUS_ASYNC_METHOD("Cancel", NULL, NULL, agent_cancel) },
690 { GDBUS_ASYNC_METHOD("RequestBrowser",
691 GDBUS_ARGS({ "service", "o" },
693 NULL, agent_request_browser) },
694 { GDBUS_ASYNC_METHOD("ReportError",
695 GDBUS_ARGS({ "service", "o" },
697 NULL, agent_report_error) },
698 { GDBUS_ASYNC_METHOD("ReportPeerError",
699 GDBUS_ARGS({ "peer", "o" },
701 NULL, agent_report_peer_error) },
702 { GDBUS_ASYNC_METHOD("RequestInput",
703 GDBUS_ARGS({ "service", "o" },
704 { "fields", "a{sv}" }),
705 GDBUS_ARGS({ "fields", "a{sv}" }),
706 agent_request_input) },
707 { GDBUS_ASYNC_METHOD("RequestPeerAuthorization",
708 GDBUS_ARGS({ "peer", "o" },
709 { "fields", "a{sv}" }),
710 GDBUS_ARGS({ "fields", "a{sv}" }),
711 agent_request_peer_authorization) },
715 static int agent_register_return(DBusMessageIter *iter, int errnum,
716 const char *error, void *user_data)
718 DBusConnection *connection = user_data;
721 g_dbus_unregister_interface(connection, agent_path(),
723 fprintf(stderr, "Error registering Agent: %s\n", error);
727 agent_request.registered = true;
728 fprintf(stdout, "Agent registered\n");
733 static void append_path(DBusMessageIter *iter, void *user_data)
735 const char *path = user_data;
737 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
740 int __connmanctl_agent_register(DBusConnection *connection)
742 char *path = agent_path();
745 if (agent_request.registered == true) {
746 fprintf(stderr, "Agent already registered\n");
750 agent_connection = connection;
752 if (!g_dbus_register_interface(connection, path,
753 AGENT_INTERFACE, agent_methods,
754 NULL, NULL, &agent_request, NULL)) {
755 fprintf(stderr, "Error: Failed to register Agent callbacks\n");
759 result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
760 CONNMAN_PATH, "net.connman.Manager", "RegisterAgent",
761 agent_register_return, connection, append_path, path);
763 if (result != -EINPROGRESS) {
764 g_dbus_unregister_interface(connection, agent_path(),
767 fprintf(stderr, "Error: Failed to register Agent\n");
773 static int agent_unregister_return(DBusMessageIter *iter, int errnum,
774 const char *error, void *user_data)
777 fprintf(stderr, "Error unregistering Agent: %s\n", error);
781 agent_request.registered = false;
782 fprintf(stdout, "Agent unregistered\n");
787 int __connmanctl_agent_unregister(DBusConnection *connection)
789 char *path = agent_path();
792 if (agent_request.registered == false) {
793 fprintf(stderr, "Agent not registered\n");
797 g_dbus_unregister_interface(connection, agent_path(), AGENT_INTERFACE);
799 result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
800 CONNMAN_PATH, "net.connman.Manager", "UnregisterAgent",
801 agent_unregister_return, NULL, append_path, path);
803 if (result != -EINPROGRESS)
804 fprintf(stderr, "Error: Failed to unregister Agent\n");
809 static const GDBusMethodTable vpn_agent_methods[] = {
810 { GDBUS_ASYNC_METHOD("Release", NULL, NULL, agent_release) },
811 { GDBUS_ASYNC_METHOD("Cancel", NULL, NULL, agent_cancel) },
812 { GDBUS_ASYNC_METHOD("ReportError",
813 GDBUS_ARGS({ "service", "o" },
815 NULL, agent_report_error) },
816 { GDBUS_ASYNC_METHOD("RequestInput",
817 GDBUS_ARGS({ "service", "o" },
818 { "fields", "a{sv}" }),
819 GDBUS_ARGS({ "fields", "a{sv}" }),
820 agent_request_input) },
824 static int vpn_agent_register_return(DBusMessageIter *iter, int errnum,
825 const char *error, void *user_data)
827 DBusConnection *connection = user_data;
830 g_dbus_unregister_interface(connection, agent_path(),
831 VPN_AGENT_INTERFACE);
832 fprintf(stderr, "Error registering VPN Agent: %s\n", error);
836 vpn_agent_request.registered = true;
837 fprintf(stdout, "VPN Agent registered\n");
842 int __connmanctl_vpn_agent_register(DBusConnection *connection)
844 char *path = agent_path();
847 if (vpn_agent_request.registered == true) {
848 fprintf(stderr, "VPN Agent already registered\n");
852 agent_connection = connection;
854 if (!g_dbus_register_interface(connection, path,
855 VPN_AGENT_INTERFACE, vpn_agent_methods,
856 NULL, NULL, &vpn_agent_request, NULL)) {
857 fprintf(stderr, "Error: Failed to register VPN Agent "
862 result = __connmanctl_dbus_method_call(connection, VPN_SERVICE,
863 VPN_PATH, "net.connman.vpn.Manager", "RegisterAgent",
864 vpn_agent_register_return, connection, append_path,
867 if (result != -EINPROGRESS) {
868 g_dbus_unregister_interface(connection, agent_path(),
869 VPN_AGENT_INTERFACE);
871 fprintf(stderr, "Error: Failed to register VPN Agent\n");
877 static int vpn_agent_unregister_return(DBusMessageIter *iter, int errnum,
878 const char *error, void *user_data)
881 fprintf(stderr, "Error unregistering VPN Agent: %s\n", error);
885 vpn_agent_request.registered = false;
886 fprintf(stdout, "VPN Agent unregistered\n");
891 int __connmanctl_vpn_agent_unregister(DBusConnection *connection)
893 char *path = agent_path();
896 if (vpn_agent_request.registered == false) {
897 fprintf(stderr, "VPN Agent not registered\n");
901 g_dbus_unregister_interface(connection, agent_path(),
902 VPN_AGENT_INTERFACE);
904 result = __connmanctl_dbus_method_call(connection, VPN_SERVICE,
905 VPN_PATH, "net.connman.vpn.Manager", "UnregisterAgent",
906 vpn_agent_unregister_return, NULL, append_path, path);
908 if (result != -EINPROGRESS)
909 fprintf(stderr, "Error: Failed to unregister VPN Agent\n");