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"
51 GDBusMethodFunction pending_function;
54 static DBusConnection *agent_connection;
56 static struct agent_data agent_request = {
59 static struct agent_data vpn_agent_request = {
63 static void request_input_ssid_return(char *input, void *user_data);
64 static void request_input_passphrase_return(char *input, void *user_data);
65 static void request_input_string_return(char *input, void *user_data);
67 static int confirm_input(char *input)
74 for (i = 0; input[i] != '\0'; i++)
75 if (isspace(input[i]) == 0)
78 if (strcasecmp(&input[i], "yes") == 0 ||
79 strcasecmp(&input[i], "y") == 0)
82 if (strcasecmp(&input[i], "no") == 0 ||
83 strcasecmp(&input[i], "n") == 0)
89 static char *strip_path(char *path)
91 char *name = strrchr(path, '/');
100 static char *agent_path(void)
102 static char *path = NULL;
105 path = g_strdup_printf("/net/connman/connmanctl%d", getpid());
110 static void pending_message_remove(struct agent_data *request)
112 if (request->message != NULL) {
113 dbus_message_unref(request->message);
114 request->message = NULL;
117 if (request->reply != NULL) {
118 dbus_message_unref(request->reply);
119 request->reply = NULL;
123 static void pending_command_complete(char *message)
125 struct agent_data *next_request = NULL;
126 DBusMessage *pending_message;
127 GDBusMethodFunction pending_function;
129 __connmanctl_save_rl();
131 fprintf(stdout, "%s", message);
133 __connmanctl_redraw_rl();
135 if (__connmanctl_is_interactive() == true)
136 __connmanctl_command_mode();
138 __connmanctl_agent_mode("", NULL, NULL);
140 if (agent_request.message != NULL)
141 next_request = &agent_request;
142 else if (vpn_agent_request.message != NULL)
143 next_request = &vpn_agent_request;
145 if (next_request == NULL)
148 pending_message = next_request->message;
149 pending_function = next_request->pending_function;
150 next_request->pending_function = NULL;
152 pending_function(agent_connection, next_request->message,
155 dbus_message_unref(pending_message);
158 static bool handle_message(DBusMessage *message, struct agent_data *request,
159 GDBusMethodFunction function)
161 if (agent_request.pending_function == NULL &&
162 vpn_agent_request.pending_function == NULL)
165 request->message = dbus_message_ref(message);
166 request->pending_function = function;
171 static DBusMessage *agent_release(DBusConnection *connection,
172 DBusMessage *message, void *user_data)
174 struct agent_data *request = user_data;
176 if (handle_message(message, request, agent_release) == false)
179 g_dbus_unregister_interface(connection, agent_path(),
181 request->registered = false;
183 pending_message_remove(request);
185 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
186 pending_command_complete("Agent unregistered by ConnMan\n");
188 pending_command_complete("VPN Agent unregistered by ConnMan "
191 if (__connmanctl_is_interactive() == false)
194 return dbus_message_new_method_return(message);
197 static DBusMessage *agent_cancel(DBusConnection *connection,
198 DBusMessage *message, void *user_data)
200 struct agent_data *request = user_data;
202 if (handle_message(message, request, agent_cancel) == false)
205 pending_message_remove(request);
207 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
208 pending_command_complete("Agent request cancelled by "
211 pending_command_complete("VPN Agent request cancelled by "
214 return dbus_message_new_method_return(message);
217 static void request_browser_return(char *input, void *user_data)
219 struct agent_data *request = user_data;
221 switch (confirm_input(input)) {
223 g_dbus_send_reply(agent_connection, request->message,
227 g_dbus_send_error(agent_connection, request->message,
228 "net.connman.Agent.Error.Canceled", NULL);
234 pending_message_remove(request);
235 pending_command_complete("");
238 static DBusMessage *agent_request_browser(DBusConnection *connection,
239 DBusMessage *message, void *user_data)
241 struct agent_data *request = user_data;
242 DBusMessageIter iter;
245 if (handle_message(message, request, agent_request_browser) == false)
248 dbus_message_iter_init(message, &iter);
250 dbus_message_iter_get_basic(&iter, &service);
251 dbus_message_iter_next(&iter);
252 dbus_message_iter_get_basic(&iter, &url);
254 __connmanctl_save_rl();
255 fprintf(stdout, "Agent RequestBrowser %s\n", strip_path(service));
256 fprintf(stdout, " %s\n", url);
257 __connmanctl_redraw_rl();
259 request->message = dbus_message_ref(message);
260 __connmanctl_agent_mode("Connected (yes/no)? ",
261 request_browser_return, request);
266 static void report_error_return(char *input, void *user_data)
268 struct agent_data *request = user_data;
270 switch (confirm_input(input)) {
272 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
273 g_dbus_send_error(agent_connection, request->message,
274 "net.connman.Agent.Error.Retry", NULL);
276 g_dbus_send_error(agent_connection, request->message,
277 "net.connman.vpn.Agent.Error.Retry",
281 g_dbus_send_reply(agent_connection, request->message,
288 pending_message_remove(request);
289 pending_command_complete("");
292 static DBusMessage *agent_report_error(DBusConnection *connection,
293 DBusMessage *message, void *user_data)
295 struct agent_data *request = user_data;
296 DBusMessageIter iter;
297 char *path, *service, *error;
299 if (handle_message(message, request, agent_report_error) == false)
302 dbus_message_iter_init(message, &iter);
304 dbus_message_iter_get_basic(&iter, &path);
305 service = strip_path(path);
307 dbus_message_iter_next(&iter);
308 dbus_message_iter_get_basic(&iter, &error);
310 __connmanctl_save_rl();
311 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
312 fprintf(stdout, "Agent ReportError %s\n", service);
314 fprintf(stdout, "VPN Agent ReportError %s\n", service);
315 fprintf(stdout, " %s\n", error);
316 __connmanctl_redraw_rl();
318 request->message = dbus_message_ref(message);
319 __connmanctl_agent_mode("Retry (yes/no)? ", report_error_return,
331 WISPR_PASSPHRASE = 5,
332 REQUEST_INPUT_MAX = 6,
336 const char *attribute;
339 connmanctl_input_func_t func;
341 { "Name", false, "Hidden SSID name? ", request_input_ssid_return },
342 { "Identity", false, "EAP username? ", request_input_string_return },
343 { "Passphrase", false, "Passphrase? ",
344 request_input_passphrase_return },
345 { "WPS", false, "WPS PIN (empty line for pushbutton)? " ,
346 request_input_string_return },
347 { "Username", false, "WISPr username? ", request_input_string_return },
348 { "Password", false, "WISPr password? ", request_input_string_return },
352 static void request_input_next(struct agent_data *request)
356 for (i = 0; agent_input[i].attribute != NULL; i++) {
357 if (agent_input[i].requested == true) {
358 if(agent_input[i].func != NULL)
359 __connmanctl_agent_mode(agent_input[i].prompt,
360 agent_input[i].func, request);
362 agent_input[i].requested = false;
367 dbus_message_iter_close_container(&request->iter, &request->dict);
369 g_dbus_send_message(agent_connection, request->reply);
370 request->reply = NULL;
372 pending_message_remove(request);
373 pending_command_complete("");
375 __connmanctl_redraw_rl();
378 static void request_input_append(struct agent_data *request,
379 const char *attribute, char *value)
381 __connmanctl_dbus_append_dict_entry(&request->dict, attribute,
382 DBUS_TYPE_STRING, &value);
385 static void request_input_ssid_return(char *input,
388 struct agent_data *request = user_data;
394 if (len > 0 && len <= 32) {
395 agent_input[SSID].requested = false;
396 request_input_append(request, agent_input[SSID].attribute,
399 request_input_next(request);
403 static void request_input_passphrase_return(char *input, void *user_data)
405 struct agent_data *request = user_data;
407 /* TBD passphrase length checking */
409 if (input != NULL && strlen(input) > 0) {
410 agent_input[PASSPHRASE].requested = false;
411 request_input_append(request,
412 agent_input[PASSPHRASE].attribute, input);
414 agent_input[WPS].requested = false;
416 request_input_next(request);
420 static void request_input_string_return(char *input, void *user_data)
422 struct agent_data *request = user_data;
425 for (i = 0; agent_input[i].attribute != NULL; i++) {
426 if (agent_input[i].requested == true) {
427 request_input_append(request, agent_input[i].attribute,
429 agent_input[i].requested = false;
434 request_input_next(request);
437 static DBusMessage *agent_request_input(DBusConnection *connection,
438 DBusMessage *message, void *user_data)
440 struct agent_data *request = user_data;
441 DBusMessageIter iter, dict, entry, variant;
442 char *service, *str, *field;
443 DBusMessageIter dict_entry, field_entry, field_value;
444 char *argument, *value, *attr_type;
448 if (handle_message(message, request, agent_request_input) == false)
451 dbus_message_iter_init(message, &iter);
453 dbus_message_iter_get_basic(&iter, &str);
454 service = strip_path(str);
456 dbus_message_iter_next(&iter);
457 dbus_message_iter_recurse(&iter, &dict);
459 __connmanctl_save_rl();
460 fprintf(stdout, "Agent RequestInput %s\n", service);
461 __connmanctl_dbus_print(&dict, " ", " = ", "\n");
462 fprintf(stdout, "\n");
464 dbus_message_iter_recurse(&iter, &dict);
466 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
468 dbus_message_iter_recurse(&dict, &entry);
470 dbus_message_iter_get_basic(&entry, &field);
472 dbus_message_iter_next(&entry);
474 dbus_message_iter_recurse(&entry, &variant);
475 dbus_message_iter_recurse(&variant, &dict_entry);
477 while (dbus_message_iter_get_arg_type(&dict_entry)
478 == DBUS_TYPE_DICT_ENTRY) {
479 dbus_message_iter_recurse(&dict_entry, &field_entry);
481 dbus_message_iter_get_basic(&field_entry, &argument);
483 dbus_message_iter_next(&field_entry);
485 dbus_message_iter_recurse(&field_entry, &field_value);
487 if (strcmp(argument, "Type") == 0) {
488 dbus_message_iter_get_basic(&field_value,
490 attr_type = g_strdup(value);
493 dbus_message_iter_next(&dict_entry);
496 for (i = 0; agent_input[i].attribute != NULL; i++) {
497 if (strcmp(field, agent_input[i].attribute) == 0) {
498 agent_input[i].requested = true;
506 dbus_message_iter_next(&dict);
509 request->reply = dbus_message_new_method_return(message);
510 dbus_message_iter_init_append(request->reply, &request->iter);
512 dbus_message_iter_open_container(&request->iter, DBUS_TYPE_ARRAY,
513 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
514 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
515 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
518 request_input_next(request);
523 static const GDBusMethodTable agent_methods[] = {
524 { GDBUS_ASYNC_METHOD("Release", NULL, NULL, agent_release) },
525 { GDBUS_ASYNC_METHOD("Cancel", NULL, NULL, agent_cancel) },
526 { GDBUS_ASYNC_METHOD("RequestBrowser",
527 GDBUS_ARGS({ "service", "o" },
529 NULL, agent_request_browser) },
530 { GDBUS_ASYNC_METHOD("ReportError",
531 GDBUS_ARGS({ "service", "o" },
533 NULL, agent_report_error) },
534 { GDBUS_ASYNC_METHOD("RequestInput",
535 GDBUS_ARGS({ "service", "o" },
536 { "fields", "a{sv}" }),
537 GDBUS_ARGS({ "fields", "a{sv}" }),
538 agent_request_input) },
542 static int agent_register_return(DBusMessageIter *iter, const char *error,
545 DBusConnection *connection = user_data;
548 g_dbus_unregister_interface(connection, agent_path(),
550 fprintf(stderr, "Error registering Agent: %s\n", error);
554 agent_request.registered = true;
555 fprintf(stdout, "Agent registered\n");
560 int __connmanctl_agent_register(DBusConnection *connection)
562 char *path = agent_path();
565 if (agent_request.registered == true) {
566 fprintf(stderr, "Agent already registered\n");
570 agent_connection = connection;
572 if (g_dbus_register_interface(connection, path,
573 AGENT_INTERFACE, agent_methods,
574 NULL, NULL, &agent_request,
576 fprintf(stderr, "Error: Failed to register Agent callbacks\n");
580 result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
581 CONNMAN_PATH, "net.connman.Manager", "RegisterAgent",
582 agent_register_return, connection,
583 DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
585 if (result != -EINPROGRESS) {
586 g_dbus_unregister_interface(connection, agent_path(),
589 fprintf(stderr, "Error: Failed to register Agent\n");
595 static int agent_unregister_return(DBusMessageIter *iter, const char *error,
599 fprintf(stderr, "Error unregistering Agent: %s\n", error);
603 agent_request.registered = false;
604 fprintf(stdout, "Agent unregistered\n");
609 int __connmanctl_agent_unregister(DBusConnection *connection)
611 char *path = agent_path();
614 if (agent_request.registered == false) {
615 fprintf(stderr, "Agent not registered\n");
619 g_dbus_unregister_interface(connection, agent_path(), AGENT_INTERFACE);
621 result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
622 CONNMAN_PATH, "net.connman.Manager", "UnregisterAgent",
623 agent_unregister_return, NULL,
624 DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
626 if (result != -EINPROGRESS)
627 fprintf(stderr, "Error: Failed to unregister Agent\n");
632 static const GDBusMethodTable vpn_agent_methods[] = {
633 { GDBUS_ASYNC_METHOD("Release", NULL, NULL, agent_release) },
634 { GDBUS_ASYNC_METHOD("Cancel", NULL, NULL, agent_cancel) },
635 { GDBUS_ASYNC_METHOD("ReportError",
636 GDBUS_ARGS({ "service", "o" },
638 NULL, agent_report_error) },
642 static int vpn_agent_register_return(DBusMessageIter *iter, const char *error,
645 DBusConnection *connection = user_data;
648 g_dbus_unregister_interface(connection, agent_path(),
649 VPN_AGENT_INTERFACE);
650 fprintf(stderr, "Error registering VPN Agent: %s\n", error);
654 vpn_agent_request.registered = true;
655 fprintf(stdout, "VPN Agent registered\n");
660 int __connmanctl_vpn_agent_register(DBusConnection *connection)
662 char *path = agent_path();
665 if (vpn_agent_request.registered == true) {
666 fprintf(stderr, "VPN Agent already registered\n");
670 agent_connection = connection;
672 if (g_dbus_register_interface(connection, path,
673 VPN_AGENT_INTERFACE, vpn_agent_methods,
674 NULL, NULL, &vpn_agent_request,
676 fprintf(stderr, "Error: Failed to register VPN Agent "
681 result = __connmanctl_dbus_method_call(connection, VPN_SERVICE,
682 VPN_PATH, "net.connman.vpn.Manager", "RegisterAgent",
683 vpn_agent_register_return, connection,
684 DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
686 if (result != -EINPROGRESS) {
687 g_dbus_unregister_interface(connection, agent_path(),
688 VPN_AGENT_INTERFACE);
690 fprintf(stderr, "Error: Failed to register VPN Agent\n");
696 static int vpn_agent_unregister_return(DBusMessageIter *iter,
697 const char *error, void *user_data)
700 fprintf(stderr, "Error unregistering VPN Agent: %s\n", error);
704 vpn_agent_request.registered = false;
705 fprintf(stdout, "VPN Agent unregistered\n");
710 int __connmanctl_vpn_agent_unregister(DBusConnection *connection)
712 char *path = agent_path();
715 if (vpn_agent_request.registered == false) {
716 fprintf(stderr, "VPN Agent not registered\n");
720 g_dbus_unregister_interface(connection, agent_path(),
721 VPN_AGENT_INTERFACE);
723 result = __connmanctl_dbus_method_call(connection, VPN_SERVICE,
724 VPN_PATH, "net.connman.vpn.Manager", "UnregisterAgent",
725 vpn_agent_unregister_return, NULL,
726 DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
728 if (result != -EINPROGRESS)
729 fprintf(stderr, "Error: Failed to unregister VPN Agent\n");