Chromium Code Reviews| Index: plugins/l2tpipsec.c |
| diff --git a/plugins/l2tpipsec.c b/plugins/l2tpipsec.c |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..186f3814999a954c4a8aedf38c67fbb907892a2d |
| --- /dev/null |
| +++ b/plugins/l2tpipsec.c |
| @@ -0,0 +1,234 @@ |
| +/* |
| + * L2TP/IPsec VPN plugin. |
| + * |
| + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| + * Use of this source code is governed by a BSD-style license that can be |
| + * found in the LICENSE file. |
| + * |
| + */ |
| + |
| +#ifdef HAVE_CONFIG_H |
| +#include <config.h> |
| +#endif |
| + |
| +#include <string.h> |
| +#include <errno.h> |
| +#include <unistd.h> |
| +#include <sys/types.h> |
| +#include <sys/stat.h> |
| +#include <fcntl.h> |
| + |
| +#include <stdio.h> |
| +#include <net/if.h> |
| + |
| +#include <glib.h> |
| + |
| +#define CONNMAN_API_SUBJECT_TO_CHANGE |
| +#include <connman/plugin.h> |
| +#include <connman/provider.h> |
| +#include <connman/log.h> |
| +#include <connman/task.h> |
| +#include <connman/dbus.h> |
| +#include <connman/inet.h> |
| + |
| +#include "vpn.h" |
| + |
| +#define _DBG_VPN(fmt, arg...) DBG(DBG_VPN, fmt, ## arg) |
| + |
| +static DBusConnection *connection; |
| + |
| +static DBusMessage *li_get_sec(struct connman_task *task, |
| + DBusMessage *msg, void *user_data) |
| +{ |
| + const char *user, *passwd; |
| + struct connman_provider *provider = user_data; |
| + |
| + if (dbus_message_get_no_reply(msg) == FALSE) { |
| + DBusMessage *reply; |
| + |
| + user = connman_provider_get_string(provider, "L2TPIPsec.User"); |
| + passwd = connman_provider_get_string(provider, |
| + "L2TPIPsec.Password"); |
| + |
| + if (user == NULL || strlen(user) == 0 || |
| + passwd == NULL || strlen(passwd) == 0) { |
| + _DBG_VPN("User or password not set"); |
|
Sam Leffler
2011/03/11 17:49:55
if you print both user+passwd then you can see whi
|
| + return NULL; |
| + } |
| + |
| + reply = dbus_message_new_method_return(msg); |
| + if (reply == NULL) |
| + return NULL; |
| + |
| + dbus_message_append_args(reply, DBUS_TYPE_STRING, &user, |
| + DBUS_TYPE_STRING, &passwd, |
| + DBUS_TYPE_INVALID); |
| + |
| + return reply; |
| + } |
| + |
| + return NULL; |
| +} |
| + |
| +static int li_notify(DBusMessage *msg, struct connman_provider *provider) |
| +{ |
| + DBusMessageIter iter, dict; |
| + const char *reason, *key, *value; |
| + char *ifname = NULL; |
| + char *dns1 = NULL; |
| + char *dns2 = NULL; |
| + struct connman_ipaddress ipaddr; |
| + |
| + dbus_message_iter_init(msg, &iter); |
| + |
| + dbus_message_iter_get_basic(&iter, &reason); |
| + dbus_message_iter_next(&iter); |
|
Sam Leffler
2011/03/11 17:49:55
might want _DBG_VPN("reason %s", reason) here; not
kmixter1
2011/03/12 00:52:31
Done.
|
| + |
| + if (provider == NULL) { |
| + connman_error("%s: No provider found", __func__); |
| + return VPN_STATE_FAILURE; |
| + } |
| + |
| + if (strcmp(reason, "connect")) |
| + return VPN_STATE_DISCONNECT; |
| + |
| + memset(&ipaddr, 0, sizeof(ipaddr)); |
| + ipaddr.af = AF_INET; |
| + ipaddr.mask |= CONNMAN_IPCONFIG_AF; |
| + |
| + dbus_message_iter_recurse(&iter, &dict); |
| + |
| + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { |
| + DBusMessageIter entry; |
| + |
| + dbus_message_iter_recurse(&dict, &entry); |
| + dbus_message_iter_get_basic(&entry, &key); |
| + dbus_message_iter_next(&entry); |
| + dbus_message_iter_get_basic(&entry, &value); |
| + |
| + _DBG_VPN("%s = %s", key, value); |
| + |
| + if (!strcmp(key, "INTERNAL_IP4_ADDRESS")) { |
| + ipaddr.local = g_strdup(value); |
| + ipaddr.mask |= CONNMAN_IPCONFIG_LOCAL; |
| + } else if (!strcmp(key, "EXTERNAL_IP4_ADDRESS")) { |
| + ipaddr.peer = g_strdup(value); |
| + ipaddr.mask |= CONNMAN_IPCONFIG_PEER; |
| + } else if (!strcmp(key, "DNS1")) { |
| + dns1 = g_strdup(value); |
| + } else if (!strcmp(key, "DNS2")) { |
| + dns2 = g_strdup(value); |
| + } else if (!strcmp(key, "INTERNAL_IFNAME")) { |
| + ifname = g_strdup(value); |
| + } |
| + |
| + dbus_message_iter_next(&dict); |
| + } |
| + |
| + ipaddr.dns_servers = g_try_new0(gchar *, 3); |
| + if (dns1 != NULL) { |
| + ipaddr.dns_servers[0] = dns1; |
| + if (dns2 != NULL) |
| + ipaddr.dns_servers[1] = dns2; |
| + ipaddr.mask |= CONNMAN_IPCONFIG_DNS; |
| + } |
| + |
| + if (vpn_set_ifname(provider, ifname) <0) { |
| + g_free(ifname); |
| + return VPN_STATE_FAILURE; |
| + } |
| + |
| + connman_provider_ipconfig_set(provider, &ipaddr); |
| + |
| + g_free(ifname); |
| + g_free(dns1); |
| + g_free(dns2); |
| + g_strfreev(ipaddr.dns_servers); /* TODO(kmixter): OK to free? */ |
|
Sam Leffler
2011/03/11 17:49:55
you own the storage so you need to free (note cons
|
| + |
| + return VPN_STATE_CONNECT; |
| +} |
| + |
| +static int li_connect(struct connman_provider *provider, |
| + struct connman_task *task, const char *if_name) |
| +{ |
| +#define OPT_STR(property, option) do { \ |
| + const char *s = connman_provider_get_string(provider, property); \ |
| + if (s != NULL) \ |
| + connman_task_add_argument(task, option, (char *)s); \ |
| +} while (0) |
| +#define OPT_BOOL(property, true_option, false_option) do { \ |
| + const char *s = connman_provider_get_string(provider, property); \ |
| + if (s != NULL) { \ |
| + connman_task_add_argument(task, strcmp("true", s) == 0 ? \ |
| + true_option : false_option, \ |
| + NULL); \ |
| + } \ |
| +} while (0) |
| + const char *vpnhost; |
| + int err, fd; |
| + |
| + if (connman_task_set_notify(task, "getsec", |
| + li_get_sec, provider)) |
| + return -ENOMEM; |
| + |
| + vpnhost = connman_provider_get_string(provider, "Host"); |
| + if (!vpnhost) { |
| + connman_error("%s: host not set; cannot enable VPN", __func__); |
| + return -EINVAL; |
| + } |
| + |
| + connman_task_add_argument(task, "--remote_address", |
| + (char *)vpnhost); |
| + connman_task_add_argument(task, "--pppd_plugin", |
| + SCRIPTDIR "/libppp-plugin.so"); |
| + |
| + OPT_STR("L2TPIPsec.CACert", "--server_ca_file"); |
| + OPT_STR("L2TPIPsec.Key", "--client_key_file"); |
| + OPT_STR("L2TPIPsec.Cert", "--client_cert_file"); |
| + OPT_STR("L2TPIPsec.PSK", "--psk_file"); |
| + OPT_STR("L2TPIPsec.User", "--user"); |
| + OPT_STR("L2TPIPsec.IPsecTimeout", "--ipsec_timeout"); |
| + OPT_STR("L2TPIPsec.LeftProtoPort", "--leftprotoport"); |
| + OPT_BOOL("L2TPIPsec.PFS", "--pfs", "--nopfs"); |
| + OPT_BOOL("L2TPIPsec.Rekey", "--rekey", "--norekey"); |
| + OPT_STR("L2TPIPsec.RightProtoPort", "--leftprotoport"); |
| + |
| + OPT_BOOL("L2TPIPsec.RequireChap", "--require_chap", "--norequire_chap"); |
| + OPT_BOOL("L2TPIPsec.RefusePap", "--refuse_pap", "--norefuse_pap"); |
| + OPT_BOOL("L2TPIPsec.RequireAuth", "--require_authentication", |
| + "--norequire_authentication"); |
| + OPT_BOOL("L2TPIPsec.LengthBit", "--length_bit", "--nolength_bit"); |
| + |
| + fd = fileno(stderr); |
| + err = connman_task_run(task, vpn_died, provider, |
| + NULL, &fd, &fd); |
| + if (err < 0) { |
| + connman_error("l2tpipsec failed to start"); |
| + return -EIO; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static struct vpn_driver vpn_driver = { |
| + .flags = VPN_FLAG_NO_TUN, |
| + .notify = li_notify, |
| + .connect = li_connect, |
| +}; |
| + |
| +static int li_init(void) |
| +{ |
| + connection = connman_dbus_get_connection(); |
| + |
| + return vpn_register("l2tpipsec", &vpn_driver, L2TPIPSEC); |
| +} |
| + |
| +static void li_exit(void) |
| +{ |
| + vpn_unregister("l2tpipsec"); |
| + |
| + dbus_connection_unref(connection); |
| +} |
| + |
| +CONNMAN_PLUGIN_DEFINE(l2tpipsec, "l2tpipsec plugin", VERSION, |
| + CONNMAN_PLUGIN_PRIORITY_DEFAULT, li_init, li_exit) |