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