Imported Upstream version 1.41
[platform/upstream/connman.git] / client / agent.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2013  Intel Corporation. All rights reserved.
6  *
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.
11  *
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.
16  *
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
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <stdbool.h>
32 #include <string.h>
33 #include <ctype.h>
34
35 #include <gdbus.h>
36
37 #include "input.h"
38 #include "dbus_helpers.h"
39 #include "agent.h"
40
41 #define AGENT_INTERFACE      "net.connman.Agent"
42 #define VPN_AGENT_INTERFACE  "net.connman.vpn.Agent"
43
44 static DBusConnection *agent_connection;
45
46 struct agent_input_data {
47         const char *attribute;
48         bool requested;
49         char *prompt;
50         connmanctl_input_func_t func;
51 };
52
53 struct agent_data {
54         struct agent_input_data *input;
55         char *interface;
56         bool registered;
57         DBusMessage *message;
58         DBusMessage *reply;
59         DBusMessageIter iter;
60         DBusMessageIter dict;
61         GDBusMethodFunction pending_function;
62 };
63
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);
67
68 enum requestinput {
69         SSID                    = 0,
70         IDENTITY                = 1,
71         PASSPHRASE              = 2,
72         WPS                     = 3,
73         WISPR_USERNAME          = 4,
74         WISPR_PASSPHRASE        = 5,
75         REQUEST_INPUT_MAX       = 6,
76 };
77
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 },
87         { },
88 };
89
90 static struct agent_data agent_request = {
91         agent_input_handler,
92         AGENT_INTERFACE,
93 };
94
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 },
107         { },
108 };
109
110 static struct agent_data vpn_agent_request = {
111         vpnagent_input_handler,
112         VPN_AGENT_INTERFACE,
113 };
114
115 static int confirm_input(char *input)
116 {
117         int i;
118
119         if (!input)
120                 return -1;
121
122         for (i = 0; input[i] != '\0'; i++)
123                 if (isspace(input[i]) == 0)
124                         break;
125
126         if (strcasecmp(&input[i], "yes") == 0 ||
127                         strcasecmp(&input[i], "y") == 0)
128                 return 1;
129
130         if (strcasecmp(&input[i], "no") == 0 ||
131                         strcasecmp(&input[i], "n") == 0)
132                 return 0;
133
134         return -1;
135 }
136
137 static char *strip_path(char *path)
138 {
139         char *name = strrchr(path, '/');
140         if (name)
141                 name++;
142         else
143                 name = path;
144
145         return name;
146 }
147
148 static char *agent_path(void)
149 {
150         static char *path = NULL;
151
152         if (!path)
153                 path = g_strdup_printf("/net/connman/connmanctl%d", getpid());
154
155         return path;
156 }
157
158 static void pending_message_remove(struct agent_data *request)
159 {
160         if (request->message) {
161                 dbus_message_unref(request->message);
162                 request->message = NULL;
163         }
164
165         if (request->reply) {
166                 dbus_message_unref(request->reply);
167                 request->reply = NULL;
168         }
169 }
170
171 static void pending_command_complete(char *message)
172 {
173         struct agent_data *next_request = NULL;
174         DBusMessage *pending_message;
175         GDBusMethodFunction pending_function;
176
177         __connmanctl_save_rl();
178
179         fprintf(stdout, "%s", message);
180
181         __connmanctl_redraw_rl();
182
183         if (__connmanctl_is_interactive() == true)
184                 __connmanctl_command_mode();
185         else
186                 __connmanctl_agent_mode("", NULL, NULL);
187
188         if (agent_request.message)
189                 next_request = &agent_request;
190         else if (vpn_agent_request.message)
191                 next_request = &vpn_agent_request;
192
193         if (!next_request)
194                 return;
195
196         pending_message = next_request->message;
197         pending_function = next_request->pending_function;
198         next_request->pending_function = NULL;
199
200         pending_function(agent_connection, next_request->message,
201                         next_request);
202
203         dbus_message_unref(pending_message);
204 }
205
206 static bool handle_message(DBusMessage *message, struct agent_data *request,
207                 GDBusMethodFunction function)
208 {
209         if (!agent_request.pending_function &&
210                         !vpn_agent_request.pending_function)
211                 return true;
212
213         request->message = dbus_message_ref(message);
214         request->pending_function = function;
215
216         return false;
217 }
218
219 static DBusMessage *agent_release(DBusConnection *connection,
220                 DBusMessage *message, void *user_data)
221 {
222         struct agent_data *request = user_data;
223
224         if (handle_message(message, request, agent_release) == false)
225                 return NULL;
226
227         g_dbus_unregister_interface(connection, agent_path(),
228                         request->interface);
229         request->registered = false;
230
231         pending_message_remove(request);
232
233         if (strcmp(request->interface, AGENT_INTERFACE) == 0)
234                 pending_command_complete("Agent unregistered by ConnMan\n");
235         else
236                 pending_command_complete("VPN Agent unregistered by ConnMan "
237                                 "VPNd\n");
238
239         if (__connmanctl_is_interactive() == false)
240                 __connmanctl_quit();
241
242         return dbus_message_new_method_return(message);
243 }
244
245 static DBusMessage *agent_cancel(DBusConnection *connection,
246                 DBusMessage *message, void *user_data)
247 {
248         struct agent_data *request = user_data;
249
250         if (handle_message(message, request, agent_cancel) == false)
251                 return NULL;
252
253         pending_message_remove(request);
254
255         if (strcmp(request->interface, AGENT_INTERFACE) == 0)
256                 pending_command_complete("Agent request cancelled by "
257                                 "ConnMan\n");
258         else
259                 pending_command_complete("VPN Agent request cancelled by "
260                                 "ConnMan VPNd\n");
261
262         return dbus_message_new_method_return(message);
263 }
264
265 static void request_browser_return(char *input, void *user_data)
266 {
267         struct agent_data *request = user_data;
268
269         switch (confirm_input(input)) {
270         case 1:
271                 g_dbus_send_reply(agent_connection, request->message,
272                                 DBUS_TYPE_INVALID);
273                 break;
274         case 0:
275                 g_dbus_send_error(agent_connection, request->message,
276                                 "net.connman.Agent.Error.Canceled", NULL);
277                 break;
278         default:
279                 return;
280         }
281
282         pending_message_remove(request);
283         pending_command_complete("");
284 }
285
286 static DBusMessage *agent_request_browser(DBusConnection *connection,
287                 DBusMessage *message, void *user_data)
288 {
289         struct agent_data *request = user_data;
290         DBusMessageIter iter;
291         char *service, *url;
292
293         if (handle_message(message, request, agent_request_browser) == false)
294                 return NULL;
295
296         dbus_message_iter_init(message, &iter);
297
298         dbus_message_iter_get_basic(&iter, &service);
299         dbus_message_iter_next(&iter);
300         dbus_message_iter_get_basic(&iter, &url);
301
302         __connmanctl_save_rl();
303         fprintf(stdout, "Agent RequestBrowser %s\n", strip_path(service));
304         fprintf(stdout, "  %s\n", url);
305         __connmanctl_redraw_rl();
306
307         request->message = dbus_message_ref(message);
308         __connmanctl_agent_mode("Connected (yes/no)? ",
309                         request_browser_return, request);
310
311         return NULL;
312 }
313
314 static void report_error_return(char *input, void *user_data)
315 {
316         struct agent_data *request = user_data;
317
318         switch (confirm_input(input)) {
319         case 1:
320                 if (strcmp(request->interface, AGENT_INTERFACE) == 0)
321                         g_dbus_send_error(agent_connection, request->message,
322                                         "net.connman.Agent.Error.Retry", NULL);
323                 else
324                         g_dbus_send_error(agent_connection, request->message,
325                                         "net.connman.vpn.Agent.Error.Retry",
326                                         NULL);
327                 break;
328         case 0:
329                 g_dbus_send_reply(agent_connection, request->message,
330                                 DBUS_TYPE_INVALID);
331                 break;
332         default:
333                 return;
334         }
335
336         pending_message_remove(request);
337         pending_command_complete("");
338 }
339
340 static DBusMessage *agent_report_error(DBusConnection *connection,
341                 DBusMessage *message, void *user_data)
342 {
343         struct agent_data *request = user_data;
344         DBusMessageIter iter;
345         char *path, *service, *error;
346
347         if (handle_message(message, request, agent_report_error) == false)
348                 return NULL;
349
350         dbus_message_iter_init(message, &iter);
351
352         dbus_message_iter_get_basic(&iter, &path);
353         service = strip_path(path);
354
355         dbus_message_iter_next(&iter);
356         dbus_message_iter_get_basic(&iter, &error);
357
358         __connmanctl_save_rl();
359         if (strcmp(request->interface, AGENT_INTERFACE) == 0)
360                 fprintf(stdout, "Agent ReportError %s\n", service);
361         else
362                 fprintf(stdout, "VPN Agent ReportError %s\n", service);
363         fprintf(stdout, "  %s\n", error);
364         __connmanctl_redraw_rl();
365
366         request->message = dbus_message_ref(message);
367         __connmanctl_agent_mode("Retry (yes/no)? ", report_error_return,
368                         request);
369
370         return NULL;
371 }
372
373 static DBusMessage *agent_report_peer_error(DBusConnection *connection,
374                                         DBusMessage *message, void *user_data)
375 {
376         struct agent_data *request = user_data;
377         char *path, *peer, *error;
378         DBusMessageIter iter;
379
380         if (handle_message(message, request,
381                                 agent_report_peer_error) == false)
382                 return NULL;
383
384         dbus_message_iter_init(message, &iter);
385
386         dbus_message_iter_get_basic(&iter, &path);
387         peer = strip_path(path);
388
389         dbus_message_iter_next(&iter);
390         dbus_message_iter_get_basic(&iter, &error);
391
392         __connmanctl_save_rl();
393         fprintf(stdout, "Agent ReportPeerError %s\n", peer);
394         fprintf(stdout, "  %s\n", error);
395         __connmanctl_redraw_rl();
396
397         request->message = dbus_message_ref(message);
398         __connmanctl_agent_mode("Retry (yes/no)? ",
399                                 report_error_return, request);
400         return NULL;
401 }
402
403 static void request_input_next(struct agent_data *request)
404 {
405         int i;
406
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,
412                                                 request);
413                         else
414                                 request->input[i].requested = false;
415                         return;
416                 }
417         }
418
419         dbus_message_iter_close_container(&request->iter, &request->dict);
420
421         g_dbus_send_message(agent_connection, request->reply);
422         request->reply = NULL;
423
424         pending_message_remove(request);
425         pending_command_complete("");
426
427         __connmanctl_redraw_rl();
428 }
429
430 static void request_input_append(struct agent_data *request,
431                 const char *attribute, char *value)
432 {
433         __connmanctl_dbus_append_dict_entry(&request->dict, attribute,
434                         DBUS_TYPE_STRING, &value);
435 }
436
437 static void request_input_ssid_return(char *input,
438                 void *user_data)
439 {
440         struct agent_data *request = user_data;
441         int len = 0;
442
443         if (input)
444                 len = strlen(input);
445
446         if (len > 0 && len <= 32) {
447                 request->input[SSID].requested = false;
448                 request_input_append(request, request->input[SSID].attribute,
449                                 input);
450
451                 request_input_next(request);
452         }
453 }
454
455 static void request_input_passphrase_return(char *input, void *user_data)
456 {
457         struct agent_data *request = user_data;
458         int len = 0;
459
460         /* TBD passphrase length checking */
461
462         if (input)
463                 len = strlen(input);
464
465         if (len == 0 && request->input[WPS].requested == false)
466                 return;
467
468         request->input[PASSPHRASE].requested = false;
469
470         if (len > 0) {
471                 request_input_append(request,
472                                 request->input[PASSPHRASE].attribute, input);
473
474                 request->input[WPS].requested = false;
475         }
476
477         request_input_next(request);
478 }
479
480 static void request_input_string_return(char *input, void *user_data)
481 {
482         struct agent_data *request = user_data;
483         int i;
484
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;
490                         break;
491                 }
492         }
493
494         request_input_next(request);
495 }
496
497 static void parse_agent_request(struct agent_data *request,
498                                                 DBusMessageIter *iter)
499 {
500         DBusMessageIter dict, entry, variant, dict_entry;
501         DBusMessageIter field_entry, field_value;
502         char *field, *argument, *value;
503         char *attr_type = NULL;
504         int i;
505
506         dbus_message_iter_recurse(iter, &dict);
507
508         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
509
510                 dbus_message_iter_recurse(&dict, &entry);
511
512                 dbus_message_iter_get_basic(&entry, &field);
513
514                 dbus_message_iter_next(&entry);
515
516                 dbus_message_iter_recurse(&entry, &variant);
517                 dbus_message_iter_recurse(&variant, &dict_entry);
518
519                 while (dbus_message_iter_get_arg_type(&dict_entry)
520                                 == DBUS_TYPE_DICT_ENTRY) {
521                         dbus_message_iter_recurse(&dict_entry, &field_entry);
522
523                         dbus_message_iter_get_basic(&field_entry, &argument);
524
525                         dbus_message_iter_next(&field_entry);
526
527                         dbus_message_iter_recurse(&field_entry, &field_value);
528
529                         if (strcmp(argument, "Type") == 0) {
530                                 dbus_message_iter_get_basic(&field_value,
531                                                 &value);
532                                 attr_type = g_strdup(value);
533                         }
534
535                         dbus_message_iter_next(&dict_entry);
536                 }
537
538                 for (i = 0; request->input[i].attribute; i++) {
539                         if (strcmp(field, request->input[i].attribute) == 0) {
540                                 request->input[i].requested = true;
541                                 break;
542                         }
543                 }
544
545                 g_free(attr_type);
546                 attr_type = NULL;
547
548                 dbus_message_iter_next(&dict);
549         }
550 }
551
552 static DBusMessage *agent_request_input(DBusConnection *connection,
553                 DBusMessage *message, void *user_data)
554 {
555         struct agent_data *request = user_data;
556         DBusMessageIter iter, dict;
557         char *service, *str;
558
559         if (handle_message(message, request, agent_request_input) == false)
560                 return NULL;
561
562         dbus_message_iter_init(message, &iter);
563
564         dbus_message_iter_get_basic(&iter, &str);
565         service = strip_path(str);
566
567         dbus_message_iter_next(&iter);
568         dbus_message_iter_recurse(&iter, &dict);
569
570         __connmanctl_save_rl();
571         if (strcmp(request->interface, AGENT_INTERFACE) == 0)
572                 fprintf(stdout, "Agent RequestInput %s\n", service);
573         else
574                 fprintf(stdout, "VPN Agent RequestInput %s\n", service);
575         __connmanctl_dbus_print(&dict, "  ", " = ", "\n");
576         fprintf(stdout, "\n");
577
578         parse_agent_request(request, &iter);
579
580         request->reply = dbus_message_new_method_return(message);
581         dbus_message_iter_init_append(request->reply, &request->iter);
582
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,
587                         &request->dict);
588
589         request_input_next(request);
590
591         return NULL;
592 }
593
594 static void request_authorization_return(char *input, void *user_data)
595 {
596         struct agent_data *request = user_data;
597
598         switch (confirm_input(input)) {
599         case 1:
600                 request->reply = dbus_message_new_method_return(
601                                                         request->message);
602                 dbus_message_iter_init_append(request->reply, &request->iter);
603
604                 dbus_message_iter_open_container(&request->iter,
605                                 DBUS_TYPE_ARRAY,
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,
610                                 &request->dict);
611                 dbus_message_iter_close_container(&request->iter,
612                                                         &request->dict);
613                 g_dbus_send_message(agent_connection, request->reply);
614                 request->reply = NULL;
615                 break;
616         case 0:
617                  g_dbus_send_error(agent_connection, request->message,
618                                  "net.connman.Agent.Error.Rejected", NULL);
619                  break;
620         default:
621                  g_dbus_send_error(agent_connection, request->message,
622                                  "net.connman.Agent.Error.Canceled", NULL);
623                  break;
624         }
625
626         pending_message_remove(request);
627         pending_command_complete("");
628 }
629
630 static DBusMessage *
631 agent_request_peer_authorization(DBusConnection *connection,
632                                         DBusMessage *message, void *user_data)
633 {
634         struct agent_data *request = user_data;
635         DBusMessageIter iter, dict;
636         char *peer, *str;
637         bool input;
638         int i;
639
640         if (handle_message(message, request, agent_request_peer_authorization)
641                                                                 == false)
642                 return NULL;
643
644         dbus_message_iter_init(message, &iter);
645
646         dbus_message_iter_get_basic(&iter, &str);
647         peer = strip_path(str);
648
649         dbus_message_iter_next(&iter);
650         dbus_message_iter_recurse(&iter, &dict);
651
652         __connmanctl_save_rl();
653         fprintf(stdout, "Agent RequestPeerAuthorization %s\n", peer);
654         __connmanctl_dbus_print(&dict, "  ", " = ", "\n");
655         fprintf(stdout, "\n");
656
657         parse_agent_request(request, &iter);
658
659         for (input = false, i = 0; request->input[i].attribute; i++) {
660                 if (request->input[i].requested == true) {
661                         input = true;
662                         break;
663                 }
664         }
665
666         if (!input) {
667                 request->message = dbus_message_ref(message);
668                 __connmanctl_agent_mode("Accept connection (yes/no)? ",
669                                         request_authorization_return, request);
670                 return NULL;
671         }
672
673         request->reply = dbus_message_new_method_return(message);
674         dbus_message_iter_init_append(request->reply, &request->iter);
675
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,
680                         &request->dict);
681
682         request_input_next(request);
683
684         return NULL;
685 }
686
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" },
692                                         { "url", "s" }),
693                                 NULL, agent_request_browser) },
694         { GDBUS_ASYNC_METHOD("ReportError",
695                                 GDBUS_ARGS({ "service", "o" },
696                                         { "error", "s" }),
697                                 NULL, agent_report_error) },
698         { GDBUS_ASYNC_METHOD("ReportPeerError",
699                                 GDBUS_ARGS({ "peer", "o" },
700                                         { "error", "s" }),
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) },
712         { },
713 };
714
715 static int agent_register_return(DBusMessageIter *iter, int errnum,
716                                  const char *error, void *user_data)
717 {
718         DBusConnection *connection = user_data;
719
720         if (error) {
721                 g_dbus_unregister_interface(connection, agent_path(),
722                                 AGENT_INTERFACE);
723                 fprintf(stderr, "Error registering Agent: %s\n", error);
724                 return 0;
725         }
726
727         agent_request.registered = true;
728         fprintf(stdout, "Agent registered\n");
729
730         return -EINPROGRESS;
731 }
732
733 static void append_path(DBusMessageIter *iter, void *user_data)
734 {
735         const char *path = user_data;
736
737         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
738 }
739
740 int __connmanctl_agent_register(DBusConnection *connection)
741 {
742         char *path = agent_path();
743         int result;
744
745         if (agent_request.registered == true) {
746                 fprintf(stderr, "Agent already registered\n");
747                 return -EALREADY;
748         }
749
750         agent_connection = connection;
751
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");
756                 return 0;
757         }
758
759         result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
760                         CONNMAN_PATH, "net.connman.Manager", "RegisterAgent",
761                         agent_register_return, connection, append_path, path);
762
763         if (result != -EINPROGRESS) {
764                 g_dbus_unregister_interface(connection, agent_path(),
765                                 AGENT_INTERFACE);
766
767                 fprintf(stderr, "Error: Failed to register Agent\n");
768         }
769
770         return result;
771 }
772
773 static int agent_unregister_return(DBusMessageIter *iter, int errnum,
774                                    const char *error, void *user_data)
775 {
776         if (error) {
777                 fprintf(stderr, "Error unregistering Agent: %s\n", error);
778                 return 0;
779         }
780
781         agent_request.registered = false;
782         fprintf(stdout, "Agent unregistered\n");
783
784         return 0;
785 }
786
787 int __connmanctl_agent_unregister(DBusConnection *connection)
788 {
789         char *path = agent_path();
790         int result;
791
792         if (agent_request.registered == false) {
793                 fprintf(stderr, "Agent not registered\n");
794                 return -EALREADY;
795         }
796
797         g_dbus_unregister_interface(connection, agent_path(), AGENT_INTERFACE);
798
799         result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
800                         CONNMAN_PATH, "net.connman.Manager", "UnregisterAgent",
801                         agent_unregister_return, NULL, append_path, path);
802
803         if (result != -EINPROGRESS)
804                 fprintf(stderr, "Error: Failed to unregister Agent\n");
805
806         return result;
807 }
808
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" },
814                                         { "error", "s" }),
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) },
821         { },
822 };
823
824 static int vpn_agent_register_return(DBusMessageIter *iter, int errnum,
825                                      const char *error, void *user_data)
826 {
827         DBusConnection *connection = user_data;
828
829         if (error) {
830                 g_dbus_unregister_interface(connection, agent_path(),
831                                 VPN_AGENT_INTERFACE);
832                 fprintf(stderr, "Error registering VPN Agent: %s\n", error);
833                 return 0;
834         }
835
836         vpn_agent_request.registered = true;
837         fprintf(stdout, "VPN Agent registered\n");
838
839         return -EINPROGRESS;
840 }
841
842 int __connmanctl_vpn_agent_register(DBusConnection *connection)
843 {
844         char *path = agent_path();
845         int result;
846
847         if (vpn_agent_request.registered == true) {
848                 fprintf(stderr, "VPN Agent already registered\n");
849                 return -EALREADY;
850         }
851
852         agent_connection = connection;
853
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 "
858                                 "callbacks\n");
859                 return 0;
860         }
861
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,
865                         path);
866
867         if (result != -EINPROGRESS) {
868                 g_dbus_unregister_interface(connection, agent_path(),
869                                 VPN_AGENT_INTERFACE);
870
871                 fprintf(stderr, "Error: Failed to register VPN Agent\n");
872         }
873
874         return result;
875 }
876
877 static int vpn_agent_unregister_return(DBusMessageIter *iter, int errnum,
878                 const char *error, void *user_data)
879 {
880         if (error) {
881                 fprintf(stderr, "Error unregistering VPN Agent: %s\n", error);
882                 return 0;
883         }
884
885         vpn_agent_request.registered = false;
886         fprintf(stdout, "VPN Agent unregistered\n");
887
888         return 0;
889 }
890
891 int __connmanctl_vpn_agent_unregister(DBusConnection *connection)
892 {
893         char *path = agent_path();
894         int result;
895
896         if (vpn_agent_request.registered == false) {
897                 fprintf(stderr, "VPN Agent not registered\n");
898                 return -EALREADY;
899         }
900
901         g_dbus_unregister_interface(connection, agent_path(),
902                         VPN_AGENT_INTERFACE);
903
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);
907
908         if (result != -EINPROGRESS)
909                 fprintf(stderr, "Error: Failed to unregister VPN Agent\n");
910
911         return result;
912 }