Imported Upstream version 1.40
[platform/upstream/connman.git] / vpn / plugins / vpnc.c
1 /*
2  *
3  *  ConnMan VPN daemon
4  *
5  *  Copyright (C) 2010,2013  BMW Car IT GmbH.
6  *  Copyright (C) 2010,2012-2013  Intel Corporation. All rights reserved.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2 as
10  *  published by the Free Software Foundation.
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 <string.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <net/if.h>
32 #include <linux/if_tun.h>
33 #include <sys/types.h>
34 #include <pwd.h>
35 #include <grp.h>
36 #include <fcntl.h>
37
38 #include <glib.h>
39
40 #define CONNMAN_API_SUBJECT_TO_CHANGE
41 #include <connman/plugin.h>
42 #include <connman/log.h>
43 #include <connman/task.h>
44 #include <connman/ipconfig.h>
45 #include <connman/dbus.h>
46 #include <connman/agent.h>
47 #include <connman/setting.h>
48 #include <connman/vpn-dbus.h>
49
50 #include "../vpn-provider.h"
51 #include "../vpn-agent.h"
52
53 #include "vpn.h"
54 #include "../vpn.h"
55
56 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
57 #define PID_PATH_ROOT "/var/run/user"
58
59 enum {
60         OPT_STRING = 1,
61         OPT_BOOLEAN = 2,
62 };
63
64 struct {
65         const char *cm_opt;
66         const char *vpnc_opt;
67         const char *vpnc_default;
68         int type;
69         bool cm_save;
70 } vpnc_options[] = {
71         { "Host", "IPSec gateway", NULL, OPT_STRING, true },
72         { "VPNC.IPSec.ID", "IPSec ID", NULL, OPT_STRING, true },
73         { "VPNC.IPSec.Secret", "IPSec secret", NULL, OPT_STRING, false },
74         { "VPNC.Xauth.Username", "Xauth username", NULL, OPT_STRING, false },
75         { "VPNC.Xauth.Password", "Xauth password", NULL, OPT_STRING, false },
76         { "VPNC.IKE.Authmode", "IKE Authmode", NULL, OPT_STRING, true },
77         { "VPNC.IKE.DHGroup", "IKE DH Group", NULL, OPT_STRING, true },
78         { "VPNC.PFS", "Perfect Forward Secrecy", NULL, OPT_STRING, true },
79         { "VPNC.Domain", "Domain", NULL, OPT_STRING, true },
80         { "VPNC.Vendor", "Vendor", NULL, OPT_STRING, true },
81         { "VPNC.LocalPort", "Local Port", "0", OPT_STRING, true, },
82         { "VPNC.CiscoPort", "Cisco UDP Encapsulation Port", "0", OPT_STRING,
83                                                                         true },
84         { "VPNC.AppVersion", "Application version", NULL, OPT_STRING, true },
85         { "VPNC.NATTMode", "NAT Traversal Mode", "cisco-udp", OPT_STRING,
86                                                                         true },
87         { "VPNC.DPDTimeout", "DPD idle timeout (our side)", NULL, OPT_STRING,
88                                                                         true },
89         { "VPNC.SingleDES", "Enable Single DES", NULL, OPT_BOOLEAN, true },
90         { "VPNC.NoEncryption", "Enable no encryption", NULL, OPT_BOOLEAN,
91                                                                         true },
92 };
93
94 struct vc_private_data {
95         struct vpn_provider *provider;
96         struct connman_task *task;
97         char *if_name;
98         vpn_provider_connect_cb_t cb;
99         void *user_data;
100         int err_ch_id;
101         GIOChannel *err_ch;
102 };
103
104 static void vc_connect_done(struct vc_private_data *data, int err)
105 {
106         DBG("data %p err %d", data, err);
107
108         if (data && data->cb) {
109                 vpn_provider_connect_cb_t cb = data->cb;
110                 void *user_data = data->user_data;
111
112                 /* Make sure we don't invoke this callback twice */
113                 data->cb = NULL;
114                 data->user_data = NULL;
115                 cb(data->provider, user_data, err);
116         }
117 }
118
119 static void close_io_channel(struct vc_private_data *data, GIOChannel *channel)
120 {
121         if (!data || !channel)
122                 return;
123
124         if (data->err_ch == channel) {
125                 DBG("closing stderr");
126
127                 if (data->err_ch_id) {
128                         g_source_remove(data->err_ch_id);
129                         data->err_ch_id = 0;
130                 }
131
132                 if (!data->err_ch)
133                         return;
134
135                 g_io_channel_shutdown(data->err_ch, FALSE, NULL);
136                 g_io_channel_unref(data->err_ch);
137
138                 data->err_ch = NULL;
139         }
140 }
141
142 static void free_private_data(struct vc_private_data *data)
143 {
144         DBG("data %p", data);
145
146         if (!data || !data->provider)
147                 return;
148
149         DBG("provider %p", data->provider);
150
151         if (vpn_provider_get_plugin_data(data->provider) == data)
152                 vpn_provider_set_plugin_data(data->provider, NULL);
153
154         vpn_provider_unref(data->provider);
155
156         g_free(data->if_name);
157         g_free(data);
158 }
159
160 static int vc_notify(DBusMessage *msg, struct vpn_provider *provider)
161 {
162         DBusMessageIter iter, dict;
163         char *address = NULL, *netmask = NULL, *gateway = NULL;
164         struct connman_ipaddress *ipaddress;
165         const char *reason, *key, *value;
166         struct vc_private_data *data;
167         int type;
168
169         data = vpn_provider_get_plugin_data(provider);
170
171         dbus_message_iter_init(msg, &iter);
172
173         type = dbus_message_iter_get_arg_type(&iter);
174         if (type != DBUS_TYPE_STRING) {
175                 DBG("invalid D-Bus arg type %d", type);
176                 return VPN_STATE_FAILURE;
177         }
178
179         dbus_message_iter_get_basic(&iter, &reason);
180         dbus_message_iter_next(&iter);
181
182         if (!provider) {
183                 connman_error("No provider found");
184                 vc_connect_done(data, ENOENT);
185                 return VPN_STATE_FAILURE;
186         }
187
188         if (g_strcmp0(reason, "connect")) {
189                 vc_connect_done(data, EIO);
190                 return VPN_STATE_DISCONNECT;
191         }
192
193         dbus_message_iter_recurse(&iter, &dict);
194
195         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
196                 DBusMessageIter entry;
197
198                 dbus_message_iter_recurse(&dict, &entry);
199
200                 type = dbus_message_iter_get_arg_type(&entry);
201                 if (type != DBUS_TYPE_STRING)
202                         continue;
203
204                 dbus_message_iter_get_basic(&entry, &key);
205                 dbus_message_iter_next(&entry);
206
207                 type = dbus_message_iter_get_arg_type(&entry);
208                 if (type != DBUS_TYPE_STRING)
209                         continue;
210
211                 dbus_message_iter_get_basic(&entry, &value);
212
213                 DBG("%s = %s", key, value);
214
215                 if (!strcmp(key, "VPNGATEWAY"))
216                         gateway = g_strdup(value);
217
218                 if (!strcmp(key, "INTERNAL_IP4_ADDRESS"))
219                         address = g_strdup(value);
220
221                 if (!strcmp(key, "INTERNAL_IP4_NETMASK"))
222                         netmask = g_strdup(value);
223
224                 if (!strcmp(key, "INTERNAL_IP4_DNS"))
225                         vpn_provider_set_nameservers(provider, value);
226
227                 if (!strcmp(key, "CISCO_DEF_DOMAIN"))
228                         vpn_provider_set_domain(provider, value);
229
230                 if (g_str_has_prefix(key, "CISCO_SPLIT_INC") ||
231                         g_str_has_prefix(key, "CISCO_IPV6_SPLIT_INC"))
232                         vpn_provider_append_route(provider, key, value);
233
234                 dbus_message_iter_next(&dict);
235         }
236
237
238         ipaddress = connman_ipaddress_alloc(AF_INET);
239         if (!ipaddress) {
240                 g_free(address);
241                 g_free(netmask);
242                 g_free(gateway);
243                 vc_connect_done(data, EIO);
244                 return VPN_STATE_FAILURE;
245         }
246
247         connman_ipaddress_set_ipv4(ipaddress, address, netmask, gateway);
248         connman_ipaddress_set_p2p(ipaddress, true);
249         vpn_provider_set_ipaddress(provider, ipaddress);
250
251         g_free(address);
252         g_free(netmask);
253         g_free(gateway);
254         connman_ipaddress_free(ipaddress);
255
256         vc_connect_done(data, 0);
257         return VPN_STATE_CONNECT;
258 }
259
260 static ssize_t full_write(int fd, const void *buf, size_t len)
261 {
262         ssize_t byte_write;
263
264         while (len) {
265                 byte_write = write(fd, buf, len);
266                 if (byte_write < 0) {
267                         connman_error("failed to write config to vpnc: %s\n",
268                                         strerror(errno));
269                         return byte_write;
270                 }
271                 len -= byte_write;
272                 buf += byte_write;
273         }
274
275         return 0;
276 }
277
278 static ssize_t write_option(int fd, const char *key, const char *value)
279 {
280         gchar *buf;
281         ssize_t ret = 0;
282
283         if (key && value) {
284                 buf = g_strdup_printf("%s %s\n", key, value);
285                 ret = full_write(fd, buf, strlen(buf));
286
287                 g_free(buf);
288         }
289
290         return ret;
291 }
292
293 static ssize_t write_bool_option(int fd, const char *key, const char *value)
294 {
295         gchar *buf;
296         ssize_t ret = 0;
297
298         if (key && value) {
299                 if (strcasecmp(value, "yes") == 0 ||
300                                 strcasecmp(value, "true") == 0 ||
301                                 strcmp(value, "1") == 0) {
302                         buf = g_strdup_printf("%s\n", key);
303                         ret = full_write(fd, buf, strlen(buf));
304
305                         g_free(buf);
306                 }
307         }
308
309         return ret;
310 }
311
312 static int vc_write_config_data(struct vpn_provider *provider, int fd)
313 {
314         const char *opt_s;
315         int i;
316
317         for (i = 0; i < (int)ARRAY_SIZE(vpnc_options); i++) {
318                 opt_s = vpn_provider_get_string(provider,
319                                         vpnc_options[i].cm_opt);
320                 if (!opt_s)
321                         opt_s = vpnc_options[i].vpnc_default;
322
323                 if (!opt_s)
324                         continue;
325
326                 if (vpnc_options[i].type == OPT_STRING) {
327                         if (write_option(fd,
328                                         vpnc_options[i].vpnc_opt, opt_s) < 0)
329                                 return -EIO;
330                 } else if (vpnc_options[i].type == OPT_BOOLEAN) {
331                         if (write_bool_option(fd,
332                                         vpnc_options[i].vpnc_opt, opt_s) < 0)
333                                 return -EIO;
334                 }
335
336         }
337
338         return 0;
339 }
340
341 static int vc_save(struct vpn_provider *provider, GKeyFile *keyfile)
342 {
343         const char *option;
344         int i;
345
346         for (i = 0; i < (int)ARRAY_SIZE(vpnc_options); i++) {
347                 if (strncmp(vpnc_options[i].cm_opt, "VPNC.", 5) == 0) {
348
349                         if (!vpnc_options[i].cm_save)
350                                 continue;
351
352                         option = vpn_provider_get_string(provider,
353                                                         vpnc_options[i].cm_opt);
354                         if (!option)
355                                 continue;
356
357                         g_key_file_set_string(keyfile,
358                                         vpn_provider_get_save_group(provider),
359                                         vpnc_options[i].cm_opt, option);
360                 }
361         }
362         return 0;
363 }
364
365 static void vc_died(struct connman_task *task, int exit_code, void *user_data)
366 {
367         struct vc_private_data *data = user_data;
368
369         DBG("task %p data %p exit_code %d user_data %p", task, data, exit_code,
370                                 user_data);
371
372         if (!data)
373                 return;
374
375         if (data->provider) {
376                 connman_agent_cancel(data->provider);
377
378                 if (task)
379                         vpn_died(task, exit_code, data->provider);
380         }
381
382         free_private_data(data);
383 }
384
385 static gboolean io_channel_cb(GIOChannel *source, GIOCondition condition,
386                         gpointer user_data)
387 {
388         struct vc_private_data *data;
389         const char *auth_failures[] = {
390                         VPNC ": hash comparison failed",
391                         VPNC ": authentication unsuccessful",
392                         VPNC ": expected xauth packet; rejected",
393                         NULL
394         };
395         const char *conn_failures[] = {
396                         VPNC ": unknown host",
397                         VPNC ": no response from target",
398                         VPNC ": receiving packet: No route to host",
399                         NULL
400         };
401         char *str;
402         int i;
403
404         data = user_data;
405
406         if ((condition & G_IO_IN) &&
407                 g_io_channel_read_line(source, &str, NULL, NULL, NULL) ==
408                                                         G_IO_STATUS_NORMAL) {
409                 str[strlen(str) - 1] = '\0';
410
411                 for (i = 0; auth_failures[i]; i++) {
412                         if (g_str_has_prefix(str, auth_failures[i])) {
413                                 DBG("authentication failed: %s", str);
414
415                                 vpn_provider_indicate_error(data->provider,
416                                         VPN_PROVIDER_ERROR_AUTH_FAILED);
417                         }
418                 }
419
420                 for (i = 0; conn_failures[i]; i++) {
421                         if (g_str_has_prefix(str, conn_failures[i])) {
422                                 DBG("connection failed: %s", str);
423
424                                 vpn_provider_indicate_error(data->provider,
425                                         VPN_PROVIDER_ERROR_CONNECT_FAILED);
426                         }
427                 }
428
429                 g_free(str);
430         } else if (condition & (G_IO_ERR | G_IO_HUP)) {
431                 DBG("Channel termination");
432                 close_io_channel(data, source);
433                 return G_SOURCE_REMOVE;
434         }
435
436         return G_SOURCE_CONTINUE;
437 }
438
439 static char *create_pid_path(const char *user, const char *group)
440 {
441         struct passwd *pwd;
442         struct group *grp;
443         char *uid_str;
444         char *pid_path = NULL;
445         int mode = S_IRWXU|S_IRWXG;
446         gid_t gid;
447
448         if (!user || !*user)
449                 return NULL;
450
451         if (vpn_settings_is_system_user(user))
452                 return NULL;
453
454         pwd = vpn_util_get_passwd(user);
455         uid_str = g_strdup_printf("%d", pwd->pw_uid);
456
457         grp = vpn_util_get_group(group);
458         gid = grp ? grp->gr_gid : pwd->pw_gid;
459
460         pid_path = g_build_filename(PID_PATH_ROOT, uid_str, "vpnc", "pid",
461                                 NULL);
462         if (vpn_util_create_path(pid_path, pwd->pw_uid, gid, mode)) {
463                 g_free(pid_path);
464                 pid_path = NULL;
465         }
466
467         g_free(uid_str);
468
469         return pid_path;
470 }
471
472 static int run_connect(struct vc_private_data *data)
473 {
474         struct vpn_provider *provider;
475         struct connman_task *task;
476         struct vpn_plugin_data *plugin_data;
477         const char *credentials[] = {"VPNC.IPSec.Secret", "VPNC.Xauth.Username",
478                                 "VPNC.Xauth.Password", NULL};
479         const char *if_name;
480         const char *option;
481         char *pid_path;
482         int err;
483         int fd_in;
484         int fd_err;
485         int i;
486
487         provider = data->provider;
488         task = data->task;
489         if_name = data->if_name;
490
491         DBG("provider %p task %p interface %s user_data %p", provider, task,
492                                 if_name, data->user_data);
493
494         /*
495          * Change to use C locale, options should be in ASCII according to
496          * documentation. To be on the safe side, set both LANG and LC_ALL.
497          * This is required especially when the VPNC processe is ran using an
498          * user other than root.
499          */
500         connman_task_add_variable(task,"LANG", "C");
501         connman_task_add_variable(task,"LC_ALL", "C");
502
503         connman_task_add_argument(task, "--non-inter", NULL);
504         connman_task_add_argument(task, "--no-detach", NULL);
505
506         connman_task_add_argument(task, "--ifname", if_name);
507         option = vpn_provider_get_string(provider, "VPNC.DeviceType");
508         if (option) {
509                 connman_task_add_argument(task, "--ifmode", option);
510         } else {
511                 /*
512                  * Default to tun for backwards compatibility.
513                  */
514                 connman_task_add_argument(task, "--ifmode", "tun");
515         }
516
517         plugin_data = vpn_settings_get_vpn_plugin_config("vpnc");
518
519         option = vpn_settings_get_binary_user(plugin_data);
520         if (option) {
521                 pid_path = create_pid_path(option,
522                                         vpn_settings_get_binary_group(
523                                                 plugin_data));
524                 if (pid_path)
525                         connman_task_add_argument(task, "--pid-file",
526                                                                 pid_path);
527
528                 g_free(pid_path);
529         }
530
531         connman_task_add_argument(task, "--script", SCRIPTDIR "/vpn-script");
532
533         option = vpn_provider_get_string(provider, "VPNC.Debug");
534         if (option)
535                 connman_task_add_argument(task, "--debug", option);
536
537         connman_task_add_argument(task, "-", NULL);
538
539         err = connman_task_run(data->task, vc_died, data, &fd_in, NULL,
540                                 &fd_err);
541         if (err < 0) {
542                 connman_error("vpnc failed to start");
543                 err = -EIO;
544                 goto done;
545         }
546
547         err = vc_write_config_data(provider, fd_in);
548
549         if (err) {
550                 DBG("config write error %s", strerror(err));
551                 goto done;
552         }
553
554         err = -EINPROGRESS;
555
556         data->err_ch = g_io_channel_unix_new(fd_err);
557         data->err_ch_id = g_io_add_watch(data->err_ch,
558                                 G_IO_IN | G_IO_ERR | G_IO_HUP,
559                                 (GIOFunc)io_channel_cb, data);
560
561 done:
562         close(fd_in);
563
564         /*
565          * Clear out credentials if they are non-immutable. If this is called
566          * directly from vc_connect() all credentials are read from config and
567          * are set as immutable, so no change is done. In case a VPN agent is
568          * used these values should be reset to "-" in order to retrieve them
569          * from VPN agent next time VPN connection is established. This supports
570          * then partially defined credentials in .config and some can be
571          * retrieved using an agent.
572          */
573         for (i = 0; credentials[i]; i++) {
574                 const char *key = credentials[i];
575                 if (!vpn_provider_get_string_immutable(provider, key))
576                         vpn_provider_set_string(provider, key, "-");
577         }
578
579         return err;
580 }
581
582 static void request_input_append_mandatory(DBusMessageIter *iter,
583                 void *user_data)
584 {
585         char *str = "string";
586
587         connman_dbus_dict_append_basic(iter, "Type",
588                                 DBUS_TYPE_STRING, &str);
589         str = "mandatory";
590         connman_dbus_dict_append_basic(iter, "Requirement",
591                                 DBUS_TYPE_STRING, &str);
592
593         if (!user_data)
594                 return;
595
596         str = user_data;
597         connman_dbus_dict_append_basic(iter, "Value", DBUS_TYPE_STRING, &str);
598 }
599
600 static void request_input_append_password(DBusMessageIter *iter,
601                 void *user_data)
602 {
603         char *str = "password";
604
605         connman_dbus_dict_append_basic(iter, "Type",
606                                 DBUS_TYPE_STRING, &str);
607         str = "mandatory";
608         connman_dbus_dict_append_basic(iter, "Requirement",
609                                 DBUS_TYPE_STRING, &str);
610
611         if (!user_data)
612                 return;
613
614         str = user_data;
615         connman_dbus_dict_append_basic(iter, "Value", DBUS_TYPE_STRING, &str);
616 }
617
618 static void request_input_append_informational(DBusMessageIter *iter,
619                 void *user_data)
620 {
621         char *str = "password";
622
623         connman_dbus_dict_append_basic(iter, "Type",
624                                 DBUS_TYPE_STRING, &str);
625         str = "informational";
626         connman_dbus_dict_append_basic(iter, "Requirement",
627                                 DBUS_TYPE_STRING, &str);
628
629         if (!user_data)
630                 return;
631
632         str = user_data;
633         connman_dbus_dict_append_basic(iter, "Value", DBUS_TYPE_STRING, &str);
634 }
635
636 static void request_input_append_to_dict(struct vpn_provider *provider,
637                         DBusMessageIter *dict,
638                         connman_dbus_append_cb_t function_cb, const char *key)
639 {
640         const char *str;
641         bool immutable = false;
642
643         if (!provider || !dict || !function_cb || !key)
644                 return;
645
646         str = vpn_provider_get_string(provider, key);
647
648         /* If value is "-", it is cleared by VPN agent */
649         if (!g_strcmp0(str, "-"))
650                 str = NULL;
651
652         if (str)
653                 immutable = vpn_provider_get_string_immutable(provider, key);
654
655         if (immutable) {
656                 /* Hide immutable password types */
657                 if (function_cb == request_input_append_password)
658                         str = "********";
659
660                 /* Send immutable as informational */
661                 function_cb = request_input_append_informational;
662         }
663
664         connman_dbus_dict_append_dict(dict, key, function_cb, (void *)str);
665 }
666
667 static void request_input_credentials_reply(DBusMessage *reply, void *user_data)
668 {
669         struct vc_private_data *data = user_data;
670         char *secret = NULL, *username = NULL, *password = NULL;
671         const char *key;
672         DBusMessageIter iter, dict;
673         int err;
674
675         DBG("provider %p", data->provider);
676
677         if (!reply) {
678                 err = ENOENT;
679                 goto err;
680         }
681
682         err = vpn_agent_check_and_process_reply_error(reply, data->provider,
683                                 data->task, data->cb, data->user_data);
684         if (err) {
685                 /* Ensure cb is called only once */
686                 data->cb = NULL;
687                 data->user_data = NULL;
688                 return;
689         }
690
691         if (!vpn_agent_check_reply_has_dict(reply)) {
692                 err = ENOENT;
693                 goto err;
694         }
695
696         dbus_message_iter_init(reply, &iter);
697         dbus_message_iter_recurse(&iter, &dict);
698         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
699                 DBusMessageIter entry, value;
700
701                 dbus_message_iter_recurse(&dict, &entry);
702                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
703                         break;
704
705                 dbus_message_iter_get_basic(&entry, &key);
706
707                 if (g_str_equal(key, "VPNC.IPSec.Secret")) {
708                         dbus_message_iter_next(&entry);
709                         if (dbus_message_iter_get_arg_type(&entry)
710                                                         != DBUS_TYPE_VARIANT)
711                                 break;
712                         dbus_message_iter_recurse(&entry, &value);
713                         if (dbus_message_iter_get_arg_type(&value)
714                                                         != DBUS_TYPE_STRING)
715                                 break;
716                         dbus_message_iter_get_basic(&value, &secret);
717                         vpn_provider_set_string_hide_value(data->provider,
718                                         key, secret);
719
720                 } else if (g_str_equal(key, "VPNC.Xauth.Username")) {
721                         dbus_message_iter_next(&entry);
722                         if (dbus_message_iter_get_arg_type(&entry)
723                                                         != DBUS_TYPE_VARIANT)
724                                 break;
725                         dbus_message_iter_recurse(&entry, &value);
726                         if (dbus_message_iter_get_arg_type(&value)
727                                                         != DBUS_TYPE_STRING)
728                                 break;
729                         dbus_message_iter_get_basic(&value, &username);
730                         vpn_provider_set_string(data->provider, key, username);
731
732                 } else if (g_str_equal(key, "VPNC.Xauth.Password")) {
733                         dbus_message_iter_next(&entry);
734                         if (dbus_message_iter_get_arg_type(&entry)
735                                                         != DBUS_TYPE_VARIANT)
736                                 break;
737                         dbus_message_iter_recurse(&entry, &value);
738                         if (dbus_message_iter_get_arg_type(&value)
739                                                         != DBUS_TYPE_STRING)
740                                 break;
741                         dbus_message_iter_get_basic(&value, &password);
742                         vpn_provider_set_string_hide_value(data->provider, key,
743                                                 password);
744                 }
745
746                 dbus_message_iter_next(&dict);
747         }
748
749         if (!secret || !username || !password) {
750                 vpn_provider_indicate_error(data->provider,
751                                         VPN_PROVIDER_ERROR_AUTH_FAILED);
752                 err = EACCES;
753                 goto err;
754         }
755
756         /* vpn_provider.c:connect_cb() expects positive errors */
757         err = -run_connect(data);
758         if (err != EINPROGRESS)
759                 goto err;
760
761         return;
762
763 err:
764         vc_connect_done(data, err);
765 }
766
767 static int request_input_credentials(struct vc_private_data *data,
768                                         const char* dbus_sender)
769 {
770         DBusMessage *message;
771         const char *path, *agent_sender, *agent_path;
772         DBusMessageIter iter;
773         DBusMessageIter dict;
774         int err;
775         void *agent;
776
777         if (!data || !data->provider)
778                 return -ENOENT;
779
780         DBG("data %p provider %p sender %s", data, data->provider, dbus_sender);
781
782         agent = connman_agent_get_info(dbus_sender, &agent_sender, &agent_path);
783         if (!agent || !agent_path)
784                 return -ESRCH;
785
786         message = dbus_message_new_method_call(agent_sender, agent_path,
787                                         VPN_AGENT_INTERFACE,
788                                         "RequestInput");
789         if (!message)
790                 return -ENOMEM;
791
792         dbus_message_iter_init_append(message, &iter);
793
794         path = vpn_provider_get_path(data->provider);
795         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
796
797         connman_dbus_dict_open(&iter, &dict);
798
799         if (vpn_provider_get_authentication_errors(data->provider))
800                 vpn_agent_append_auth_failure(&dict, data->provider, NULL);
801
802         request_input_append_to_dict(data->provider, &dict,
803                                 request_input_append_password,
804                                 "VPNC.IPSec.Secret");
805         request_input_append_to_dict(data->provider, &dict,
806                                 request_input_append_mandatory,
807                                 "VPNC.Xauth.Username");
808         request_input_append_to_dict(data->provider, &dict,
809                                 request_input_append_password,
810                                 "VPNC.Xauth.Password");
811
812         vpn_agent_append_host_and_name(&dict, data->provider);
813
814         connman_dbus_dict_close(&iter, &dict);
815
816         err = connman_agent_queue_message(data->provider, message,
817                                 connman_timeout_input_request(),
818                                 request_input_credentials_reply, data, agent);
819
820         dbus_message_unref(message);
821
822         if (err < 0 && err != -EBUSY) {
823                 DBG("error %d sending agent request", err);
824                 return err;
825         }
826
827         return -EINPROGRESS;
828 }
829
830 static int vc_connect(struct vpn_provider *provider,
831                         struct connman_task *task, const char *if_name,
832                         vpn_provider_connect_cb_t cb, const char *dbus_sender,
833                         void *user_data)
834 {
835         struct vc_private_data *data;
836         const char *option;
837         bool username_set = false;
838         bool password_set = false;
839         bool ipsec_secret_set = false;
840         int err;
841
842         DBG("provider %p if_name %s user_data %p", provider, if_name, user_data);
843
844         option = vpn_provider_get_string(provider, "VPNC.IPSec.ID");
845         if (!option) {
846                 connman_error("Group not set; cannot enable VPN");
847                 return -EINVAL;
848         }
849
850         option = vpn_provider_get_string(provider, "VPNC.IPSec.Secret");
851         if (option && *option && g_strcmp0(option, "-"))
852                 ipsec_secret_set = true;
853
854         option = vpn_provider_get_string(provider, "VPNC.Xauth.Username");
855         if (option && *option && g_strcmp0(option, "-"))
856                 username_set = true;
857
858         option = vpn_provider_get_string(provider, "VPNC.Xauth.Password");
859         if (option && *option && g_strcmp0(option, "-"))
860                 password_set = true;
861
862         data = g_try_new0(struct vc_private_data, 1);
863         if (!data)
864                 return -ENOMEM;
865
866         vpn_provider_set_plugin_data(provider, data);
867         data->provider = vpn_provider_ref(provider);
868         data->task = task;
869         data->if_name = g_strdup(if_name);
870         data->cb = cb;
871         data->user_data = user_data;
872
873         if (!ipsec_secret_set || !username_set || !password_set) {
874                 err = request_input_credentials(data, dbus_sender);
875                 if (err != -EINPROGRESS) {
876                         vc_connect_done(data, ECONNABORTED);
877                         vpn_provider_indicate_error(data->provider,
878                                         VPN_PROVIDER_ERROR_LOGIN_FAILED);
879                         free_private_data(data);
880                 }
881
882                 return err;
883         }
884
885         return run_connect(data);
886 }
887
888 static void vc_disconnect(struct vpn_provider *provider)
889 {
890         if (!provider)
891                 return;
892
893         connman_agent_cancel(provider);
894 }
895
896 static int vc_error_code(struct vpn_provider *provider, int exit_code)
897 {
898         switch (exit_code) {
899         case 1:
900                 return VPN_PROVIDER_ERROR_CONNECT_FAILED;
901         case 2:
902                 return VPN_PROVIDER_ERROR_LOGIN_FAILED;
903         default:
904                 return VPN_PROVIDER_ERROR_UNKNOWN;
905         }
906 }
907
908 static int vc_device_flags(struct vpn_provider *provider)
909 {
910         const char *option;
911
912         option = vpn_provider_get_string(provider, "VPNC.DeviceType");
913         if (!option) {
914                 return IFF_TUN;
915         }
916
917         if (g_str_equal(option, "tap")) {
918                 return IFF_TAP;
919         }
920
921         if (!g_str_equal(option, "tun")) {
922                 connman_warn("bad VPNC.DeviceType value, falling back to tun");
923         }
924
925         return IFF_TUN;
926 }
927
928 static struct vpn_driver vpn_driver = {
929         .notify         = vc_notify,
930         .connect        = vc_connect,
931         .disconnect     = vc_disconnect,
932         .error_code     = vc_error_code,
933         .save           = vc_save,
934         .device_flags   = vc_device_flags,
935 };
936
937 static int vpnc_init(void)
938 {
939         return vpn_register("vpnc", &vpn_driver, VPNC);
940 }
941
942 static void vpnc_exit(void)
943 {
944         vpn_unregister("vpnc");
945 }
946
947 CONNMAN_PLUGIN_DEFINE(vpnc, "vpnc plugin", VERSION,
948         CONNMAN_PLUGIN_PRIORITY_DEFAULT, vpnc_init, vpnc_exit)