X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=plugins%2Fopenconnect.c;h=cf3bcd97ace3cf0886c04e321673a7075ac832e4;hb=5ed7094e4994d03c7606f25881918565c81d1c24;hp=891aa8764a91ff3adecb22e2340dd7a44aadd00c;hpb=2f217e25d799ef351d4e8e06b0da83e72b2183f0;p=framework%2Fconnectivity%2Fconnman.git diff --git a/plugins/openconnect.c b/plugins/openconnect.c index 891aa87..cf3bcd9 100644 --- a/plugins/openconnect.c +++ b/plugins/openconnect.c @@ -23,122 +23,32 @@ #include #endif +#include #include -#include -#include -#include -#include -#include #include -#include -#include +#include #include -#include -#include -#include -#include -#include +#include #define CONNMAN_API_SUBJECT_TO_CHANGE #include -#include -#include #include #include -#include -#include #include +#include -#include "inet.h" - -struct oc_data { - char *if_name; - unsigned flags; - unsigned int watch; - struct connman_task *task; -}; - -static int kill_tun(char *tun_name) -{ - struct ifreq ifr; - int fd, err; - - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; - sprintf(ifr.ifr_name, "%s", tun_name); - - fd = open("/dev/net/tun", O_RDWR); - if (fd < 0) { - err = -errno; - connman_error("Failed to open /dev/net/tun to device %s: %s", - tun_name, strerror(errno)); - return err; - } - - if (ioctl(fd, TUNSETIFF, (void *)&ifr)) { - err = -errno; - connman_error("Failed to TUNSETIFF for device %s to it: %s", - tun_name, strerror(errno)); - close(fd); - return err; - } - - if (ioctl(fd, TUNSETPERSIST, 0)) { - err = -errno; - connman_error("Failed to set tun device %s nonpersistent: %s", - tun_name, strerror(errno)); - close(fd); - return err; - } - close(fd); - DBG("Killed tun device %s", tun_name); - return 0; -} - -static void openconnect_died(struct connman_task *task, void *user_data) -{ - struct connman_provider *provider = user_data; - struct oc_data *data = connman_provider_get_data(provider); - - DBG("provider %p data %p", provider, data); - - if (!data) - goto oc_exit; +#include "vpn.h" - kill_tun(data->if_name); - connman_provider_set_data(provider, NULL); - connman_rtnl_remove_watch(data->watch); - g_free(data); - - oc_exit: - connman_provider_set_connected(provider, FALSE); - connman_provider_set_index(provider, -1); - connman_provider_unref(provider); - connman_task_destroy(task); -} - -static void vpn_newlink(unsigned flags, unsigned change, void *user_data) -{ - struct connman_provider *provider = user_data; - struct oc_data *data = connman_provider_get_data(provider); - - if ((data->flags & IFF_UP) != (flags & IFF_UP)) { - if (flags & IFF_UP) - connman_provider_set_connected(provider, TRUE); - } - data->flags = flags; -} - -static void openconnect_task_notify(struct connman_task *task, - DBusMessage *msg, void *user_data) +static int oc_notify(DBusMessage *msg, struct connman_provider *provider) { DBusMessageIter iter, dict; - struct connman_provider *provider = user_data; - struct oc_data *data; const char *reason, *key, *value; const char *domain = NULL; - int index; + char *addressv4 = NULL, *addressv6 = NULL; + char *netmask = NULL, *gateway = NULL; + unsigned char prefix_len = 0; + struct connman_ipaddress *ipaddress; dbus_message_iter_init(msg, &iter); @@ -147,19 +57,11 @@ static void openconnect_task_notify(struct connman_task *task, if (!provider) { connman_error("No provider found"); - return; - } - - data = connman_provider_get_data(provider); - if (!data) { - DBG("provider %p no data", provider); - return; + return VPN_STATE_FAILURE; } - if (strcmp(reason, "connect")) { - connman_provider_set_connected(provider, FALSE); - return; - } + if (strcmp(reason, "connect")) + return VPN_STATE_DISCONNECT; domain = connman_provider_get_string(provider, "VPN.Domain"); @@ -177,251 +79,202 @@ static void openconnect_task_notify(struct connman_task *task, DBG("%s = %s", key, value); if (!strcmp(key, "VPNGATEWAY")) - connman_provider_set_string(provider, "Gateway", value); + gateway = g_strdup(value); if (!strcmp(key, "INTERNAL_IP4_ADDRESS")) - connman_provider_set_string(provider, "Address", value); + addressv4 = g_strdup(value); + + if (!strcmp(key, "INTERNAL_IP6_ADDRESS")) { + addressv6 = g_strdup(value); + prefix_len = 128; + } if (!strcmp(key, "INTERNAL_IP4_NETMASK")) - connman_provider_set_string(provider, "Netmask", value); + netmask = g_strdup(value); + + if (!strcmp(key, "INTERNAL_IP6_NETMASK")) { + char *sep; + + /* The netmask contains the address and the prefix */ + sep = strchr(value, '/'); + if (sep != NULL) { + unsigned char ip_len = sep - value; + + addressv6 = g_strndup(value, ip_len); + prefix_len = (unsigned char) + strtol(sep + 1, NULL, 10); + } + } - if (!strcmp(key, "INTERNAL_IP4_DNS")) - connman_provider_set_string(provider, "DNS", value); + if (!strcmp(key, "INTERNAL_IP4_DNS") || + !strcmp(key, "INTERNAL_IP6_DNS")) + connman_provider_set_nameservers(provider, value); if (!strcmp(key, "CISCO_PROXY_PAC")) - connman_provider_set_string(provider, "PAC", value); + connman_provider_set_pac(provider, value); if (domain == NULL && !strcmp(key, "CISCO_DEF_DOMAIN")) domain = value; + if (g_str_has_prefix(key, "CISCO_SPLIT_INC") == TRUE || + g_str_has_prefix(key, "CISCO_IPV6_SPLIT_INC") == TRUE) + connman_provider_append_route(provider, key, value); + dbus_message_iter_next(&dict); } - index = connman_provider_get_index(provider); - connman_provider_set_string(provider, "Domain", domain); - data->watch = connman_rtnl_add_newlink_watch(index, - vpn_newlink, provider); + DBG("%p %p", addressv4, addressv6); - connman_inet_ifup(index); -} + if (addressv4 != NULL) + ipaddress = connman_ipaddress_alloc(AF_INET); + else if (addressv6 != NULL) + ipaddress = connman_ipaddress_alloc(AF_INET6); + else + ipaddress = NULL; -static int oc_connect(struct connman_provider *provider) -{ - struct oc_data *data = connman_provider_get_data(provider); - struct ifreq ifr; - int oc_fd, fd, i, index; - const char *vpnhost, *vpncookie, *cafile, *mtu; - int ret = 0; + if (ipaddress == NULL) { + g_free(addressv4); + g_free(addressv6); + g_free(netmask); + g_free(gateway); - if (data != NULL) - return -EISCONN; - - data = g_try_new0(struct oc_data, 1); - if (data == NULL) - return -ENOMEM; + return VPN_STATE_FAILURE; + } - data->watch = 0; - data->flags = 0; - data->task = NULL; + if (addressv4 != NULL) + connman_ipaddress_set_ipv4(ipaddress, addressv4, + netmask, gateway); + else + connman_ipaddress_set_ipv6(ipaddress, addressv6, + prefix_len, gateway); + connman_provider_set_ipaddress(provider, ipaddress); + connman_provider_set_domain(provider, domain); + + g_free(addressv4); + g_free(addressv6); + g_free(netmask); + g_free(gateway); + connman_ipaddress_free(ipaddress); + + return VPN_STATE_CONNECT; +} - connman_provider_set_data(provider, data); +static int oc_connect(struct connman_provider *provider, + struct connman_task *task, const char *if_name) +{ + const char *vpnhost, *vpncookie, *cafile, *certsha1, *mtu; + int fd, err; - vpnhost = connman_provider_get_string(provider, "OpenConnect.Host"); + vpnhost = connman_provider_get_string(provider, "Host"); if (!vpnhost) { - connman_error("OpenConnect.Host not set; cannot enable VPN"); - ret = -EINVAL; - goto exist_err; + connman_error("Host not set; cannot enable VPN"); + return -EINVAL; } vpncookie = connman_provider_get_string(provider, "OpenConnect.Cookie"); if (!vpncookie) { connman_error("OpenConnect.Cookie not set; cannot enable VPN"); - ret = -EINVAL; - goto exist_err; + return -EINVAL; } + certsha1 = connman_provider_get_string(provider, + "OpenConnect.ServerCert"); + if (certsha1) + connman_task_add_argument(task, "--servercert", + (char *)certsha1); + cafile = connman_provider_get_string(provider, "OpenConnect.CACert"); mtu = connman_provider_get_string(provider, "VPN.MTU"); - fd = open("/dev/net/tun", O_RDWR); - if (fd < 0) { - i = -errno; - connman_error("Failed to open /dev/net/tun: %s", - strerror(errno)); - ret = i; - goto exist_err; - } - - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; - - for (i = 0; i < 256; i++) { - sprintf(ifr.ifr_name, "vpn%d", i); - - if (!ioctl(fd, TUNSETIFF, (void *)&ifr)) - break; - } - - if (i == 256) { - connman_error("Failed to find available tun device"); - close(fd); - ret = -ENODEV; - goto exist_err; - } - - data->if_name = (char *)g_strdup(ifr.ifr_name); - if (!data->if_name) { - ret = -ENOMEM; - goto exist_err; - } - - if (ioctl(fd, TUNSETPERSIST, 1)) { - i = -errno; - connman_error("Failed to set tun persistent: %s", - strerror(errno)); - close(fd); - ret = i; - goto exist_err; - } - - close(fd); - - index = connman_inet_ifindex(data->if_name); - if (index < 0) { - connman_error("Failed to get tun ifindex"); - kill_tun(data->if_name); - ret = -EIO; - goto exist_err; - } - connman_provider_set_index(provider, index); - - data->task = connman_task_create(OPENCONNECT); - - if (data->task == NULL) { - ret = -ENOMEM; - kill_tun(data->if_name); - goto exist_err; - } - - if (connman_task_set_notify(data->task, "notify", - openconnect_task_notify, provider)) { - ret = -ENOMEM; - kill_tun(data->if_name); - connman_task_destroy(data->task); - data->task = NULL; - goto exist_err; - } - if (cafile) - connman_task_add_argument(data->task, "--cafile", + connman_task_add_argument(task, "--cafile", (char *)cafile); if (mtu) - connman_task_add_argument(data->task, "--mtu", (char *)mtu); + connman_task_add_argument(task, "--mtu", (char *)mtu); - connman_task_add_argument(data->task, "--syslog", NULL); - connman_task_add_argument(data->task, "--cookie-on-stdin", NULL); + connman_task_add_argument(task, "--syslog", NULL); + connman_task_add_argument(task, "--cookie-on-stdin", NULL); - connman_task_add_argument(data->task, "--script", + connman_task_add_argument(task, "--script", SCRIPTDIR "/openconnect-script"); - connman_task_add_argument(data->task, "--interface", data->if_name); + connman_task_add_argument(task, "--interface", if_name); - connman_task_add_argument(data->task, (char *)vpnhost, NULL); + connman_task_add_argument(task, (char *)vpnhost, NULL); - ret = connman_task_run(data->task, openconnect_died, provider, - &oc_fd, NULL, NULL); - if (ret) { - connman_error("Openconnect failed to start"); - kill_tun(data->if_name); - ret = -EIO; - connman_task_destroy(data->task); - data->task = NULL; - goto exist_err; + err = connman_task_run(task, vpn_died, provider, + &fd, NULL, NULL); + if (err < 0) { + connman_error("openconnect failed to start"); + return -EIO; } - DBG("openconnect started with dev %s", data->if_name); - - if (write(oc_fd, vpncookie, strlen(vpncookie)) != - (ssize_t)strlen(vpncookie) || - write(oc_fd, "\n", 1) != 1) { + if (write(fd, vpncookie, strlen(vpncookie)) != + (ssize_t)strlen(vpncookie) || + write(fd, "\n", 1) != 1) { connman_error("openconnect failed to take cookie on stdin"); - connman_provider_set_data(provider, NULL); - connman_task_stop(data->task); - ret = -EIO; - goto exist_err; + return -EIO; } - connman_provider_ref(provider); - return -EINPROGRESS; - - exist_err: - connman_provider_set_index(provider, -1); - connman_provider_set_data(provider, NULL); - g_free(data); - - return ret; -} - -static int oc_probe(struct connman_provider *provider) -{ return 0; } -static int oc_disconnect(struct connman_provider *provider) +static int oc_save (struct connman_provider *provider, GKeyFile *keyfile) { - struct oc_data *data = connman_provider_get_data(provider); - - DBG("disconnect provider %p:", provider); - - if (data == NULL) - return 0; - - if (data->watch != 0) - connman_rtnl_remove_watch(data->watch); - - data->watch = 0; - connman_task_stop(data->task); + const char *setting; + + setting = connman_provider_get_string(provider, + "OpenConnect.ServerCert"); + if (setting != NULL) + g_key_file_set_string(keyfile, + connman_provider_get_save_group(provider), + "OpenConnect.ServerCert", setting); + + setting = connman_provider_get_string(provider, + "OpenConnect.CACert"); + if (setting != NULL) + g_key_file_set_string(keyfile, + connman_provider_get_save_group(provider), + "OpenConnect.CACert", setting); + + setting = connman_provider_get_string(provider, + "VPN.MTU"); + if (setting != NULL) + g_key_file_set_string(keyfile, + connman_provider_get_save_group(provider), + "VPN.MTU", setting); return 0; } -static int oc_remove(struct connman_provider *provider) +static int oc_error_code(int exit_code) { - struct oc_data *data; - - data = connman_provider_get_data(provider); - connman_provider_set_data(provider, NULL); - if (data == NULL) - return 0; - if (data->watch != 0) - connman_rtnl_remove_watch(data->watch); - data->watch = 0; - connman_task_stop(data->task); - - g_usleep(G_USEC_PER_SEC); - kill_tun(data->if_name); - return 0; + switch (exit_code) { + case 1: + return CONNMAN_PROVIDER_ERROR_CONNECT_FAILED; + case 2: + return CONNMAN_PROVIDER_ERROR_LOGIN_FAILED; + default: + return CONNMAN_PROVIDER_ERROR_UNKNOWN; + } } -static struct connman_provider_driver provider_driver = { - .name = "openconnect", - .disconnect = oc_disconnect, +static struct vpn_driver vpn_driver = { + .notify = oc_notify, .connect = oc_connect, - .probe = oc_probe, - .remove = oc_remove, + .error_code = oc_error_code, + .save = oc_save, }; static int openconnect_init(void) { - connman_provider_driver_register(&provider_driver); - - return 0; + return vpn_register("openconnect", &vpn_driver, OPENCONNECT); } static void openconnect_exit(void) { - connman_provider_driver_unregister(&provider_driver); + vpn_unregister("openconnect"); } CONNMAN_PLUGIN_DEFINE(openconnect, "OpenConnect VPN plugin", VERSION,