Commit 7b8fd002 authored by David Woodhouse's avatar David Woodhouse

Fix thread-unsafe setenv() usage

Since moving the tunnel handling into libopenconnect too, we've been
unsafely using setenv() before spawning vpnc-script. We mustn't do that
in a multi-threaded environment.

So store up all the variables in a list, and apply them after fork(). Or
on Windows, build up the environment block to pass to CreateProcess()
manually.
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 9018487a
......@@ -183,43 +183,6 @@ char *openconnect__strndup(const char *s, size_t n)
}
#endif
#ifndef HAVE_SETENV
int openconnect__setenv(const char *name, const char *value, int overwrite)
{
struct oc_text_buf *buf;
if (!value) {
openconnect__unsetenv(name);
return 0;
}
buf = buf_alloc();
buf_append_utf16le(buf, name);
buf_append_utf16le(buf, "=");
buf_append_utf16le(buf, value);
if (buf_error(buf)) {
errno = -buf_free(buf);
return -1;
}
/* Windows putenv() takes a copy of the string */
_wputenv((wchar_t *)buf->data);
buf_free(buf);
return 0;
}
#endif
#ifndef HAVE_UNSETENV
void openconnect__unsetenv(const char *name)
{
char *buf = alloca(strlen(name) + 2);
sprintf(buf, "%s=", name);
putenv(buf);
}
#endif
#ifndef HAVE_INET_ATON
int openconnect__inet_aton(const char *cp, struct in_addr *addr)
{
......
......@@ -177,8 +177,6 @@ fi
AC_CHECK_FUNC(__android_log_vprint, [], AC_CHECK_LIB(log, __android_log_vprint, [], []))
AC_CHECK_FUNCS(setenv unsetenv)
AC_ENABLE_SHARED
AC_DISABLE_STATIC
......
......@@ -178,6 +178,7 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo)
CloseHandle(vpninfo->dtls_event);
#endif
free(vpninfo->peer_addr);
free_optlist(vpninfo->script_env);
free_optlist(vpninfo->cookies);
free_optlist(vpninfo->cstp_options);
free_optlist(vpninfo->dtls_options);
......@@ -657,7 +658,7 @@ int openconnect_setup_tun_device(struct openconnect_info *vpninfo,
STRDUP(vpninfo->vpnc_script, vpnc_script);
STRDUP(vpninfo->ifname, ifname);
set_script_env(vpninfo);
prepare_script_env(vpninfo);
script_config_tun(vpninfo, "pre-init");
tun_fd = os_setup_tun(vpninfo);
......@@ -665,7 +666,7 @@ int openconnect_setup_tun_device(struct openconnect_info *vpninfo,
return tun_fd;
legacy_ifname = openconnect_utf8_to_legacy(vpninfo, vpninfo->ifname);
setenv("TUNDEV", legacy_ifname, 1);
script_setenv(vpninfo, "TUNDEV", legacy_ifname, 0);
if (legacy_ifname != vpninfo->ifname)
free(legacy_ifname);
script_config_tun(vpninfo, "connect");
......
......@@ -289,6 +289,8 @@ struct openconnect_info {
struct oc_vpn_option *cstp_options;
struct oc_vpn_option *dtls_options;
struct oc_vpn_option *script_env;
unsigned pfs;
#if defined(OPENCONNECT_OPENSSL)
X509 *cert_x509;
......@@ -493,14 +495,6 @@ char *openconnect__strcasestr(const char *haystack, const char *needle);
#define strndup openconnect__strndup
char *openconnect__strndup(const char *s, size_t n);
#endif
#ifndef HAVE_SETENV
#define setenv openconnect__setenv
int openconnect__setenv(const char *name, const char *value, int overwrite);
#endif
#ifndef HAVE_UNSETENV
#define unsetenv openconnect__unsetenv
void openconnect__unsetenv(const char *name);
#endif
#ifndef HAVE_INET_ATON
#define inet_aton openconnect__inet_aton
......@@ -568,9 +562,11 @@ char *openconnect_legacy_to_utf8(struct openconnect_info *vpninfo, const char *l
#endif
/* script.c */
int setenv_int(const char *opt, int value);
void set_script_env(struct openconnect_info *vpninfo);
int script_setenv(struct openconnect_info *vpninfo, const char *opt, const char *val, int append);
int script_setenv_int(struct openconnect_info *vpninfo, const char *opt, int value);
void prepare_script_env(struct openconnect_info *vpninfo);
int script_config_tun(struct openconnect_info *vpninfo, const char *reason);
int apply_script_env(struct openconnect_info *vpninfo);
/* tun.c / tun-win32.c */
void os_shutdown_tun(struct openconnect_info *vpninfo);
......
This diff is collapsed.
......@@ -461,7 +461,7 @@ int openconnect_setup_tun_script(struct openconnect_info *vpninfo,
STRDUP(vpninfo->vpnc_script, tun_script);
vpninfo->script_tun = 1;
set_script_env(vpninfo);
prepare_script_env(vpninfo);
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds)) {
vpn_progress(vpninfo, PRG_ERR, _("socketpair failed: %s\n"), strerror(errno));
return -EIO;
......@@ -474,7 +474,8 @@ int openconnect_setup_tun_script(struct openconnect_info *vpninfo,
if (setpgid(0, getpid()) < 0)
vpn_perror(vpninfo, _("setpgid"));
close(fds[0]);
setenv_int("VPNFD", fds[1]);
script_setenv_int(vpninfo, "VPNFD", fds[1]);
apply_script_env(vpninfo);
execl("/bin/sh", "/bin/sh", "-c", vpninfo->vpnc_script, NULL);
vpn_perror(vpninfo, _("execl"));
exit(1);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment