From 8f2d1a5c1a48fd4fbc32eae5fc31c6aa9850a286 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 13 Feb 2014 16:10:09 +0000 Subject: [PATCH] Move set_script_env() to script.c Let's move the environment stuff out of the way so that tun.c can be built for sane platforms only. Signed-off-by: David Woodhouse --- Makefile.am | 3 +- openconnect-internal.h | 4 + script.c | 306 +++++++++++++++++++++++++++++++++++++++++ tun.c | 271 ------------------------------------ 4 files changed, 312 insertions(+), 272 deletions(-) create mode 100644 script.c diff --git a/Makefile.am b/Makefile.am index 4fdab34e..beebdb95 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,7 +18,8 @@ openconnect_SOURCES = xml.c main.c openconnect_CFLAGS = $(AM_CFLAGS) $(SSL_CFLAGS) $(DTLS_SSL_CFLAGS) $(LIBXML2_CFLAGS) $(LIBPROXY_CFLAGS) $(ZLIB_CFLAGS) $(LIBSTOKEN_CFLAGS) $(LIBOATH_CFLAGS) openconnect_LDADD = libopenconnect.la $(LIBXML2_LIBS) $(LIBPROXY_LIBS) $(LIBINTL) -library_srcs = ssl.c http.c auth.c library.c compat.c dtls.c cstp.c mainloop.c tun.c +library_srcs = ssl.c http.c auth.c library.c compat.c dtls.c cstp.c \ + mainloop.c tun.c script.c lib_srcs_gnutls = gnutls.c gnutls_pkcs12.c gnutls_tpm.c lib_srcs_openssl = openssl.c diff --git a/openconnect-internal.h b/openconnect-internal.h index c5959b57..d63c9bef 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -448,6 +448,10 @@ int dumb_socketpair(int socks[2], int make_overlapped); /* tun-win32.c */ int win32_setup_tun(struct openconnect_info *vpninfo); +/* script.c */ +int setenv_int(const char *opt, int value); +void set_script_env(struct openconnect_info *vpninfo); + /* tun.c */ int tun_mainloop(struct openconnect_info *vpninfo, int *timeout); void shutdown_tun(struct openconnect_info *vpninfo); diff --git a/script.c b/script.c new file mode 100644 index 00000000..89baa5bf --- /dev/null +++ b/script.c @@ -0,0 +1,306 @@ +/* + * OpenConnect (SSL + DTLS) VPN client + * + * Copyright © 2008-2014 Intel Corporation. + * + * Author: David Woodhouse + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#include +#include +#endif +#include +#include +#include +#include + +#include "openconnect-internal.h" + +int setenv_int(const char *opt, int value) +{ + char buf[16]; + sprintf(buf, "%d", value); + return setenv(opt, buf, 1); +} + +static int netmasklen(struct in_addr addr) +{ + int masklen; + + for (masklen = 0; masklen < 32; masklen++) { + if (ntohl(addr.s_addr) >= (0xffffffff << masklen)) + break; + } + return 32 - masklen; +} + +static int process_split_xxclude(struct openconnect_info *vpninfo, + int include, const char *route, int *v4_incs, + int *v6_incs) +{ + struct in_addr addr; + const char *in_ex = include ? "IN" : "EX"; + char envname[80]; + char *slash; + + slash = strchr(route, '/'); + if (!slash) { + badinc: + if (include) + vpn_progress(vpninfo, PRG_ERR, + _("Discard bad split include: \"%s\"\n"), + route); + else + vpn_progress(vpninfo, PRG_ERR, + _("Discard bad split exclude: \"%s\"\n"), + route); + return -EINVAL; + } + + *slash = 0; + + if (strchr(route, ':')) { + snprintf(envname, 79, "CISCO_IPV6_SPLIT_%sC_%d_ADDR", in_ex, + *v6_incs); + setenv(envname, route, 1); + + snprintf(envname, 79, "CISCO_IPV6_SPLIT_%sC_%d_MASKLEN", in_ex, + *v6_incs); + setenv(envname, slash+1, 1); + + (*v6_incs)++; + return 0; + } + + if (!inet_aton(route, &addr)) { + *slash = '/'; + goto badinc; + } + + envname[79] = 0; + snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_ADDR", in_ex, *v4_incs); + setenv(envname, route, 1); + + /* Put it back how we found it */ + *slash = '/'; + + if (!inet_aton(slash+1, &addr)) + goto badinc; + + snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_MASK", in_ex, *v4_incs); + setenv(envname, slash+1, 1); + + snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_MASKLEN", in_ex, *v4_incs); + setenv_int(envname, netmasklen(addr)); + + (*v4_incs)++; + return 0; +} + +static int appendenv(const char *opt, const char *new) +{ + char buf[1024]; + char *old = getenv(opt); + + buf[1023] = 0; + if (old) + snprintf(buf, 1023, "%s %s", old, new); + else + snprintf(buf, 1023, "%s", new); + + return setenv(opt, buf, 1); +} + +static void setenv_cstp_opts(struct openconnect_info *vpninfo) +{ + char *env_buf; + int buflen = 0; + int bufofs = 0; + struct oc_vpn_option *opt; + + for (opt = vpninfo->cstp_options; opt; opt = opt->next) + buflen += 2 + strlen(opt->option) + strlen(opt->value); + + env_buf = malloc(buflen + 1); + if (!env_buf) + return; + + env_buf[buflen] = 0; + + for (opt = vpninfo->cstp_options; opt; opt = opt->next) + bufofs += snprintf(env_buf + bufofs, buflen - bufofs, + "%s=%s\n", opt->option, opt->value); + + setenv("CISCO_CSTP_OPTIONS", env_buf, 1); + free(env_buf); +} + +static void set_banner(struct openconnect_info *vpninfo) +{ + char *banner, *q; + const char *p; + + if (!vpninfo->banner || !(banner = malloc(strlen(vpninfo->banner)+1))) { + unsetenv("CISCO_BANNER"); + return; + } + p = vpninfo->banner; + q = banner; + + while (*p) { + if (*p == '%' && isxdigit((int)(unsigned char)p[1]) && + isxdigit((int)(unsigned char)p[2])) { + *(q++) = unhex(p + 1); + p += 3; + } else + *(q++) = *(p++); + } + *q = 0; + setenv("CISCO_BANNER", banner, 1); + + free(banner); +} + +void set_script_env(struct openconnect_info *vpninfo) +{ + char host[80]; + int ret = getnameinfo(vpninfo->peer_addr, vpninfo->peer_addrlen, host, + sizeof(host), NULL, 0, NI_NUMERICHOST); + if (!ret) + setenv("VPNGATEWAY", host, 1); + + set_banner(vpninfo); + unsetenv("CISCO_SPLIT_INC"); + unsetenv("CISCO_SPLIT_EXC"); + + setenv_int("INTERNAL_IP4_MTU", vpninfo->ip_info.mtu); + + if (vpninfo->ip_info.addr) { + setenv("INTERNAL_IP4_ADDRESS", vpninfo->ip_info.addr, 1); + if (vpninfo->ip_info.netmask) { + struct in_addr addr; + struct in_addr mask; + + if (inet_aton(vpninfo->ip_info.addr, &addr) && + inet_aton(vpninfo->ip_info.netmask, &mask)) { + char *netaddr; + + addr.s_addr &= mask.s_addr; + netaddr = inet_ntoa(addr); + + setenv("INTERNAL_IP4_NETADDR", netaddr, 1); + setenv("INTERNAL_IP4_NETMASK", vpninfo->ip_info.netmask, 1); + setenv_int("INTERNAL_IP4_NETMASKLEN", netmasklen(mask)); + } + } + } + if (vpninfo->ip_info.addr6) { + setenv("INTERNAL_IP6_ADDRESS", vpninfo->ip_info.addr6, 1); + setenv("INTERNAL_IP6_NETMASK", vpninfo->ip_info.netmask6, 1); + } + + if (vpninfo->ip_info.dns[0]) + setenv("INTERNAL_IP4_DNS", vpninfo->ip_info.dns[0], 1); + else + unsetenv("INTERNAL_IP4_DNS"); + if (vpninfo->ip_info.dns[1]) + appendenv("INTERNAL_IP4_DNS", vpninfo->ip_info.dns[1]); + if (vpninfo->ip_info.dns[2]) + appendenv("INTERNAL_IP4_DNS", vpninfo->ip_info.dns[2]); + + if (vpninfo->ip_info.nbns[0]) + setenv("INTERNAL_IP4_NBNS", vpninfo->ip_info.nbns[0], 1); + else + unsetenv("INTERNAL_IP4_NBNS"); + if (vpninfo->ip_info.nbns[1]) + appendenv("INTERNAL_IP4_NBNS", vpninfo->ip_info.nbns[1]); + if (vpninfo->ip_info.nbns[2]) + appendenv("INTERNAL_IP4_NBNS", vpninfo->ip_info.nbns[2]); + + if (vpninfo->ip_info.domain) + setenv("CISCO_DEF_DOMAIN", vpninfo->ip_info.domain, 1); + else + unsetenv("CISCO_DEF_DOMAIN"); + + if (vpninfo->ip_info.proxy_pac) + setenv("CISCO_PROXY_PAC", vpninfo->ip_info.proxy_pac, 1); + + if (vpninfo->ip_info.split_dns) { + char *list; + int len = 0; + struct oc_split_include *dns = vpninfo->ip_info.split_dns; + + while (dns) { + len += strlen(dns->route) + 1; + dns = dns->next; + } + list = malloc(len); + if (list) { + char *p = list; + + dns = vpninfo->ip_info.split_dns; + while (1) { + strcpy(p, dns->route); + p += strlen(p); + dns = dns->next; + if (!dns) + break; + *(p++) = ','; + } + setenv("CISCO_SPLIT_DNS", list, 1); + free(list); + } + } + if (vpninfo->ip_info.split_includes) { + struct oc_split_include *this = vpninfo->ip_info.split_includes; + int nr_split_includes = 0; + int nr_v6_split_includes = 0; + + while (this) { + process_split_xxclude(vpninfo, 1, this->route, + &nr_split_includes, + &nr_v6_split_includes); + this = this->next; + } + if (nr_split_includes) + setenv_int("CISCO_SPLIT_INC", nr_split_includes); + if (nr_v6_split_includes) + setenv_int("CISCO_IPV6_SPLIT_INC", nr_v6_split_includes); + } + if (vpninfo->ip_info.split_excludes) { + struct oc_split_include *this = vpninfo->ip_info.split_excludes; + int nr_split_excludes = 0; + int nr_v6_split_excludes = 0; + + while (this) { + process_split_xxclude(vpninfo, 0, this->route, + &nr_split_excludes, + &nr_v6_split_excludes); + this = this->next; + } + if (nr_split_excludes) + setenv_int("CISCO_SPLIT_EXC", nr_split_excludes); + if (nr_v6_split_excludes) + setenv_int("CISCO_IPV6_SPLIT_EXC", nr_v6_split_excludes); + } + setenv_cstp_opts(vpninfo); +} + diff --git a/tun.c b/tun.c index 98e20210..b663874e 100644 --- a/tun.c +++ b/tun.c @@ -91,277 +91,6 @@ static int set_tun_mtu(struct openconnect_info *vpninfo) #endif return 0; } - -static int setenv_int(const char *opt, int value) -{ - char buf[16]; - sprintf(buf, "%d", value); - return setenv(opt, buf, 1); -} - -static int netmasklen(struct in_addr addr) -{ - int masklen; - - for (masklen = 0; masklen < 32; masklen++) { - if (ntohl(addr.s_addr) >= (0xffffffff << masklen)) - break; - } - return 32 - masklen; -} - -static int process_split_xxclude(struct openconnect_info *vpninfo, - int include, const char *route, int *v4_incs, - int *v6_incs) -{ - struct in_addr addr; - const char *in_ex = include ? "IN" : "EX"; - char envname[80]; - char *slash; - - slash = strchr(route, '/'); - if (!slash) { - badinc: - if (include) - vpn_progress(vpninfo, PRG_ERR, - _("Discard bad split include: \"%s\"\n"), - route); - else - vpn_progress(vpninfo, PRG_ERR, - _("Discard bad split exclude: \"%s\"\n"), - route); - return -EINVAL; - } - - *slash = 0; - - if (strchr(route, ':')) { - snprintf(envname, 79, "CISCO_IPV6_SPLIT_%sC_%d_ADDR", in_ex, - *v6_incs); - setenv(envname, route, 1); - - snprintf(envname, 79, "CISCO_IPV6_SPLIT_%sC_%d_MASKLEN", in_ex, - *v6_incs); - setenv(envname, slash+1, 1); - - (*v6_incs)++; - return 0; - } - - if (!inet_aton(route, &addr)) { - *slash = '/'; - goto badinc; - } - - envname[79] = 0; - snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_ADDR", in_ex, *v4_incs); - setenv(envname, route, 1); - - /* Put it back how we found it */ - *slash = '/'; - - if (!inet_aton(slash+1, &addr)) - goto badinc; - - snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_MASK", in_ex, *v4_incs); - setenv(envname, slash+1, 1); - - snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_MASKLEN", in_ex, *v4_incs); - setenv_int(envname, netmasklen(addr)); - - (*v4_incs)++; - return 0; -} - -static int appendenv(const char *opt, const char *new) -{ - char buf[1024]; - char *old = getenv(opt); - - buf[1023] = 0; - if (old) - snprintf(buf, 1023, "%s %s", old, new); - else - snprintf(buf, 1023, "%s", new); - - return setenv(opt, buf, 1); -} - -static void setenv_cstp_opts(struct openconnect_info *vpninfo) -{ - char *env_buf; - int buflen = 0; - int bufofs = 0; - struct oc_vpn_option *opt; - - for (opt = vpninfo->cstp_options; opt; opt = opt->next) - buflen += 2 + strlen(opt->option) + strlen(opt->value); - - env_buf = malloc(buflen + 1); - if (!env_buf) - return; - - env_buf[buflen] = 0; - - for (opt = vpninfo->cstp_options; opt; opt = opt->next) - bufofs += snprintf(env_buf + bufofs, buflen - bufofs, - "%s=%s\n", opt->option, opt->value); - - setenv("CISCO_CSTP_OPTIONS", env_buf, 1); - free(env_buf); -} - -static void set_banner(struct openconnect_info *vpninfo) -{ - char *banner, *q; - const char *p; - - if (!vpninfo->banner || !(banner = malloc(strlen(vpninfo->banner)+1))) { - unsetenv("CISCO_BANNER"); - return; - } - p = vpninfo->banner; - q = banner; - - while (*p) { - if (*p == '%' && isxdigit((int)(unsigned char)p[1]) && - isxdigit((int)(unsigned char)p[2])) { - *(q++) = unhex(p + 1); - p += 3; - } else - *(q++) = *(p++); - } - *q = 0; - setenv("CISCO_BANNER", banner, 1); - - free(banner); -} - -static void set_script_env(struct openconnect_info *vpninfo) -{ - char host[80]; - int ret = getnameinfo(vpninfo->peer_addr, vpninfo->peer_addrlen, host, - sizeof(host), NULL, 0, NI_NUMERICHOST); - if (!ret) - setenv("VPNGATEWAY", host, 1); - - set_banner(vpninfo); - unsetenv("CISCO_SPLIT_INC"); - unsetenv("CISCO_SPLIT_EXC"); - - setenv_int("INTERNAL_IP4_MTU", vpninfo->ip_info.mtu); - - if (vpninfo->ip_info.addr) { - setenv("INTERNAL_IP4_ADDRESS", vpninfo->ip_info.addr, 1); - if (vpninfo->ip_info.netmask) { - struct in_addr addr; - struct in_addr mask; - - if (inet_aton(vpninfo->ip_info.addr, &addr) && - inet_aton(vpninfo->ip_info.netmask, &mask)) { - char *netaddr; - - addr.s_addr &= mask.s_addr; - netaddr = inet_ntoa(addr); - - setenv("INTERNAL_IP4_NETADDR", netaddr, 1); - setenv("INTERNAL_IP4_NETMASK", vpninfo->ip_info.netmask, 1); - setenv_int("INTERNAL_IP4_NETMASKLEN", netmasklen(mask)); - } - } - } - if (vpninfo->ip_info.addr6) { - setenv("INTERNAL_IP6_ADDRESS", vpninfo->ip_info.addr6, 1); - setenv("INTERNAL_IP6_NETMASK", vpninfo->ip_info.netmask6, 1); - } - - if (vpninfo->ip_info.dns[0]) - setenv("INTERNAL_IP4_DNS", vpninfo->ip_info.dns[0], 1); - else - unsetenv("INTERNAL_IP4_DNS"); - if (vpninfo->ip_info.dns[1]) - appendenv("INTERNAL_IP4_DNS", vpninfo->ip_info.dns[1]); - if (vpninfo->ip_info.dns[2]) - appendenv("INTERNAL_IP4_DNS", vpninfo->ip_info.dns[2]); - - if (vpninfo->ip_info.nbns[0]) - setenv("INTERNAL_IP4_NBNS", vpninfo->ip_info.nbns[0], 1); - else - unsetenv("INTERNAL_IP4_NBNS"); - if (vpninfo->ip_info.nbns[1]) - appendenv("INTERNAL_IP4_NBNS", vpninfo->ip_info.nbns[1]); - if (vpninfo->ip_info.nbns[2]) - appendenv("INTERNAL_IP4_NBNS", vpninfo->ip_info.nbns[2]); - - if (vpninfo->ip_info.domain) - setenv("CISCO_DEF_DOMAIN", vpninfo->ip_info.domain, 1); - else - unsetenv("CISCO_DEF_DOMAIN"); - - if (vpninfo->ip_info.proxy_pac) - setenv("CISCO_PROXY_PAC", vpninfo->ip_info.proxy_pac, 1); - - if (vpninfo->ip_info.split_dns) { - char *list; - int len = 0; - struct oc_split_include *dns = vpninfo->ip_info.split_dns; - - while (dns) { - len += strlen(dns->route) + 1; - dns = dns->next; - } - list = malloc(len); - if (list) { - char *p = list; - - dns = vpninfo->ip_info.split_dns; - while (1) { - strcpy(p, dns->route); - p += strlen(p); - dns = dns->next; - if (!dns) - break; - *(p++) = ','; - } - setenv("CISCO_SPLIT_DNS", list, 1); - free(list); - } - } - if (vpninfo->ip_info.split_includes) { - struct oc_split_include *this = vpninfo->ip_info.split_includes; - int nr_split_includes = 0; - int nr_v6_split_includes = 0; - - while (this) { - process_split_xxclude(vpninfo, 1, this->route, - &nr_split_includes, - &nr_v6_split_includes); - this = this->next; - } - if (nr_split_includes) - setenv_int("CISCO_SPLIT_INC", nr_split_includes); - if (nr_v6_split_includes) - setenv_int("CISCO_IPV6_SPLIT_INC", nr_v6_split_includes); - } - if (vpninfo->ip_info.split_excludes) { - struct oc_split_include *this = vpninfo->ip_info.split_excludes; - int nr_split_excludes = 0; - int nr_v6_split_excludes = 0; - - while (this) { - process_split_xxclude(vpninfo, 0, this->route, - &nr_split_excludes, - &nr_v6_split_excludes); - this = this->next; - } - if (nr_split_excludes) - setenv_int("CISCO_SPLIT_EXC", nr_split_excludes); - if (nr_v6_split_excludes) - setenv_int("CISCO_IPV6_SPLIT_EXC", nr_v6_split_excludes); - } - setenv_cstp_opts(vpninfo); -} - int script_config_tun(struct openconnect_info *vpninfo, const char *reason) { int ret;