mirror of
https://github.com/OpenVPN/openvpn.git
synced 2025-05-08 21:25:53 +08:00
Completely revamped the system for calling external programs and scripts:
* All external programs and scripts are now called by execve() on unix and CreateProcess on Windows. * The system() function is no longer used. * Argument lists for external programs and scripts are now built by the new argv_printf function which natively outputs to string arrays (i.e. char *argv[] lists), never truncates its output, and eliminates the security issues inherent in formatting and parsing command lines, and dealing with argument quoting. * The --script-security directive has been added to offer policy controls on OpenVPN's execution of external programs and scripts. Also added a new plugin example (openvpn/plugin/examples/log.c) that logs information to stdout for every plugin method called by OpenVPN. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@3122 e7ae566f-a301-0410-adde-c780ea21d3b5
This commit is contained in:
parent
26bb4c740b
commit
5a2e9a2587
132
buffer.c
132
buffer.c
@ -240,6 +240,14 @@ argv_init (struct argv *a)
|
||||
a->argv = NULL;
|
||||
}
|
||||
|
||||
struct argv
|
||||
argv_new (void)
|
||||
{
|
||||
struct argv ret;
|
||||
argv_init (&ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
argv_reset (struct argv *a)
|
||||
{
|
||||
@ -266,6 +274,23 @@ argv_argc (const char *format)
|
||||
return argc;
|
||||
}
|
||||
|
||||
struct argv
|
||||
argv_insert_head (const struct argv *a, const char *head)
|
||||
{
|
||||
struct argv r;
|
||||
size_t i;
|
||||
|
||||
r.argc = (a ? a->argc : 0) + 1;
|
||||
ALLOC_ARRAY_CLEAR (r.argv, char *, r.argc + 1);
|
||||
r.argv[0] = string_alloc (head, NULL);
|
||||
if (a)
|
||||
{
|
||||
for (i = 0; i < a->argc; ++i)
|
||||
r.argv[i+1] = string_alloc (a->argv[i], NULL);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
char *
|
||||
argv_term (const char **f)
|
||||
{
|
||||
@ -323,6 +348,22 @@ argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
|
||||
return "";
|
||||
}
|
||||
|
||||
void
|
||||
argv_msg (const int msglev, const struct argv *a)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
msg (msglev, "%s", argv_str (a, &gc, 0));
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
void
|
||||
argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0));
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
void
|
||||
argv_printf (struct argv *a, const char *format, ...)
|
||||
{
|
||||
@ -373,7 +414,10 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag
|
||||
{
|
||||
if (!strcmp (term, "%s"))
|
||||
{
|
||||
a->argv[argc++] = string_alloc (va_arg (arglist, char *), NULL);
|
||||
char *s = va_arg (arglist, char *);
|
||||
if (!s)
|
||||
s = "";
|
||||
a->argv[argc++] = string_alloc (s, NULL);
|
||||
}
|
||||
else if (!strcmp (term, "%d"))
|
||||
{
|
||||
@ -387,6 +431,41 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag
|
||||
openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int));
|
||||
a->argv[argc++] = string_alloc (numstr, NULL);
|
||||
}
|
||||
else if (!strcmp (term, "%s/%d"))
|
||||
{
|
||||
char numstr[64];
|
||||
char *s = va_arg (arglist, char *);
|
||||
|
||||
if (!s)
|
||||
s = "";
|
||||
|
||||
openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
|
||||
|
||||
{
|
||||
const size_t len = strlen(s) + strlen(numstr) + 2;
|
||||
char *combined = (char *) malloc (len);
|
||||
check_malloc_return (combined);
|
||||
|
||||
strcpy (combined, s);
|
||||
strcat (combined, "/");
|
||||
strcat (combined, numstr);
|
||||
a->argv[argc++] = combined;
|
||||
}
|
||||
}
|
||||
else if (!strcmp (term, "%s%s"))
|
||||
{
|
||||
char *s1 = va_arg (arglist, char *);
|
||||
char *s2 = va_arg (arglist, char *);
|
||||
char *combined;
|
||||
|
||||
if (!s1) s1 = "";
|
||||
if (!s2) s2 = "";
|
||||
combined = (char *) malloc (strlen(s1) + strlen(s2) + 1);
|
||||
check_malloc_return (combined);
|
||||
strcpy (combined, s1);
|
||||
strcat (combined, s2);
|
||||
a->argv[argc++] = combined;
|
||||
}
|
||||
else
|
||||
ASSERT (0);
|
||||
free (term);
|
||||
@ -399,57 +478,6 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag
|
||||
ASSERT (argc == a->argc);
|
||||
}
|
||||
|
||||
#ifdef ARGV_TEST
|
||||
void
|
||||
argv_test (void)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
char line[512];
|
||||
const char *s;
|
||||
|
||||
struct argv a;
|
||||
argv_init (&a);
|
||||
argv_printf (&a, "this is a %s test of int %d unsigned %u", "FOO", -69, 42);
|
||||
s = argv_str (&a, &gc, PA_BRACKET);
|
||||
argv_reset (&a);
|
||||
printf ("%s\n", s);
|
||||
|
||||
argv_init (&a);
|
||||
argv_printf (&a, "foo bar %d", 99);
|
||||
s = argv_str (&a, &gc, PA_BRACKET);
|
||||
argv_reset (&a);
|
||||
printf ("%s\n", s);
|
||||
|
||||
argv_init (&a);
|
||||
s = argv_str (&a, &gc, PA_BRACKET);
|
||||
argv_reset (&a);
|
||||
printf ("%s\n", s);
|
||||
|
||||
argv_init (&a);
|
||||
argv_printf (&a, "foo bar %d", 99);
|
||||
argv_printf_cat (&a, "bar %d foo", 42);
|
||||
argv_printf_cat (&a, "cool %s %d u", "frood", 4);
|
||||
s = argv_str (&a, &gc, PA_BRACKET);
|
||||
argv_reset (&a);
|
||||
printf ("%s\n", s);
|
||||
|
||||
while (fgets (line, sizeof(line), stdin) != NULL)
|
||||
{
|
||||
char *term;
|
||||
const char *f = line;
|
||||
int i = 0;
|
||||
|
||||
while ((term = argv_term (&f)) != NULL)
|
||||
{
|
||||
printf ("[%d] '%s'\n", i, term);
|
||||
++i;
|
||||
free (term);
|
||||
}
|
||||
}
|
||||
gc_free (&gc);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* write a string to the end of a buffer that was
|
||||
* truncated by buf_printf
|
||||
|
4
buffer.h
4
buffer.h
@ -234,10 +234,14 @@ int openvpn_snprintf(char *str, size_t size, const char *format, ...)
|
||||
* to execve.
|
||||
*/
|
||||
void argv_init (struct argv *a);
|
||||
struct argv argv_new (void);
|
||||
void argv_reset (struct argv *a);
|
||||
size_t argv_argc (const char *format);
|
||||
char *argv_term (const char **f);
|
||||
const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags);
|
||||
struct argv argv_insert_head (const struct argv *a, const char *head);
|
||||
void argv_msg (const int msglev, const struct argv *a);
|
||||
void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix);
|
||||
|
||||
#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */
|
||||
void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist);
|
||||
|
@ -462,7 +462,8 @@ AC_CHECK_FUNCS(daemon chroot getpwnam setuid nice system getpid dup dup2 dnl
|
||||
getpass strerror syslog openlog mlockall getgrnam setgid dnl
|
||||
setgroups stat flock readv writev setsockopt getsockopt dnl
|
||||
setsid chdir putenv getpeername unlink dnl
|
||||
poll chsize ftruncate sendmsg recvmsg getsockname)
|
||||
poll chsize ftruncate sendmsg recvmsg getsockname dnl
|
||||
execve)
|
||||
AC_CACHE_SAVE
|
||||
|
||||
if test "${WIN32}" = "yes"; then
|
||||
|
@ -392,6 +392,24 @@
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/libdl-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libdl-2.5.so
|
||||
fun:dlsym
|
||||
fun:libdl_resolve_symbol
|
||||
fun:plugin_list_init
|
||||
fun:init_plugins
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
|
7
init.c
7
init.c
@ -370,7 +370,7 @@ init_port_share (struct context *c)
|
||||
bool
|
||||
init_static (void)
|
||||
{
|
||||
configure_path ();
|
||||
/* configure_path (); */
|
||||
|
||||
#if defined(USE_CRYPTO) && defined(DMALLOC)
|
||||
openssl_dmalloc_init ();
|
||||
@ -921,8 +921,11 @@ do_route (const struct options *options,
|
||||
|
||||
if (options->route_script)
|
||||
{
|
||||
struct argv argv = argv_new ();
|
||||
setenv_str (es, "script_type", "route-up");
|
||||
system_check (options->route_script, es, S_SCRIPT, "Route script failed");
|
||||
argv_printf (&argv, "%s", options->route_script);
|
||||
openvpn_execve_check (&argv, es, S_SCRIPT, "Route script failed");
|
||||
argv_reset (&argv);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
34
lladdr.c
34
lladdr.c
@ -9,7 +9,7 @@
|
||||
int set_lladdr(const char *ifname, const char *lladdr,
|
||||
const struct env_set *es)
|
||||
{
|
||||
char cmd[256];
|
||||
struct argv argv = argv_new ();
|
||||
int r;
|
||||
|
||||
if (!ifname || !lladdr)
|
||||
@ -17,37 +17,45 @@ int set_lladdr(const char *ifname, const char *lladdr,
|
||||
|
||||
#if defined(TARGET_LINUX)
|
||||
#ifdef CONFIG_FEATURE_IPROUTE
|
||||
openvpn_snprintf (cmd, sizeof (cmd),
|
||||
argv_printf (&argv,
|
||||
"%s link set addr %s dev %s",
|
||||
iproute_path, lladdr, ifname);
|
||||
#else
|
||||
openvpn_snprintf (cmd, sizeof (cmd),
|
||||
IFCONFIG_PATH " %s hw ether %s",
|
||||
argv_printf (&argv,
|
||||
"%s %s hw ether %s",
|
||||
IFCONFIG_PATH,
|
||||
ifname, lladdr);
|
||||
#endif
|
||||
#elif defined(TARGET_SOLARIS)
|
||||
openvpn_snprintf (cmd, sizeof (cmd),
|
||||
IFCONFIG_PATH " %s ether %s",
|
||||
argv_printf (&argv,
|
||||
"%s %s ether %s",
|
||||
IFCONFIG_PATH,
|
||||
ifname, lladdr);
|
||||
#elif defined(TARGET_OPENBSD)
|
||||
openvpn_snprintf (cmd, sizeof (cmd),
|
||||
IFCONFIG_PATH " %s lladdr %s",
|
||||
argv_printf (&argv,
|
||||
"%s %s lladdr %s",
|
||||
IFCONFIG_PATH,
|
||||
ifname, lladdr);
|
||||
#elif defined(TARGET_DARWIN)
|
||||
openvpn_snprintf (cmd, sizeof (cmd),
|
||||
IFCONFIG_PATH " %s lladdr %s",
|
||||
argv_printf (&argv,
|
||||
"%s %s lladdr %s",
|
||||
IFCONFIG_PATH,
|
||||
ifname, lladdr);
|
||||
#elif defined(TARGET_FREEBSD)
|
||||
openvpn_snprintf (cmd, sizeof (cmd),
|
||||
IFCONFIG_PATH " %s ether %s",
|
||||
argv_printf (&argv,
|
||||
"%s %s ether %s",
|
||||
IFCONFIG_PATH,
|
||||
ifname, lladdr);
|
||||
#else
|
||||
msg (M_WARN, "Sorry, but I don't know how to configure link layer addresses on this operating system.");
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
r = system_check (cmd, es, M_WARN, "ERROR: Unable to set link layer address.");
|
||||
argv_msg (M_INFO, &argv);
|
||||
r = openvpn_execve_check (&argv, es, M_WARN, "ERROR: Unable to set link layer address.");
|
||||
if (r)
|
||||
msg (M_INFO, "TUN/TAP link layer address set to %s", lladdr);
|
||||
|
||||
argv_reset (&argv);
|
||||
return r;
|
||||
}
|
||||
|
273
misc.c
273
misc.c
@ -43,6 +43,9 @@
|
||||
const char *iproute_path = IPROUTE_PATH;
|
||||
#endif
|
||||
|
||||
/* contains an SSEC_x value defined in misc.h */
|
||||
int script_security = SSEC_BUILT_IN; /* GLOBAL */
|
||||
|
||||
/* Redefine the top level directory of the filesystem
|
||||
to restrict access to files for security */
|
||||
void
|
||||
@ -196,38 +199,36 @@ run_up_down (const char *command,
|
||||
|
||||
if (plugin_defined (plugins, plugin_type))
|
||||
{
|
||||
struct buffer cmd = alloc_buf_gc (256, &gc);
|
||||
|
||||
struct argv argv = argv_new ();
|
||||
ASSERT (arg);
|
||||
argv_printf (&argv,
|
||||
"%s %d %d %s %s %s",
|
||||
arg,
|
||||
tun_mtu, link_mtu,
|
||||
ifconfig_local, ifconfig_remote,
|
||||
context);
|
||||
|
||||
buf_printf (&cmd,
|
||||
"\"%s\" %d %d %s %s %s",
|
||||
arg,
|
||||
tun_mtu, link_mtu,
|
||||
ifconfig_local, ifconfig_remote,
|
||||
context);
|
||||
|
||||
if (plugin_call (plugins, plugin_type, BSTR (&cmd), NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
if (plugin_call (plugins, plugin_type, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
msg (M_FATAL, "ERROR: up/down plugin call failed");
|
||||
|
||||
argv_reset (&argv);
|
||||
}
|
||||
|
||||
if (command)
|
||||
{
|
||||
struct buffer cmd = alloc_buf_gc (256, &gc);
|
||||
|
||||
struct argv argv = argv_new ();
|
||||
ASSERT (arg);
|
||||
|
||||
setenv_str (es, "script_type", script_type);
|
||||
|
||||
buf_printf (&cmd,
|
||||
"%s \"%s\" %d %d %s %s %s",
|
||||
argv_printf (&argv,
|
||||
"%s %s %d %d %s %s %s",
|
||||
command,
|
||||
arg,
|
||||
tun_mtu, link_mtu,
|
||||
ifconfig_local, ifconfig_remote,
|
||||
context);
|
||||
msg (M_INFO, "%s", BSTR (&cmd));
|
||||
system_check (BSTR (&cmd), es, S_SCRIPT|S_FATAL, "script failed");
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_SCRIPT|S_FATAL, "script failed");
|
||||
argv_reset (&argv);
|
||||
}
|
||||
|
||||
gc_free (&gc);
|
||||
@ -374,59 +375,6 @@ save_inetd_socket_descriptor (void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper around the system() call.
|
||||
*/
|
||||
int
|
||||
openvpn_system (const char *command, const struct env_set *es, unsigned int flags)
|
||||
{
|
||||
#ifdef HAVE_SYSTEM
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We need to bracket this code by mutex because system() doesn't
|
||||
* accept an environment list, so we have to use the process-wide
|
||||
* list which is shared between all threads.
|
||||
*/
|
||||
mutex_lock_static (L_SYSTEM);
|
||||
perf_push (PERF_SCRIPT);
|
||||
|
||||
/*
|
||||
* add env_set to environment.
|
||||
*/
|
||||
if (flags & S_SCRIPT)
|
||||
env_set_add_to_environment (es);
|
||||
|
||||
|
||||
/* debugging */
|
||||
dmsg (D_SCRIPT, "SYSTEM[%u] '%s'", flags, command);
|
||||
if (flags & S_SCRIPT)
|
||||
env_set_print (D_SCRIPT, es);
|
||||
|
||||
/*
|
||||
* execute the command
|
||||
*/
|
||||
ret = system (command);
|
||||
|
||||
/* debugging */
|
||||
dmsg (D_SCRIPT, "SYSTEM return=%u", ret);
|
||||
|
||||
/*
|
||||
* remove env_set from environment
|
||||
*/
|
||||
if (flags & S_SCRIPT)
|
||||
env_set_remove_from_environment (es);
|
||||
|
||||
perf_pop ();
|
||||
mutex_unlock_static (L_SYSTEM);
|
||||
return ret;
|
||||
|
||||
#else
|
||||
msg (M_FATAL, "Sorry but I can't execute the shell command '%s' because this operating system doesn't appear to support the system() call", command);
|
||||
return -1; /* NOTREACHED */
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Warn if a given file is group/others accessible.
|
||||
*/
|
||||
@ -489,35 +437,35 @@ system_error_message (int stat, struct gc_arena *gc)
|
||||
struct buffer out = alloc_buf_gc (256, gc);
|
||||
#ifdef WIN32
|
||||
if (stat == -1)
|
||||
buf_printf (&out, "shell command did not execute -- ");
|
||||
buf_printf (&out, "system() returned error code %d", stat);
|
||||
buf_printf (&out, "external program did not execute -- ");
|
||||
buf_printf (&out, "returned error code %d", stat);
|
||||
#else
|
||||
if (stat == -1)
|
||||
buf_printf (&out, "shell command fork failed");
|
||||
buf_printf (&out, "external program fork failed");
|
||||
else if (!WIFEXITED (stat))
|
||||
buf_printf (&out, "shell command did not exit normally");
|
||||
buf_printf (&out, "external program did not exit normally");
|
||||
else
|
||||
{
|
||||
const int cmd_ret = WEXITSTATUS (stat);
|
||||
if (!cmd_ret)
|
||||
buf_printf (&out, "shell command exited normally");
|
||||
buf_printf (&out, "external program exited normally");
|
||||
else if (cmd_ret == 127)
|
||||
buf_printf (&out, "could not execute shell command");
|
||||
buf_printf (&out, "could not execute external program");
|
||||
else
|
||||
buf_printf (&out, "shell command exited with error status: %d", cmd_ret);
|
||||
buf_printf (&out, "external program exited with error status: %d", cmd_ret);
|
||||
}
|
||||
#endif
|
||||
return (const char *)out.data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run system(), exiting on error.
|
||||
* Wrapper around openvpn_execve
|
||||
*/
|
||||
bool
|
||||
system_check (const char *command, const struct env_set *es, unsigned int flags, const char *error_message)
|
||||
openvpn_execve_check (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
const int stat = openvpn_system (command, es, flags);
|
||||
const int stat = openvpn_execve (a, es, flags);
|
||||
int ret = false;
|
||||
|
||||
if (system_ok (stat))
|
||||
@ -533,6 +481,69 @@ system_check (const char *command, const struct env_set *es, unsigned int flags,
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
openvpn_execve_allowed (const unsigned int flags)
|
||||
{
|
||||
if (flags & S_SCRIPT)
|
||||
return script_security >= SSEC_SCRIPTS;
|
||||
else
|
||||
return script_security >= SSEC_BUILT_IN;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
/*
|
||||
* Run execve() inside a fork(). Designed to replicate the semantics of system() but
|
||||
* in a safer way that doesn't require the invocation of a shell or the risks
|
||||
* assocated with formatting and parsing a command line.
|
||||
*/
|
||||
int
|
||||
openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
int ret = -1;
|
||||
|
||||
if (a && a->argv[0])
|
||||
{
|
||||
#if defined(ENABLE_EXECVE)
|
||||
if (openvpn_execve_allowed (flags))
|
||||
{
|
||||
const char *cmd = a->argv[0];
|
||||
char *const *argv = a->argv;
|
||||
char *const *envp = (char *const *)make_env_array (es, true, &gc);
|
||||
pid_t pid;
|
||||
|
||||
pid = fork ();
|
||||
if (pid == (pid_t)0) /* child side */
|
||||
{
|
||||
execve (cmd, argv, envp);
|
||||
exit (127);
|
||||
}
|
||||
else if (pid < (pid_t)0) /* fork failed */
|
||||
;
|
||||
else /* parent side */
|
||||
{
|
||||
if (waitpid (pid, &ret, 0) != pid)
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_WARN, "openvpn_execve: external program may not be called due to setting of --script-security level");
|
||||
}
|
||||
#else
|
||||
msg (M_WARN, "openvpn_execve: execve function not available");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_WARN, "openvpn_execve: called with empty argv");
|
||||
}
|
||||
|
||||
gc_free (&gc);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize random number seed. random() is only used
|
||||
* when "weak" random numbers are acceptable.
|
||||
@ -1479,11 +1490,23 @@ safe_print (const char *str, struct gc_arena *gc)
|
||||
return string_mod_const (str, CC_PRINT, CC_CRLF, '.', gc);
|
||||
}
|
||||
|
||||
static bool
|
||||
is_password_env_var (const char *str)
|
||||
{
|
||||
return (strncmp (str, "password", 8) == 0);
|
||||
}
|
||||
|
||||
bool
|
||||
env_allowed (const char *str)
|
||||
{
|
||||
return (script_security >= SSEC_PW_ENV || !is_password_env_var (str));
|
||||
}
|
||||
|
||||
bool
|
||||
env_safe_to_print (const char *str)
|
||||
{
|
||||
#ifndef UNSAFE_DEBUG
|
||||
if (strncmp (str, "password", 8) == 0)
|
||||
if (is_password_env_var (str))
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
@ -1492,7 +1515,9 @@ env_safe_to_print (const char *str)
|
||||
/* Make arrays of strings */
|
||||
|
||||
const char **
|
||||
make_env_array (const struct env_set *es, struct gc_arena *gc)
|
||||
make_env_array (const struct env_set *es,
|
||||
const bool check_allowed,
|
||||
struct gc_arena *gc)
|
||||
{
|
||||
char **ret = NULL;
|
||||
struct env_item *e = NULL;
|
||||
@ -1511,12 +1536,14 @@ make_env_array (const struct env_set *es, struct gc_arena *gc)
|
||||
/* fill return array */
|
||||
if (es)
|
||||
{
|
||||
e = es->list;
|
||||
for (i = 0; i < n; ++i)
|
||||
i = 0;
|
||||
for (e = es->list; e != NULL; e = e->next)
|
||||
{
|
||||
ASSERT (e);
|
||||
ret[i] = e->string;
|
||||
e = e->next;
|
||||
if (!check_allowed || env_allowed (e->string))
|
||||
{
|
||||
ASSERT (i < n);
|
||||
ret[i++] = e->string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1631,6 +1658,7 @@ openvpn_sleep (const int n)
|
||||
sleep (n);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Configure PATH. On Windows, sometimes PATH is not set correctly
|
||||
* by default.
|
||||
@ -1672,3 +1700,72 @@ configure_path (void)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ARGV_TEST
|
||||
void
|
||||
argv_test (void)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
char line[512];
|
||||
const char *s;
|
||||
|
||||
struct argv a;
|
||||
argv_init (&a);
|
||||
|
||||
#ifdef WIN32
|
||||
argv_printf (&a, "%s foo bar %s", "c:\\src\\test\\jyargs.exe", "foo bar");
|
||||
//argv_printf (&a, "%s %s %s", "c:\\src\\test files\\batargs.bat", "foo", "bar");
|
||||
#else
|
||||
argv_printf (&a, "./myechox foo bar");
|
||||
#endif
|
||||
|
||||
argv_msg_prefix (M_INFO, &a, "ARGV");
|
||||
openvpn_execve_check (&a, NULL, 0, "command failed");
|
||||
|
||||
argv_printf (&a, "this is a %s test of int %d unsigned %u", "FOO", -69, 42);
|
||||
s = argv_str (&a, &gc, PA_BRACKET);
|
||||
printf ("%s\n", s);
|
||||
|
||||
{
|
||||
struct argv b = argv_insert_head (&a, "MARK");
|
||||
s = argv_str (&b, &gc, PA_BRACKET);
|
||||
argv_reset (&b);
|
||||
printf ("%s\n", s);
|
||||
}
|
||||
|
||||
argv_printf (&a, "foo bar %d", 99);
|
||||
s = argv_str (&a, &gc, PA_BRACKET);
|
||||
argv_reset (&a);
|
||||
printf ("%s\n", s);
|
||||
|
||||
s = argv_str (&a, &gc, PA_BRACKET);
|
||||
argv_reset (&a);
|
||||
printf ("%s\n", s);
|
||||
|
||||
argv_printf (&a, "foo bar %d", 99);
|
||||
argv_printf_cat (&a, "bar %d foo", 42);
|
||||
argv_printf_cat (&a, "cool %s %d u %s/%d end", "frood", 4, "hello", 7);
|
||||
s = argv_str (&a, &gc, PA_BRACKET);
|
||||
printf ("%s\n", s);
|
||||
|
||||
#if 0
|
||||
while (fgets (line, sizeof(line), stdin) != NULL)
|
||||
{
|
||||
char *term;
|
||||
const char *f = line;
|
||||
int i = 0;
|
||||
|
||||
while ((term = argv_term (&f)) != NULL)
|
||||
{
|
||||
printf ("[%d] '%s'\n", i, term);
|
||||
++i;
|
||||
free (term);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
argv_reset (&a);
|
||||
gc_free (&gc);
|
||||
}
|
||||
#endif
|
||||
|
26
misc.h
26
misc.h
@ -117,17 +117,15 @@ void warn_if_group_others_accessible(const char* filename);
|
||||
#define S_SCRIPT (1<<0)
|
||||
#define S_FATAL (1<<1)
|
||||
|
||||
/* wrapper around the system() call. */
|
||||
int openvpn_system (const char *command, const struct env_set *es, unsigned int flags);
|
||||
|
||||
/* interpret the status code returned by system() */
|
||||
/* interpret the status code returned by system()/execve() */
|
||||
bool system_ok(int);
|
||||
int system_executed (int stat);
|
||||
const char *system_error_message (int, struct gc_arena *gc);
|
||||
|
||||
/* run system() with error check, return true if success,
|
||||
false if error, exit if error and fatal==true */
|
||||
bool system_check (const char *command, const struct env_set *es, unsigned int flags, const char *error_message);
|
||||
/* wrapper around the execve() call */
|
||||
int openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags);
|
||||
bool openvpn_execve_check (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message);
|
||||
bool openvpn_execve_allowed (const unsigned int flags);
|
||||
|
||||
#ifdef HAVE_STRERROR
|
||||
/* a thread-safe version of strerror */
|
||||
@ -184,7 +182,10 @@ void env_set_remove_from_environment (const struct env_set *es);
|
||||
|
||||
/* Make arrays of strings */
|
||||
|
||||
const char **make_env_array (const struct env_set *es, struct gc_arena *gc);
|
||||
const char **make_env_array (const struct env_set *es,
|
||||
const bool check_allowed,
|
||||
struct gc_arena *gc);
|
||||
|
||||
const char **make_arg_array (const char *first, const char *parms, struct gc_arena *gc);
|
||||
const char **make_extended_arg_array (char **p, struct gc_arena *gc);
|
||||
|
||||
@ -271,6 +272,9 @@ const char *safe_print (const char *str, struct gc_arena *gc);
|
||||
/* returns true if environmental variable safe to print to log */
|
||||
bool env_safe_to_print (const char *str);
|
||||
|
||||
/* returns true if environmental variable may be passed to an external program */
|
||||
bool env_allowed (const char *str);
|
||||
|
||||
/*
|
||||
* A sleep function that services the management layer for n
|
||||
* seconds rather than doing nothing.
|
||||
@ -290,4 +294,10 @@ void get_user_pass_auto_userid (struct user_pass *up, const char *tag);
|
||||
extern const char *iproute_path;
|
||||
#endif
|
||||
|
||||
#define SSEC_NONE 0 /* strictly no calling of external programs */
|
||||
#define SSEC_BUILT_IN 1 /* only call built-in programs such as ifconfig, route, netsh, etc.*/
|
||||
#define SSEC_SCRIPTS 2 /* allow calling of built-in programs and user-defined scripts */
|
||||
#define SSEC_PW_ENV 3 /* allow calling of built-in programs and user-defined scripts that may receive a password as an environmental variable */
|
||||
extern int script_security; /* GLOBAL */
|
||||
|
||||
#endif
|
||||
|
65
multi.c
65
multi.c
@ -85,36 +85,33 @@ learn_address_script (const struct multi_context *m,
|
||||
|
||||
if (plugin_defined (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS))
|
||||
{
|
||||
struct buffer cmd = alloc_buf_gc (256, &gc);
|
||||
|
||||
buf_printf (&cmd, "\"%s\" \"%s\"",
|
||||
op,
|
||||
mroute_addr_print (addr, &gc));
|
||||
struct argv argv = argv_new ();
|
||||
argv_printf (&argv, "%s %s",
|
||||
op,
|
||||
mroute_addr_print (addr, &gc));
|
||||
if (mi)
|
||||
buf_printf (&cmd, " \"%s\"", tls_common_name (mi->context.c2.tls_multi, false));
|
||||
|
||||
if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, BSTR (&cmd), NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false));
|
||||
if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
{
|
||||
msg (M_WARN, "WARNING: learn-address plugin call failed");
|
||||
ret = false;
|
||||
}
|
||||
argv_reset (&argv);
|
||||
}
|
||||
|
||||
if (m->top.options.learn_address_script)
|
||||
{
|
||||
struct buffer cmd = alloc_buf_gc (256, &gc);
|
||||
|
||||
struct argv argv = argv_new ();
|
||||
setenv_str (es, "script_type", "learn-address");
|
||||
|
||||
buf_printf (&cmd, "%s \"%s\" \"%s\"",
|
||||
m->top.options.learn_address_script,
|
||||
op,
|
||||
mroute_addr_print (addr, &gc));
|
||||
argv_printf (&argv, "%s %s %s",
|
||||
m->top.options.learn_address_script,
|
||||
op,
|
||||
mroute_addr_print (addr, &gc));
|
||||
if (mi)
|
||||
buf_printf (&cmd, " \"%s\"", tls_common_name (mi->context.c2.tls_multi, false));
|
||||
|
||||
if (!system_check (BSTR (&cmd), es, S_SCRIPT, "WARNING: learn-address command failed"))
|
||||
argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false));
|
||||
if (!openvpn_execve_check (&argv, es, S_SCRIPT, "WARNING: learn-address command failed"))
|
||||
ret = false;
|
||||
argv_reset (&argv);
|
||||
}
|
||||
|
||||
gc_free (&gc);
|
||||
@ -474,16 +471,11 @@ multi_client_disconnect_script (struct multi_context *m,
|
||||
|
||||
if (mi->context.options.client_disconnect_script)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
struct buffer cmd = alloc_buf_gc (256, &gc);
|
||||
|
||||
struct argv argv = argv_new ();
|
||||
setenv_str (mi->context.c2.es, "script_type", "client-disconnect");
|
||||
|
||||
buf_printf (&cmd, "%s", mi->context.options.client_disconnect_script);
|
||||
|
||||
system_check (BSTR (&cmd), mi->context.c2.es, S_SCRIPT, "client-disconnect command failed");
|
||||
|
||||
gc_free (&gc);
|
||||
argv_printf (&argv, "%s", mi->context.options.client_disconnect_script);
|
||||
openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-disconnect command failed");
|
||||
argv_reset (&argv);
|
||||
}
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
if (management)
|
||||
@ -1523,11 +1515,11 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
|
||||
/* deprecated callback, use a file for passing back return info */
|
||||
if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT))
|
||||
{
|
||||
struct argv argv = argv_new ();
|
||||
const char *dc_file = create_temp_filename (mi->context.options.tmp_dir, "cc", &gc);
|
||||
|
||||
argv_printf (&argv, "%s", dc_file);
|
||||
delete_file (dc_file);
|
||||
|
||||
if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, dc_file, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, &argv, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
{
|
||||
msg (M_WARN, "WARNING: client-connect plugin call failed");
|
||||
cc_succeeded = false;
|
||||
@ -1537,6 +1529,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
|
||||
multi_client_connect_post (m, mi, dc_file, option_permissions_mask, &option_types_found);
|
||||
++cc_succeeded_count;
|
||||
}
|
||||
argv_reset (&argv);
|
||||
}
|
||||
|
||||
/* V2 callback, use a plugin_return struct for passing back return info */
|
||||
@ -1566,7 +1559,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
|
||||
*/
|
||||
if (mi->context.options.client_connect_script && cc_succeeded)
|
||||
{
|
||||
struct buffer cmd = alloc_buf_gc (256, &gc);
|
||||
struct argv argv = argv_new ();
|
||||
const char *dc_file = NULL;
|
||||
|
||||
setenv_str (mi->context.c2.es, "script_type", "client-connect");
|
||||
@ -1575,17 +1568,19 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
|
||||
|
||||
delete_file (dc_file);
|
||||
|
||||
buf_printf (&cmd, "%s %s",
|
||||
mi->context.options.client_connect_script,
|
||||
dc_file);
|
||||
argv_printf (&argv, "%s %s",
|
||||
mi->context.options.client_connect_script,
|
||||
dc_file);
|
||||
|
||||
if (system_check (BSTR (&cmd), mi->context.c2.es, S_SCRIPT, "client-connect command failed"))
|
||||
if (openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-connect command failed"))
|
||||
{
|
||||
multi_client_connect_post (m, mi, dc_file, option_permissions_mask, &option_types_found);
|
||||
++cc_succeeded_count;
|
||||
}
|
||||
else
|
||||
cc_succeeded = false;
|
||||
|
||||
argv_reset (&argv);
|
||||
}
|
||||
|
||||
/*
|
||||
|
36
openvpn.8
36
openvpn.8
@ -252,6 +252,7 @@ openvpn \- secure IP tunnel daemon.
|
||||
[\ \fB\-\-route\-up\fR\ \fIcmd\fR\ ]
|
||||
[\ \fB\-\-route\fR\ \fInetwork\ [netmask]\ [gateway]\ [metric]\fR\ ]
|
||||
[\ \fB\-\-rport\fR\ \fIport\fR\ ]
|
||||
[\ \fB\-\-script\-security\fR\ \fIlevel\fR\ ]
|
||||
[\ \fB\-\-secret\fR\ \fIfile\ [direction]\fR\ ]
|
||||
[\ \fB\-\-secret\fR\ \fIfile\fR\ ]
|
||||
[\ \fB\-\-server\-bridge\fR\ \fIgateway\ netmask\ pool\-start\-IP\ pool\-end\-IP\fR\ ]
|
||||
@ -300,6 +301,7 @@ openvpn \- secure IP tunnel daemon.
|
||||
[\ \fB\-\-user\fR\ \fIuser\fR\ ]
|
||||
[\ \fB\-\-username\-as\-common\-name\fR\ ]
|
||||
[\ \fB\-\-verb\fR\ \fIn\fR\ ]
|
||||
[\ \fB\-\-win\-sys\fR\ \fIpath|'env'\fR\ ]
|
||||
[\ \fB\-\-writepid\fR\ \fIfile\fR\ ]
|
||||
.in -4
|
||||
.ti +4
|
||||
@ -1998,6 +2000,24 @@ is a safety precaution to prevent a LD_PRELOAD style attack
|
||||
from a malicious or compromised server.
|
||||
.\"*********************************************************
|
||||
.TP
|
||||
.B --script-security level
|
||||
This directive offers policy-level control over OpenVPN's usage of external programs
|
||||
and scripts. Lower values are more restrictive, higher values are more permissive. Settings for
|
||||
.B level:
|
||||
|
||||
.B 0 --
|
||||
Strictly no calling of external programs.
|
||||
.br
|
||||
.B 1 --
|
||||
(Default) Only call built-in executables such as ifconfig, ip, route, or netsh.
|
||||
.br
|
||||
.B 2 --
|
||||
Allow calling of built-in executables and user-defined scripts.
|
||||
.br
|
||||
.B 3 --
|
||||
Allow passwords to be passed to scripts via environmental variables (potentially unsafe).
|
||||
.\"*********************************************************
|
||||
.TP
|
||||
.B --disable-occ
|
||||
Don't output a warning message if option inconsistencies are detected between
|
||||
peers. An example of an option inconsistency would be where one peer uses
|
||||
@ -4481,6 +4501,22 @@ Optional group to be owner of this tunnel.
|
||||
.SS Windows-Specific Options:
|
||||
.\"*********************************************************
|
||||
.TP
|
||||
.B --win-sys path|'env'
|
||||
Set the Windows system directory pathname to use when looking for system
|
||||
executables such as
|
||||
.B route.exe
|
||||
and
|
||||
.B netsh.exe.
|
||||
By default, if this directive is
|
||||
not specified, the pathname will be set to "C:\\WINDOWS"
|
||||
|
||||
The special string
|
||||
.B 'env'
|
||||
indicates that the pathname should be read from the
|
||||
.B SystemRoot
|
||||
environmental variable.
|
||||
.\"*********************************************************
|
||||
.TP
|
||||
.B --ip-win32 method
|
||||
When using
|
||||
.B --ifconfig
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "init.h"
|
||||
#include "forward.h"
|
||||
#include "multi.h"
|
||||
#include "win32.h"
|
||||
|
||||
#include "memdbg.h"
|
||||
|
||||
@ -131,6 +132,9 @@ main (int argc, char *argv[])
|
||||
|
||||
/* initialize environmental variable store */
|
||||
c.es = env_set_create (NULL);
|
||||
#ifdef WIN32
|
||||
env_set_add_win32 (c.es);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MANAGEMENT
|
||||
/* initialize management subsystem */
|
||||
|
19
options.c
19
options.c
@ -189,6 +189,10 @@ static const char usage_message[] =
|
||||
" flag to add a direct route to DHCP server, bypassing tunnel.\n"
|
||||
" Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n"
|
||||
"--setenv name value : Set a custom environmental variable to pass to script.\n"
|
||||
"--script-security level : 0 -- strictly no calling of external programs\n"
|
||||
" 1 -- (default) only call built-ins such as ifconfig\n"
|
||||
" 2 -- allow calling of built-ins and scripts\n"
|
||||
" 3 -- allow password to be passed to scripts via env\n"
|
||||
"--shaper n : Restrict output to peer to n bytes per second.\n"
|
||||
"--keepalive n m : Helper option for setting timeouts in server mode. Send\n"
|
||||
" ping once every n seconds, restart if ping not received\n"
|
||||
@ -536,6 +540,8 @@ static const char usage_message[] =
|
||||
#ifdef WIN32
|
||||
"\n"
|
||||
"Windows Specific:\n"
|
||||
"--win-sys path|'env' : Pathname of Windows system directory, C:\\WINDOWS by default.\n"
|
||||
" If specified as 'env', read the pathname from SystemRoot env var.\n"
|
||||
"--ip-win32 method : When using --ifconfig on Windows, set TAP-Win32 adapter\n"
|
||||
" IP address using method = manual, netsh, ipapi,\n"
|
||||
" dynamic, or adaptive (default = adaptive).\n"
|
||||
@ -4249,6 +4255,11 @@ add_option (struct options *options,
|
||||
VERIFY_PERMISSION (OPT_P_SETENV);
|
||||
setenv_str_safe (es, p[1], p[2] ? p[2] : "");
|
||||
}
|
||||
else if (streq (p[0], "script-security") && p[1])
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
script_security = atoi (p[1]);
|
||||
}
|
||||
else if (streq (p[0], "mssfix"))
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
@ -4618,6 +4629,14 @@ add_option (struct options *options,
|
||||
}
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
else if (streq (p[0], "win-sys") && p[1])
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
if (streq (p[1], "env"))
|
||||
set_win_sys_path_via_env (es);
|
||||
else
|
||||
set_win_sys_path (p[1], es);
|
||||
}
|
||||
else if (streq (p[0], "route-method") && p[1])
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS);
|
||||
|
19
plugin.c
19
plugin.c
@ -327,7 +327,7 @@ static int
|
||||
plugin_call_item (const struct plugin *p,
|
||||
void *per_client_context,
|
||||
const int type,
|
||||
const char *args,
|
||||
const struct argv *av,
|
||||
struct openvpn_plugin_string_list **retlist,
|
||||
const char **envp)
|
||||
{
|
||||
@ -340,18 +340,18 @@ plugin_call_item (const struct plugin *p,
|
||||
if (p->plugin_handle && (p->plugin_type_mask & OPENVPN_PLUGIN_MASK (type)))
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
const char **argv = make_arg_array (p->so_pathname, args, &gc);
|
||||
struct argv a = argv_insert_head (av, p->so_pathname);
|
||||
|
||||
dmsg (D_PLUGIN_DEBUG, "PLUGIN_CALL: PRE type=%s", plugin_type_name (type));
|
||||
plugin_show_args_env (D_PLUGIN_DEBUG, argv, envp);
|
||||
plugin_show_args_env (D_PLUGIN_DEBUG, (const char **)a.argv, envp);
|
||||
|
||||
/*
|
||||
* Call the plugin work function
|
||||
*/
|
||||
if (p->func2)
|
||||
status = (*p->func2)(p->plugin_handle, type, argv, envp, per_client_context, retlist);
|
||||
status = (*p->func2)(p->plugin_handle, type, (const char **)a.argv, envp, per_client_context, retlist);
|
||||
else if (p->func1)
|
||||
status = (*p->func1)(p->plugin_handle, type, argv, envp);
|
||||
status = (*p->func1)(p->plugin_handle, type, (const char **)a.argv, envp);
|
||||
else
|
||||
ASSERT (0);
|
||||
|
||||
@ -366,6 +366,7 @@ plugin_call_item (const struct plugin *p,
|
||||
status,
|
||||
p->so_pathname);
|
||||
|
||||
argv_reset (&a);
|
||||
gc_free (&gc);
|
||||
}
|
||||
return status;
|
||||
@ -482,7 +483,7 @@ plugin_common_open (struct plugin_common *pc,
|
||||
int i;
|
||||
const char **envp;
|
||||
|
||||
envp = make_env_array (es, &gc);
|
||||
envp = make_env_array (es, false, &gc);
|
||||
|
||||
if (pr)
|
||||
plugin_return_init (pr);
|
||||
@ -540,7 +541,7 @@ plugin_list_open (struct plugin_list *pl,
|
||||
int
|
||||
plugin_call (const struct plugin_list *pl,
|
||||
const int type,
|
||||
const char *args,
|
||||
const struct argv *av,
|
||||
struct plugin_return *pr,
|
||||
struct env_set *es)
|
||||
{
|
||||
@ -560,14 +561,14 @@ plugin_call (const struct plugin_list *pl,
|
||||
mutex_lock_static (L_PLUGIN);
|
||||
|
||||
setenv_del (es, "script_type");
|
||||
envp = make_env_array (es, &gc);
|
||||
envp = make_env_array (es, false, &gc);
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
{
|
||||
const int status = plugin_call_item (&pl->common->plugins[i],
|
||||
pl->per_client.per_client_context[i],
|
||||
type,
|
||||
args,
|
||||
av,
|
||||
pr ? &pr->list[i] : NULL,
|
||||
envp);
|
||||
switch (status)
|
||||
|
4
plugin.h
4
plugin.h
@ -116,7 +116,7 @@ struct plugin_list *plugin_list_inherit (const struct plugin_list *src);
|
||||
|
||||
int plugin_call (const struct plugin_list *pl,
|
||||
const int type,
|
||||
const char *args,
|
||||
const struct argv *av,
|
||||
struct plugin_return *pr,
|
||||
struct env_set *es);
|
||||
|
||||
@ -168,7 +168,7 @@ plugin_defined (const struct plugin_list *pl, const int type)
|
||||
static inline int
|
||||
plugin_call (const struct plugin_list *pl,
|
||||
const int type,
|
||||
const char *args,
|
||||
const struct argv *av,
|
||||
struct plugin_return *pr,
|
||||
struct env_set *es)
|
||||
{
|
||||
|
184
plugin/examples/log.c
Normal file
184
plugin/examples/log.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* OpenVPN -- An application to securely tunnel IP networks
|
||||
* over a single TCP/UDP port, with support for SSL/TLS-based
|
||||
* session authentication and key exchange,
|
||||
* packet encryption, packet authentication, and
|
||||
* packet compression.
|
||||
*
|
||||
* Copyright (C) 2002-2008 Telethra, Inc. <sales@openvpn.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (see the file COPYING included with this
|
||||
* distribution); if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This plugin is similar to simple.c, except it also logs extra information
|
||||
* to stdout for every plugin method called by OpenVPN.
|
||||
*
|
||||
* See the README file for build instructions.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "openvpn-plugin.h"
|
||||
|
||||
/*
|
||||
* Our context, where we keep our state.
|
||||
*/
|
||||
struct plugin_context {
|
||||
const char *username;
|
||||
const char *password;
|
||||
};
|
||||
|
||||
/*
|
||||
* Given an environmental variable name, search
|
||||
* the envp array for its value, returning it
|
||||
* if found or NULL otherwise.
|
||||
*/
|
||||
static const char *
|
||||
get_env (const char *name, const char *envp[])
|
||||
{
|
||||
if (envp)
|
||||
{
|
||||
int i;
|
||||
const int namelen = strlen (name);
|
||||
for (i = 0; envp[i]; ++i)
|
||||
{
|
||||
if (!strncmp (envp[i], name, namelen))
|
||||
{
|
||||
const char *cp = envp[i] + namelen;
|
||||
if (*cp == '=')
|
||||
return cp + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OPENVPN_EXPORT openvpn_plugin_handle_t
|
||||
openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[])
|
||||
{
|
||||
struct plugin_context *context;
|
||||
|
||||
/*
|
||||
* Allocate our context
|
||||
*/
|
||||
context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context));
|
||||
|
||||
/*
|
||||
* Set the username/password we will require.
|
||||
*/
|
||||
context->username = "foo";
|
||||
context->password = "bar";
|
||||
|
||||
/*
|
||||
* Which callbacks to intercept.
|
||||
*/
|
||||
*type_mask =
|
||||
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) |
|
||||
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN) |
|
||||
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ROUTE_UP) |
|
||||
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_IPCHANGE) |
|
||||
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_VERIFY) |
|
||||
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) |
|
||||
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) |
|
||||
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) |
|
||||
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_LEARN_ADDRESS) |
|
||||
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_FINAL);
|
||||
|
||||
return (openvpn_plugin_handle_t) context;
|
||||
}
|
||||
|
||||
void
|
||||
show (const int type, const char *argv[], const char *envp[])
|
||||
{
|
||||
size_t i;
|
||||
switch (type)
|
||||
{
|
||||
case OPENVPN_PLUGIN_UP:
|
||||
printf ("OPENVPN_PLUGIN_UP\n");
|
||||
break;
|
||||
case OPENVPN_PLUGIN_DOWN:
|
||||
printf ("OPENVPN_PLUGIN_DOWN\n");
|
||||
break;
|
||||
case OPENVPN_PLUGIN_ROUTE_UP:
|
||||
printf ("OPENVPN_PLUGIN_ROUTE_UP\n");
|
||||
break;
|
||||
case OPENVPN_PLUGIN_IPCHANGE:
|
||||
printf ("OPENVPN_PLUGIN_IPCHANGE\n");
|
||||
break;
|
||||
case OPENVPN_PLUGIN_TLS_VERIFY:
|
||||
printf ("OPENVPN_PLUGIN_TLS_VERIFY\n");
|
||||
break;
|
||||
case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
|
||||
printf ("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
|
||||
break;
|
||||
case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
|
||||
printf ("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
|
||||
break;
|
||||
case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
|
||||
printf ("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n");
|
||||
break;
|
||||
case OPENVPN_PLUGIN_LEARN_ADDRESS:
|
||||
printf ("OPENVPN_PLUGIN_LEARN_ADDRESS\n");
|
||||
break;
|
||||
case OPENVPN_PLUGIN_TLS_FINAL:
|
||||
printf ("OPENVPN_PLUGIN_TLS_FINAL\n");
|
||||
break;
|
||||
default:
|
||||
printf ("OPENVPN_PLUGIN_?\n");
|
||||
break;
|
||||
}
|
||||
|
||||
printf ("ARGV\n");
|
||||
for (i = 0; argv[i] != NULL; ++i)
|
||||
printf ("%d '%s'\n", (int)i, argv[i]);
|
||||
|
||||
printf ("ENVP\n");
|
||||
for (i = 0; envp[i] != NULL; ++i)
|
||||
printf ("%d '%s'\n", (int)i, envp[i]);
|
||||
}
|
||||
|
||||
OPENVPN_EXPORT int
|
||||
openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
|
||||
{
|
||||
struct plugin_context *context = (struct plugin_context *) handle;
|
||||
|
||||
show (type, argv, envp);
|
||||
|
||||
/* check entered username/password against what we require */
|
||||
if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
|
||||
{
|
||||
/* get username/password from envp string array */
|
||||
const char *username = get_env ("username", envp);
|
||||
const char *password = get_env ("password", envp);
|
||||
|
||||
if (username && !strcmp (username, context->username)
|
||||
&& password && !strcmp (password, context->password))
|
||||
return OPENVPN_PLUGIN_FUNC_SUCCESS;
|
||||
else
|
||||
return OPENVPN_PLUGIN_FUNC_ERROR;
|
||||
}
|
||||
else
|
||||
return OPENVPN_PLUGIN_FUNC_SUCCESS;
|
||||
}
|
||||
|
||||
OPENVPN_EXPORT void
|
||||
openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle)
|
||||
{
|
||||
struct plugin_context *context = (struct plugin_context *) handle;
|
||||
free (context);
|
||||
}
|
159
route.c
159
route.c
@ -34,6 +34,7 @@
|
||||
#include "misc.h"
|
||||
#include "socket.h"
|
||||
#include "manage.h"
|
||||
#include "win32.h"
|
||||
|
||||
#include "memdbg.h"
|
||||
|
||||
@ -743,7 +744,7 @@ void
|
||||
add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
|
||||
{
|
||||
struct gc_arena gc;
|
||||
struct buffer buf;
|
||||
struct argv argv;
|
||||
const char *network;
|
||||
const char *netmask;
|
||||
const char *gateway;
|
||||
@ -753,7 +754,7 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s
|
||||
return;
|
||||
|
||||
gc_init (&gc);
|
||||
buf = alloc_buf_gc (256, &gc);
|
||||
argv_init (&argv);
|
||||
|
||||
network = print_in_addr_t (r->network, 0, &gc);
|
||||
netmask = print_in_addr_t (r->netmask, 0, &gc);
|
||||
@ -771,35 +772,38 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s
|
||||
|
||||
#if defined(TARGET_LINUX)
|
||||
#ifdef CONFIG_FEATURE_IPROUTE
|
||||
buf_printf (&buf, "%s route add %s/%d via %s",
|
||||
argv_printf (&argv, "%s route add %s/%d via %s",
|
||||
iproute_path,
|
||||
network,
|
||||
count_netmask_bits(netmask),
|
||||
gateway);
|
||||
if (r->metric_defined)
|
||||
buf_printf (&buf, " metric %d", r->metric);
|
||||
argv_printf_cat (&argv, "metric %d", r->metric);
|
||||
|
||||
#else
|
||||
buf_printf (&buf, ROUTE_PATH " add -net %s netmask %s gw %s",
|
||||
argv_printf (&argv, "%s add -net %s netmask %s gw %s",
|
||||
ROUTE_PATH,
|
||||
network,
|
||||
netmask,
|
||||
gateway);
|
||||
if (r->metric_defined)
|
||||
buf_printf (&buf, " metric %d", r->metric);
|
||||
argv_printf_cat (&argv, "metric %d", r->metric);
|
||||
#endif /*CONFIG_FEATURE_IPROUTE*/
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
status = system_check (BSTR (&buf), es, 0, "ERROR: Linux route add command failed");
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route add command failed");
|
||||
|
||||
#elif defined (WIN32)
|
||||
|
||||
buf_printf (&buf, ROUTE_PATH " ADD %s MASK %s %s",
|
||||
network,
|
||||
netmask,
|
||||
gateway);
|
||||
argv_printf (&argv, "%s%s ADD %s MASK %s %s",
|
||||
get_win_sys_path(),
|
||||
WIN_ROUTE_PATH_SUFFIX,
|
||||
network,
|
||||
netmask,
|
||||
gateway);
|
||||
if (r->metric_defined)
|
||||
buf_printf (&buf, " METRIC %d", r->metric);
|
||||
argv_printf_cat (&argv, "METRIC %d", r->metric);
|
||||
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
|
||||
if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI)
|
||||
{
|
||||
@ -809,7 +813,7 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s
|
||||
else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_EXE)
|
||||
{
|
||||
netcmd_semaphore_lock ();
|
||||
status = system_check (BSTR (&buf), es, 0, "ERROR: Windows route add command failed");
|
||||
status = openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add command failed");
|
||||
netcmd_semaphore_release ();
|
||||
}
|
||||
else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_ADAPTIVE)
|
||||
@ -820,7 +824,7 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s
|
||||
{
|
||||
msg (D_ROUTE, "Route addition fallback to route.exe");
|
||||
netcmd_semaphore_lock ();
|
||||
status = system_check (BSTR (&buf), es, 0, "ERROR: Windows route add command failed [adaptive]");
|
||||
status = openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add command failed [adaptive]");
|
||||
netcmd_semaphore_release ();
|
||||
}
|
||||
}
|
||||
@ -833,88 +837,93 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s
|
||||
|
||||
/* example: route add 192.0.2.32 -netmask 255.255.255.224 somegateway */
|
||||
|
||||
buf_printf (&buf, ROUTE_PATH " add");
|
||||
argv_printf (&argv, "%s add",
|
||||
ROUTE_PATH);
|
||||
|
||||
#if 0
|
||||
if (r->metric_defined)
|
||||
buf_printf (&buf, " -rtt %d", r->metric);
|
||||
argv_printf_cat (&argv, "-rtt %d", r->metric);
|
||||
#endif
|
||||
|
||||
buf_printf (&buf, " %s -netmask %s %s",
|
||||
argv_printf_cat (&argv, "%s -netmask %s %s",
|
||||
network,
|
||||
netmask,
|
||||
gateway);
|
||||
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
status = system_check (BSTR (&buf), es, 0, "ERROR: Solaris route add command failed");
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
status = openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route add command failed");
|
||||
|
||||
#elif defined(TARGET_FREEBSD)
|
||||
|
||||
buf_printf (&buf, ROUTE_PATH " add");
|
||||
argv_printf (&argv, "%s add",
|
||||
ROUTE_PATH);
|
||||
|
||||
#if 0
|
||||
if (r->metric_defined)
|
||||
buf_printf (&buf, " -rtt %d", r->metric);
|
||||
argv_printf_cat (&argv, "-rtt %d", r->metric);
|
||||
#endif
|
||||
|
||||
buf_printf (&buf, " -net %s %s %s",
|
||||
argv_printf_cat (&argv, "-net %s %s %s",
|
||||
network,
|
||||
gateway,
|
||||
netmask);
|
||||
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
status = system_check (BSTR (&buf), es, 0, "ERROR: FreeBSD route add command failed");
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
status = openvpn_execve_check (&argv, es, 0, "ERROR: FreeBSD route add command failed");
|
||||
|
||||
#elif defined(TARGET_DRAGONFLY)
|
||||
|
||||
buf_printf (&buf, ROUTE_PATH " add");
|
||||
argv_printf (&argv, "%s add",
|
||||
ROUTE_PATH);
|
||||
|
||||
#if 0
|
||||
if (r->metric_defined)
|
||||
buf_printf (&buf, " -rtt %d", r->metric);
|
||||
argv_printf_cat (&argv, "-rtt %d", r->metric);
|
||||
#endif
|
||||
|
||||
buf_printf (&buf, " -net %s %s %s",
|
||||
argv_printf_cat (&argv, "-net %s %s %s",
|
||||
network,
|
||||
gateway,
|
||||
netmask);
|
||||
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
status = system_check (BSTR (&buf), es, 0, "ERROR: DragonFly route add command failed");
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
status = openvpn_execve_check (&argv, es, 0, "ERROR: DragonFly route add command failed");
|
||||
|
||||
#elif defined(TARGET_DARWIN)
|
||||
|
||||
buf_printf (&buf, ROUTE_PATH " add");
|
||||
argv_printf (&argv, "%s add",
|
||||
ROUTE_PATH);
|
||||
|
||||
#if 0
|
||||
if (r->metric_defined)
|
||||
buf_printf (&buf, " -rtt %d", r->metric);
|
||||
argv_printf_cat (&argv, "-rtt %d", r->metric);
|
||||
#endif
|
||||
|
||||
buf_printf (&buf, " -net %s %s %s",
|
||||
argv_printf_cat (&argv, "-net %s %s %s",
|
||||
network,
|
||||
gateway,
|
||||
netmask);
|
||||
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
status = system_check (BSTR (&buf), es, 0, "ERROR: OS X route add command failed");
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
status = openvpn_execve_check (&argv, es, 0, "ERROR: OS X route add command failed");
|
||||
|
||||
#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
|
||||
|
||||
buf_printf (&buf, ROUTE_PATH " add");
|
||||
argv_printf (&argv, "%s add",
|
||||
ROUTE_PATH);
|
||||
|
||||
#if 0
|
||||
if (r->metric_defined)
|
||||
buf_printf (&buf, " -rtt %d", r->metric);
|
||||
argv_printf_cat (&argv, "-rtt %d", r->metric);
|
||||
#endif
|
||||
|
||||
buf_printf (&buf, " -net %s %s -netmask %s",
|
||||
argv_printf_cat (&argv, "-net %s %s -netmask %s",
|
||||
network,
|
||||
gateway,
|
||||
netmask);
|
||||
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
status = system_check (BSTR (&buf), es, 0, "ERROR: OpenBSD/NetBSD route add command failed");
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
status = openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD/NetBSD route add command failed");
|
||||
|
||||
#else
|
||||
msg (M_FATAL, "Sorry, but I don't know how to do 'route' commands on this operating system. Try putting your routes in a --route-up script");
|
||||
@ -922,6 +931,7 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s
|
||||
|
||||
done:
|
||||
r->defined = status;
|
||||
argv_reset (&argv);
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
@ -929,7 +939,7 @@ static void
|
||||
delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
|
||||
{
|
||||
struct gc_arena gc;
|
||||
struct buffer buf;
|
||||
struct argv argv;
|
||||
const char *network;
|
||||
const char *netmask;
|
||||
const char *gateway;
|
||||
@ -938,37 +948,40 @@ delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags
|
||||
return;
|
||||
|
||||
gc_init (&gc);
|
||||
argv_init (&argv);
|
||||
|
||||
buf = alloc_buf_gc (256, &gc);
|
||||
network = print_in_addr_t (r->network, 0, &gc);
|
||||
netmask = print_in_addr_t (r->netmask, 0, &gc);
|
||||
gateway = print_in_addr_t (r->gateway, 0, &gc);
|
||||
|
||||
#if defined(TARGET_LINUX)
|
||||
#ifdef CONFIG_FEATURE_IPROUTE
|
||||
buf_printf (&buf, "%s route del %s/%d",
|
||||
argv_printf (&argv, "%s route del %s/%d",
|
||||
iproute_path,
|
||||
network,
|
||||
count_netmask_bits(netmask));
|
||||
#else
|
||||
|
||||
buf_printf (&buf, ROUTE_PATH " del -net %s netmask %s",
|
||||
argv_printf (&argv, "%s del -net %s netmask %s",
|
||||
ROUTE_PATH,
|
||||
network,
|
||||
netmask);
|
||||
#endif /*CONFIG_FEATURE_IPROUTE*/
|
||||
if (r->metric_defined)
|
||||
buf_printf (&buf, " metric %d", r->metric);
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
system_check (BSTR (&buf), es, 0, "ERROR: Linux route delete command failed");
|
||||
argv_printf_cat (&argv, "metric %d", r->metric);
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
openvpn_execve_check (&argv, es, 0, "ERROR: Linux route delete command failed");
|
||||
|
||||
#elif defined (WIN32)
|
||||
|
||||
buf_printf (&buf, ROUTE_PATH " DELETE %s MASK %s %s",
|
||||
network,
|
||||
netmask,
|
||||
gateway);
|
||||
argv_printf (&argv, "%s%s DELETE %s MASK %s %s",
|
||||
get_win_sys_path(),
|
||||
WIN_ROUTE_PATH_SUFFIX,
|
||||
network,
|
||||
netmask,
|
||||
gateway);
|
||||
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
|
||||
if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI)
|
||||
{
|
||||
@ -978,7 +991,7 @@ delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags
|
||||
else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_EXE)
|
||||
{
|
||||
netcmd_semaphore_lock ();
|
||||
system_check (BSTR (&buf), es, 0, "ERROR: Windows route delete command failed");
|
||||
openvpn_execve_check (&argv, es, 0, "ERROR: Windows route delete command failed");
|
||||
netcmd_semaphore_release ();
|
||||
}
|
||||
else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_ADAPTIVE)
|
||||
@ -989,7 +1002,7 @@ delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags
|
||||
{
|
||||
msg (D_ROUTE, "Route deletion fallback to route.exe");
|
||||
netcmd_semaphore_lock ();
|
||||
system_check (BSTR (&buf), es, 0, "ERROR: Windows route delete command failed [adaptive]");
|
||||
openvpn_execve_check (&argv, es, 0, "ERROR: Windows route delete command failed [adaptive]");
|
||||
netcmd_semaphore_release ();
|
||||
}
|
||||
}
|
||||
@ -1000,58 +1013,64 @@ delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags
|
||||
|
||||
#elif defined (TARGET_SOLARIS)
|
||||
|
||||
buf_printf (&buf, ROUTE_PATH " delete %s -netmask %s %s",
|
||||
argv_printf (&argv, "%s delete %s -netmask %s %s",
|
||||
ROUTE_PATH,
|
||||
network,
|
||||
netmask,
|
||||
gateway);
|
||||
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
system_check (BSTR (&buf), es, 0, "ERROR: Solaris route delete command failed");
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route delete command failed");
|
||||
|
||||
#elif defined(TARGET_FREEBSD)
|
||||
|
||||
buf_printf (&buf, ROUTE_PATH " delete -net %s %s %s",
|
||||
argv_printf (&argv, "%s delete -net %s %s %s",
|
||||
ROUTE_PATH,
|
||||
network,
|
||||
gateway,
|
||||
netmask);
|
||||
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
system_check (BSTR (&buf), es, 0, "ERROR: FreeBSD route delete command failed");
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
openvpn_execve_check (&argv, es, 0, "ERROR: FreeBSD route delete command failed");
|
||||
|
||||
#elif defined(TARGET_DRAGONFLY)
|
||||
|
||||
buf_printf (&buf, ROUTE_PATH " delete -net %s %s %s",
|
||||
argv_printf (&argv, "%s delete -net %s %s %s",
|
||||
ROUTE_PATH,
|
||||
network,
|
||||
gateway,
|
||||
netmask);
|
||||
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
system_check (BSTR (&buf), es, 0, "ERROR: DragonFly route delete command failed");
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
openvpn_execve_check (&argv, es, 0, "ERROR: DragonFly route delete command failed");
|
||||
|
||||
#elif defined(TARGET_DARWIN)
|
||||
|
||||
buf_printf (&buf, ROUTE_PATH " delete -net %s %s %s",
|
||||
argv_printf (&argv, "%s delete -net %s %s %s",
|
||||
ROUTE_PATH,
|
||||
network,
|
||||
gateway,
|
||||
netmask);
|
||||
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
system_check (BSTR (&buf), es, 0, "ERROR: OS X route delete command failed");
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
openvpn_execve_check (&argv, es, 0, "ERROR: OS X route delete command failed");
|
||||
|
||||
#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
|
||||
|
||||
buf_printf (&buf, ROUTE_PATH " delete -net %s %s -netmask %s",
|
||||
argv_printf (&argv, "%s delete -net %s %s -netmask %s",
|
||||
ROUTE_PATH,
|
||||
network,
|
||||
gateway,
|
||||
netmask);
|
||||
|
||||
msg (D_ROUTE, "%s", BSTR (&buf));
|
||||
system_check (BSTR (&buf), es, 0, "ERROR: OpenBSD/NetBSD route delete command failed");
|
||||
argv_msg (D_ROUTE, &argv);
|
||||
openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD/NetBSD route delete command failed");
|
||||
|
||||
#else
|
||||
msg (M_FATAL, "Sorry, but I don't know how to do 'route' commands on this operating system. Try putting your routes in a --route-up script");
|
||||
#endif
|
||||
|
||||
argv_reset (&argv);
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
|
34
socket.c
34
socket.c
@ -1480,6 +1480,22 @@ setenv_trusted (struct env_set *es, const struct link_socket_info *info)
|
||||
setenv_link_socket_actual (es, "trusted", &info->lsa->actual, SA_IP_PORT);
|
||||
}
|
||||
|
||||
static void
|
||||
ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc)
|
||||
{
|
||||
const char *ip = print_sockaddr_ex (&info->lsa->actual.dest, NULL, 0, gc);
|
||||
const char *port = print_sockaddr_ex (&info->lsa->actual.dest, NULL, PS_DONT_SHOW_ADDR|PS_SHOW_PORT, gc);
|
||||
if (include_cmd)
|
||||
argv_printf (argv, "%s %s %s",
|
||||
info->ipchange_command,
|
||||
ip,
|
||||
port);
|
||||
else
|
||||
argv_printf (argv, "%s %s",
|
||||
ip,
|
||||
port);
|
||||
}
|
||||
|
||||
void
|
||||
link_socket_connection_initiated (const struct buffer *buf,
|
||||
struct link_socket_info *info,
|
||||
@ -1508,20 +1524,21 @@ link_socket_connection_initiated (const struct buffer *buf,
|
||||
/* Process --ipchange plugin */
|
||||
if (plugin_defined (info->plugins, OPENVPN_PLUGIN_IPCHANGE))
|
||||
{
|
||||
const char *addr_ascii = print_sockaddr_ex (&info->lsa->actual.dest, " ", PS_SHOW_PORT, &gc);
|
||||
if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, addr_ascii, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
struct argv argv = argv_new ();
|
||||
ipchange_fmt (false, &argv, info, &gc);
|
||||
if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
msg (M_WARN, "WARNING: ipchange plugin call failed");
|
||||
argv_reset (&argv);
|
||||
}
|
||||
|
||||
/* Process --ipchange option */
|
||||
if (info->ipchange_command)
|
||||
{
|
||||
struct buffer out = alloc_buf_gc (256, &gc);
|
||||
struct argv argv = argv_new ();
|
||||
setenv_str (es, "script_type", "ipchange");
|
||||
buf_printf (&out, "%s %s",
|
||||
info->ipchange_command,
|
||||
print_sockaddr_ex (&info->lsa->actual.dest, " ", PS_SHOW_PORT, &gc));
|
||||
system_check (BSTR (&out), es, S_SCRIPT, "ip-change command failed");
|
||||
ipchange_fmt (true, &argv, info, &gc);
|
||||
openvpn_execve_check (&argv, es, S_SCRIPT, "ip-change command failed");
|
||||
argv_reset (&argv);
|
||||
}
|
||||
|
||||
gc_free (&gc);
|
||||
@ -1791,7 +1808,8 @@ print_sockaddr_ex (const struct openvpn_sockaddr *addr,
|
||||
const int port = ntohs (addr->sa.sin_port);
|
||||
|
||||
mutex_lock_static (L_INET_NTOA);
|
||||
buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sa.sin_addr) : "[undef]"));
|
||||
if (!(flags & PS_DONT_SHOW_ADDR))
|
||||
buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sa.sin_addr) : "[undef]"));
|
||||
mutex_unlock_static (L_INET_NTOA);
|
||||
|
||||
if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED)))
|
||||
|
1
socket.h
1
socket.h
@ -325,6 +325,7 @@ void link_socket_close (struct link_socket *sock);
|
||||
#define PS_SHOW_PORT_IF_DEFINED (1<<0)
|
||||
#define PS_SHOW_PORT (1<<1)
|
||||
#define PS_SHOW_PKTINFO (1<<2)
|
||||
#define PS_DONT_SHOW_ADDR (1<<3)
|
||||
|
||||
const char *print_sockaddr_ex (const struct openvpn_sockaddr *addr,
|
||||
const char* separator,
|
||||
|
40
ssl.c
40
ssl.c
@ -544,6 +544,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
|
||||
struct tls_session *session;
|
||||
const struct tls_options *opt;
|
||||
const int max_depth = 8;
|
||||
struct argv argv = argv_new ();
|
||||
|
||||
/* get the tls_session pointer */
|
||||
ssl = X509_STORE_CTX_get_ex_data (ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
||||
@ -689,16 +690,13 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
|
||||
/* call --tls-verify plug-in(s) */
|
||||
if (plugin_defined (opt->plugins, OPENVPN_PLUGIN_TLS_VERIFY))
|
||||
{
|
||||
char command[256];
|
||||
struct buffer out;
|
||||
int ret;
|
||||
|
||||
buf_set_write (&out, (uint8_t*)command, sizeof (command));
|
||||
buf_printf (&out, "%d %s",
|
||||
ctx->error_depth,
|
||||
subject);
|
||||
argv_printf (&argv, "%d %s",
|
||||
ctx->error_depth,
|
||||
subject);
|
||||
|
||||
ret = plugin_call (opt->plugins, OPENVPN_PLUGIN_TLS_VERIFY, command, NULL, opt->es);
|
||||
ret = plugin_call (opt->plugins, OPENVPN_PLUGIN_TLS_VERIFY, &argv, NULL, opt->es);
|
||||
|
||||
if (ret == OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
{
|
||||
@ -716,19 +714,16 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
|
||||
/* run --tls-verify script */
|
||||
if (opt->verify_command)
|
||||
{
|
||||
char command[256];
|
||||
struct buffer out;
|
||||
int ret;
|
||||
|
||||
setenv_str (opt->es, "script_type", "tls-verify");
|
||||
|
||||
buf_set_write (&out, (uint8_t*)command, sizeof (command));
|
||||
buf_printf (&out, "%s %d %s",
|
||||
opt->verify_command,
|
||||
ctx->error_depth,
|
||||
subject);
|
||||
dmsg (D_TLS_DEBUG, "TLS: executing verify command: %s", command);
|
||||
ret = openvpn_system (command, opt->es, S_SCRIPT);
|
||||
argv_printf (&argv, "%s %d %s",
|
||||
opt->verify_command,
|
||||
ctx->error_depth,
|
||||
subject);
|
||||
argv_msg_prefix (D_TLS_DEBUG, &argv, "TLS: executing verify command");
|
||||
ret = openvpn_execve (&argv, opt->es, S_SCRIPT);
|
||||
|
||||
if (system_ok (ret))
|
||||
{
|
||||
@ -738,7 +733,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
|
||||
else
|
||||
{
|
||||
if (!system_executed (ret))
|
||||
msg (M_ERR, "Verify command failed to execute: %s", command);
|
||||
argv_msg_prefix (M_ERR, &argv, "Verify command failed to execute");
|
||||
msg (D_HANDSHAKE, "VERIFY SCRIPT ERROR: depth=%d, %s",
|
||||
ctx->error_depth, subject);
|
||||
goto err; /* Reject connection */
|
||||
@ -801,11 +796,13 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
|
||||
|
||||
session->verified = true;
|
||||
free (subject);
|
||||
argv_reset (&argv);
|
||||
return 1; /* Accept connection */
|
||||
|
||||
err:
|
||||
ERR_clear_error ();
|
||||
free (subject);
|
||||
argv_reset (&argv);
|
||||
return 0; /* Reject connection */
|
||||
}
|
||||
|
||||
@ -2901,7 +2898,7 @@ static bool
|
||||
verify_user_pass_script (struct tls_session *session, const struct user_pass *up)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
struct buffer cmd = alloc_buf_gc (256, &gc);
|
||||
struct argv argv = argv_new ();
|
||||
const char *tmp_file = "";
|
||||
int retval;
|
||||
bool ret = false;
|
||||
@ -2940,16 +2937,16 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
|
||||
setenv_untrusted (session);
|
||||
|
||||
/* format command line */
|
||||
buf_printf (&cmd, "%s %s", session->opt->auth_user_pass_verify_script, tmp_file);
|
||||
argv_printf (&argv, "%s %s", session->opt->auth_user_pass_verify_script, tmp_file);
|
||||
|
||||
/* call command */
|
||||
retval = openvpn_system (BSTR (&cmd), session->opt->es, S_SCRIPT);
|
||||
retval = openvpn_execve (&argv, session->opt->es, S_SCRIPT);
|
||||
|
||||
/* test return status of command */
|
||||
if (system_ok (retval))
|
||||
ret = true;
|
||||
else if (!system_executed (retval))
|
||||
msg (D_TLS_ERRORS, "TLS Auth Error: user-pass-verify script failed to execute: %s", BSTR (&cmd));
|
||||
argv_msg_prefix (D_TLS_ERRORS, &argv, "TLS Auth Error: user-pass-verify script failed to execute");
|
||||
|
||||
if (!session->opt->auth_user_pass_verify_script_via_file)
|
||||
setenv_del (session->opt->es, "password");
|
||||
@ -2963,6 +2960,7 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
|
||||
if (strlen (tmp_file) > 0)
|
||||
delete_file (tmp_file);
|
||||
|
||||
argv_reset (&argv);
|
||||
gc_free (&gc);
|
||||
return ret;
|
||||
}
|
||||
|
@ -447,6 +447,14 @@ socket_defined (const socket_descriptor_t sd)
|
||||
*/
|
||||
#define USE_64_BIT_COUNTERS
|
||||
|
||||
/*
|
||||
* Should we enable the use of execve() for calling subprocesses,
|
||||
* instead of system()?
|
||||
*/
|
||||
#if defined(HAVE_EXECVE) && defined(HAVE_FORK)
|
||||
#define ENABLE_EXECVE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Do we have point-to-multipoint capability?
|
||||
*/
|
||||
|
250
tun.c
250
tun.c
@ -39,6 +39,7 @@
|
||||
#include "socket.h"
|
||||
#include "manage.h"
|
||||
#include "route.h"
|
||||
#include "win32.h"
|
||||
|
||||
#include "memdbg.h"
|
||||
|
||||
@ -534,7 +535,9 @@ do_ifconfig (struct tuntap *tt,
|
||||
const char *ifconfig_local = NULL;
|
||||
const char *ifconfig_remote_netmask = NULL;
|
||||
const char *ifconfig_broadcast = NULL;
|
||||
char command_line[256];
|
||||
struct argv argv;
|
||||
|
||||
argv_init (&argv);
|
||||
|
||||
/*
|
||||
* We only handle TUN/TAP devices here, not --dev null devices.
|
||||
@ -570,31 +573,31 @@ do_ifconfig (struct tuntap *tt,
|
||||
/*
|
||||
* Set the MTU for the device
|
||||
*/
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
argv_printf (&argv,
|
||||
"%s link set dev %s up mtu %d",
|
||||
iproute_path,
|
||||
actual,
|
||||
tun_mtu
|
||||
);
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, es, S_FATAL, "Linux ip link set failed");
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "Linux ip link set failed");
|
||||
|
||||
if (tun) {
|
||||
|
||||
/*
|
||||
* Set the address for the device
|
||||
*/
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
argv_printf (&argv,
|
||||
"%s addr add dev %s local %s peer %s",
|
||||
iproute_path,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_remote_netmask
|
||||
);
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, es, S_FATAL, "Linux ip addr add failed");
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "Linux ip addr add failed");
|
||||
} else {
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
argv_printf (&argv,
|
||||
"%s addr add dev %s %s/%d broadcast %s",
|
||||
iproute_path,
|
||||
actual,
|
||||
@ -602,30 +605,32 @@ do_ifconfig (struct tuntap *tt,
|
||||
count_netmask_bits(ifconfig_remote_netmask),
|
||||
ifconfig_broadcast
|
||||
);
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, es, S_FATAL, "Linux ip addr add failed");
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "Linux ip addr add failed");
|
||||
}
|
||||
tt->did_ifconfig = true;
|
||||
#else
|
||||
if (tun)
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s %s pointopoint %s mtu %d",
|
||||
argv_printf (&argv,
|
||||
"%s %s %s pointopoint %s mtu %d",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_remote_netmask,
|
||||
tun_mtu
|
||||
);
|
||||
else
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s %s netmask %s mtu %d broadcast %s",
|
||||
argv_printf (&argv,
|
||||
"%s %s %s netmask %s mtu %d broadcast %s",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_remote_netmask,
|
||||
tun_mtu,
|
||||
ifconfig_broadcast
|
||||
);
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, es, S_FATAL, "Linux ifconfig failed");
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig failed");
|
||||
tt->did_ifconfig = true;
|
||||
|
||||
#endif /*CONFIG_FEATURE_IPROUTE*/
|
||||
@ -638,28 +643,30 @@ do_ifconfig (struct tuntap *tt,
|
||||
*/
|
||||
if (tun)
|
||||
{
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s %s %s mtu %d up",
|
||||
argv_printf (&argv,
|
||||
"%s %s %s %s mtu %d up",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_remote_netmask,
|
||||
tun_mtu
|
||||
);
|
||||
|
||||
msg (M_INFO, "%s", command_line);
|
||||
if (!system_check (command_line, es, 0, "Solaris ifconfig phase-1 failed"))
|
||||
argv_msg (M_INFO, &argv);
|
||||
if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-1 failed"))
|
||||
solaris_error_close (tt, es, actual);
|
||||
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s netmask 255.255.255.255",
|
||||
argv_printf (&argv,
|
||||
"%s %s netmask 255.255.255.255",
|
||||
IFCONFIG_PATH,
|
||||
actual
|
||||
);
|
||||
}
|
||||
else
|
||||
no_tap_ifconfig ();
|
||||
|
||||
msg (M_INFO, "%s", command_line);
|
||||
if (!system_check (command_line, es, 0, "Solaris ifconfig phase-2 failed"))
|
||||
argv_msg (M_INFO, &argv);
|
||||
if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-2 failed"))
|
||||
solaris_error_close (tt, es, actual);
|
||||
|
||||
tt->did_ifconfig = true;
|
||||
@ -672,45 +679,50 @@ do_ifconfig (struct tuntap *tt,
|
||||
* (if it exists), and re-ifconfig. Let me know if you know a better way.
|
||||
*/
|
||||
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s destroy",
|
||||
argv_printf (&argv,
|
||||
"%s %s destroy",
|
||||
IFCONFIG_PATH,
|
||||
actual);
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, es, 0, NULL);
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s create",
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, 0, NULL);
|
||||
argv_printf (&argv,
|
||||
"%s %s create",
|
||||
IFCONFIG_PATH,
|
||||
actual);
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, es, 0, NULL);
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, 0, NULL);
|
||||
msg (M_INFO, "NOTE: Tried to delete pre-existing tun/tap instance -- No Problem if failure");
|
||||
|
||||
/* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
|
||||
if (tun)
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s %s %s mtu %d netmask 255.255.255.255 up",
|
||||
argv_printf (&argv,
|
||||
"%s %s %s %s mtu %d netmask 255.255.255.255 up",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_remote_netmask,
|
||||
tun_mtu
|
||||
);
|
||||
else
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s %s netmask %s mtu %d broadcast %s link0",
|
||||
argv_printf (&argv,
|
||||
"%s %s %s netmask %s mtu %d broadcast %s link0",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_remote_netmask,
|
||||
tun_mtu,
|
||||
ifconfig_broadcast
|
||||
);
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, es, S_FATAL, "OpenBSD ifconfig failed");
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig failed");
|
||||
tt->did_ifconfig = true;
|
||||
|
||||
#elif defined(TARGET_NETBSD)
|
||||
|
||||
if (tun)
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s %s %s mtu %d netmask 255.255.255.255 up",
|
||||
argv_printf (&argv,
|
||||
"%s %s %s %s mtu %d netmask 255.255.255.255 up",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_remote_netmask,
|
||||
@ -722,16 +734,17 @@ do_ifconfig (struct tuntap *tt,
|
||||
* so we don't need the "link0" extra parameter to specify we want to do
|
||||
* tunneling at the ethernet level
|
||||
*/
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s %s netmask %s mtu %d broadcast %s",
|
||||
argv_printf (&argv,
|
||||
"%s %s %s netmask %s mtu %d broadcast %s",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_remote_netmask,
|
||||
tun_mtu,
|
||||
ifconfig_broadcast
|
||||
);
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, es, S_FATAL, "NetBSD ifconfig failed");
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig failed");
|
||||
tt->did_ifconfig = true;
|
||||
|
||||
#elif defined(TARGET_DARWIN)
|
||||
@ -740,18 +753,20 @@ do_ifconfig (struct tuntap *tt,
|
||||
* Darwin (i.e. Mac OS X) seems to exhibit similar behaviour to OpenBSD...
|
||||
*/
|
||||
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s delete",
|
||||
argv_printf (&argv,
|
||||
"%s %s delete",
|
||||
IFCONFIG_PATH,
|
||||
actual);
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, es, 0, NULL);
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, 0, NULL);
|
||||
msg (M_INFO, "NOTE: Tried to delete pre-existing tun/tap instance -- No Problem if failure");
|
||||
|
||||
|
||||
/* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
|
||||
if (tun)
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s %s %s mtu %d netmask 255.255.255.255 up",
|
||||
argv_printf (&argv,
|
||||
"%s %s %s %s mtu %d netmask 255.255.255.255 up",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_remote_netmask,
|
||||
@ -760,8 +775,9 @@ do_ifconfig (struct tuntap *tt,
|
||||
else
|
||||
{
|
||||
if (tt->topology == TOP_SUBNET)
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s %s %s netmask %s mtu %d up",
|
||||
argv_printf (&argv,
|
||||
"%s %s %s %s netmask %s mtu %d up",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_local,
|
||||
@ -769,16 +785,17 @@ do_ifconfig (struct tuntap *tt,
|
||||
tun_mtu
|
||||
);
|
||||
else
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s %s netmask %s mtu %d up",
|
||||
argv_printf (&argv,
|
||||
"%s %s %s netmask %s mtu %d up",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_remote_netmask,
|
||||
tun_mtu
|
||||
);
|
||||
}
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, es, S_FATAL, "Mac OS X ifconfig failed");
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "Mac OS X ifconfig failed");
|
||||
tt->did_ifconfig = true;
|
||||
|
||||
/* Add a network route for the local tun interface */
|
||||
@ -797,8 +814,9 @@ do_ifconfig (struct tuntap *tt,
|
||||
|
||||
/* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
|
||||
if (tun)
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s %s %s mtu %d netmask 255.255.255.255 up",
|
||||
argv_printf (&argv,
|
||||
"%s %s %s %s mtu %d netmask 255.255.255.255 up",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_remote_netmask,
|
||||
@ -806,8 +824,9 @@ do_ifconfig (struct tuntap *tt,
|
||||
);
|
||||
else {
|
||||
if (tt->topology == TOP_SUBNET)
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s %s %s netmask %s mtu %d up",
|
||||
argv_printf (&argv,
|
||||
"%s %s %s %s netmask %s mtu %d up",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_local,
|
||||
@ -815,8 +834,9 @@ do_ifconfig (struct tuntap *tt,
|
||||
tun_mtu
|
||||
);
|
||||
else
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s %s netmask %s mtu %d up",
|
||||
argv_printf (&argv,
|
||||
"%s %s %s netmask %s mtu %d up",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_local,
|
||||
ifconfig_remote_netmask,
|
||||
@ -824,8 +844,8 @@ do_ifconfig (struct tuntap *tt,
|
||||
);
|
||||
}
|
||||
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, es, S_FATAL, "FreeBSD ifconfig failed");
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig failed");
|
||||
tt->did_ifconfig = true;
|
||||
|
||||
/* Add a network route for the local tun interface */
|
||||
@ -882,6 +902,7 @@ do_ifconfig (struct tuntap *tt,
|
||||
#else
|
||||
msg (M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system. You should ifconfig your TUN/TAP device manually or use an --up script.");
|
||||
#endif
|
||||
argv_reset (&argv);
|
||||
}
|
||||
gc_free (&gc);
|
||||
}
|
||||
@ -1216,13 +1237,14 @@ close_tun (struct tuntap *tt)
|
||||
{
|
||||
if (tt->type != DEV_TYPE_NULL && tt->did_ifconfig)
|
||||
{
|
||||
char command_line[256];
|
||||
struct argv argv;
|
||||
struct gc_arena gc = gc_new ();
|
||||
argv_init (&argv);
|
||||
|
||||
#ifdef CONFIG_FEATURE_IPROUTE
|
||||
if (is_tun_p2p (tt))
|
||||
{
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
argv_printf (&argv,
|
||||
"%s addr del dev %s local %s peer %s",
|
||||
iproute_path,
|
||||
tt->actual_name,
|
||||
@ -1232,7 +1254,7 @@ close_tun (struct tuntap *tt)
|
||||
}
|
||||
else
|
||||
{
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
argv_printf (&argv,
|
||||
"%s addr del dev %s %s/%d",
|
||||
iproute_path,
|
||||
tt->actual_name,
|
||||
@ -1241,15 +1263,17 @@ close_tun (struct tuntap *tt)
|
||||
);
|
||||
}
|
||||
#else
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s 0.0.0.0",
|
||||
argv_printf (&argv,
|
||||
"%s %s 0.0.0.0",
|
||||
IFCONFIG_PATH,
|
||||
tt->actual_name
|
||||
);
|
||||
#endif
|
||||
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, NULL, 0, "Linux ip addr del failed");
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, NULL, 0, "Linux ip addr del failed");
|
||||
|
||||
argv_reset (&argv);
|
||||
gc_free (&gc);
|
||||
}
|
||||
close_tun_generic (tt);
|
||||
@ -1471,16 +1495,19 @@ close_tun (struct tuntap *tt)
|
||||
static void
|
||||
solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual)
|
||||
{
|
||||
char command_line[256];
|
||||
struct argv argv;
|
||||
argv_init (&argv);
|
||||
|
||||
openvpn_snprintf (command_line, sizeof (command_line),
|
||||
IFCONFIG_PATH " %s unplumb",
|
||||
argv_printf (&argv,
|
||||
"%s %s unplumb",
|
||||
IFCONFIG_PATH,
|
||||
actual);
|
||||
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, es, 0, "Solaris ifconfig unplumb failed");
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, 0, "Solaris ifconfig unplumb failed");
|
||||
close_tun (tt);
|
||||
msg (M_FATAL, "Solaris ifconfig failed");
|
||||
argv_reset (&argv);
|
||||
}
|
||||
|
||||
int
|
||||
@ -3275,7 +3302,7 @@ dhcp_renew (const struct tuntap *tt)
|
||||
*/
|
||||
|
||||
static void
|
||||
netsh_command (const char *cmd, int n)
|
||||
netsh_command (const struct argv *a, int n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; ++i)
|
||||
@ -3283,8 +3310,8 @@ netsh_command (const char *cmd, int n)
|
||||
bool status;
|
||||
openvpn_sleep (1);
|
||||
netcmd_semaphore_lock ();
|
||||
msg (M_INFO, "NETSH: %s", cmd);
|
||||
status = system_check (cmd, NULL, 0, "ERROR: netsh command failed");
|
||||
argv_msg_prefix (M_INFO, a, "NETSH");
|
||||
status = openvpn_execve_check (a, NULL, 0, "ERROR: netsh command failed");
|
||||
netcmd_semaphore_release ();
|
||||
if (status)
|
||||
return;
|
||||
@ -3376,7 +3403,7 @@ netsh_ifconfig_options (const char *type,
|
||||
const bool test_first)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
struct buffer out = alloc_buf_gc (256, &gc);
|
||||
struct argv argv = argv_new ();
|
||||
bool delete_first = false;
|
||||
|
||||
/* first check if we should delete existing DNS/WINS settings from TAP interface */
|
||||
@ -3391,11 +3418,12 @@ netsh_ifconfig_options (const char *type,
|
||||
/* delete existing DNS/WINS settings from TAP interface */
|
||||
if (delete_first)
|
||||
{
|
||||
buf_init (&out, 0);
|
||||
buf_printf (&out, "netsh interface ip delete %s \"%s\" all",
|
||||
type,
|
||||
flex_name);
|
||||
netsh_command (BSTR(&out), 2);
|
||||
argv_printf (&argv, "%s%s interface ip delete %s %s all",
|
||||
get_win_sys_path(),
|
||||
NETSH_PATH_SUFFIX,
|
||||
type,
|
||||
flex_name);
|
||||
netsh_command (&argv, 2);
|
||||
}
|
||||
|
||||
/* add new DNS/WINS settings to TAP interface */
|
||||
@ -3407,15 +3435,16 @@ netsh_ifconfig_options (const char *type,
|
||||
if (delete_first || !test_first || !ip_addr_member_of (addr_list[i], current))
|
||||
{
|
||||
const char *fmt = count ?
|
||||
"netsh interface ip add %s \"%s\" %s"
|
||||
: "netsh interface ip set %s \"%s\" static %s";
|
||||
"%s%s interface ip add %s %s %s"
|
||||
: "%s%s interface ip set %s %s static %s";
|
||||
|
||||
buf_init (&out, 0);
|
||||
buf_printf (&out, fmt,
|
||||
type,
|
||||
flex_name,
|
||||
print_in_addr_t (addr_list[i], 0, &gc));
|
||||
netsh_command (BSTR(&out), 2);
|
||||
argv_printf (&argv, fmt,
|
||||
get_win_sys_path(),
|
||||
NETSH_PATH_SUFFIX,
|
||||
type,
|
||||
flex_name,
|
||||
print_in_addr_t (addr_list[i], 0, &gc));
|
||||
netsh_command (&argv, 2);
|
||||
|
||||
++count;
|
||||
}
|
||||
@ -3429,6 +3458,7 @@ netsh_ifconfig_options (const char *type,
|
||||
}
|
||||
}
|
||||
|
||||
argv_reset (&argv);
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
@ -3458,7 +3488,7 @@ netsh_ifconfig (const struct tuntap_options *to,
|
||||
const unsigned int flags)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
struct buffer out = alloc_buf_gc (256, &gc);
|
||||
struct argv argv = argv_new ();
|
||||
const IP_ADAPTER_INFO *ai = NULL;
|
||||
const IP_PER_ADAPTER_INFO *pai = NULL;
|
||||
|
||||
@ -3482,14 +3512,15 @@ netsh_ifconfig (const struct tuntap_options *to,
|
||||
else
|
||||
{
|
||||
/* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */
|
||||
buf_init (&out, 0);
|
||||
buf_printf (&out,
|
||||
"netsh interface ip set address \"%s\" static %s %s",
|
||||
flex_name,
|
||||
print_in_addr_t (ip, 0, &gc),
|
||||
print_in_addr_t (netmask, 0, &gc));
|
||||
argv_printf (&argv,
|
||||
"%s%s interface ip set address %s static %s %s",
|
||||
get_win_sys_path(),
|
||||
NETSH_PATH_SUFFIX,
|
||||
flex_name,
|
||||
print_in_addr_t (ip, 0, &gc),
|
||||
print_in_addr_t (netmask, 0, &gc));
|
||||
|
||||
netsh_command (BSTR(&out), 4);
|
||||
netsh_command (&argv, 4);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3517,6 +3548,7 @@ netsh_ifconfig (const struct tuntap_options *to,
|
||||
BOOL_CAST (flags & NI_TEST_FIRST));
|
||||
}
|
||||
|
||||
argv_reset (&argv);
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
@ -3524,17 +3556,19 @@ static void
|
||||
netsh_enable_dhcp (const struct tuntap_options *to,
|
||||
const char *actual_name)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
struct buffer out = alloc_buf_gc (256, &gc);
|
||||
struct argv argv;
|
||||
argv_init (&argv);
|
||||
|
||||
/* example: netsh interface ip set address my-tap dhcp */
|
||||
buf_printf (&out,
|
||||
"netsh interface ip set address \"%s\" dhcp",
|
||||
actual_name);
|
||||
argv_printf (&argv,
|
||||
"%s%s interface ip set address %s dhcp",
|
||||
get_win_sys_path(),
|
||||
NETSH_PATH_SUFFIX,
|
||||
actual_name);
|
||||
|
||||
netsh_command (BSTR(&out), 4);
|
||||
netsh_command (&argv, 4);
|
||||
|
||||
gc_free (&gc);
|
||||
argv_reset (&argv);
|
||||
}
|
||||
|
||||
/*
|
||||
|
177
win32.c
177
win32.c
@ -35,6 +35,7 @@
|
||||
#include "mtu.h"
|
||||
#include "sig.h"
|
||||
#include "win32.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include "memdbg.h"
|
||||
|
||||
@ -69,6 +70,11 @@ struct window_title window_title; /* GLOBAL*/
|
||||
|
||||
struct semaphore netcmd_semaphore; /* GLOBAL */
|
||||
|
||||
/*
|
||||
* Windows system pathname such as c:\windows
|
||||
*/
|
||||
static char *win_sys_path = NULL; /* GLOBAL */
|
||||
|
||||
void
|
||||
init_win32 (void)
|
||||
{
|
||||
@ -100,6 +106,7 @@ uninit_win32 (void)
|
||||
window_title_restore (&window_title);
|
||||
win32_signal_close (&win32_signal);
|
||||
WSACleanup ();
|
||||
free (win_sys_path);
|
||||
}
|
||||
|
||||
void
|
||||
@ -816,4 +823,174 @@ win_safe_filename (const char *fn)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Service functions for openvpn_execve
|
||||
*/
|
||||
|
||||
static char *
|
||||
env_block (const struct env_set *es)
|
||||
{
|
||||
if (es)
|
||||
{
|
||||
struct env_item *e;
|
||||
char *ret;
|
||||
char *p;
|
||||
size_t nchars = 1;
|
||||
|
||||
for (e = es->list; e != NULL; e = e->next)
|
||||
nchars += strlen (e->string) + 1;
|
||||
|
||||
ret = (char *) malloc (nchars);
|
||||
check_malloc_return (ret);
|
||||
|
||||
p = ret;
|
||||
for (e = es->list; e != NULL; e = e->next)
|
||||
{
|
||||
if (env_allowed (e->string))
|
||||
{
|
||||
strcpy (p, e->string);
|
||||
p += strlen (e->string) + 1;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
cmd_line (const struct argv *a)
|
||||
{
|
||||
size_t nchars = 1;
|
||||
size_t maxlen = 0;
|
||||
size_t i;
|
||||
struct buffer buf;
|
||||
char *work = NULL;
|
||||
|
||||
if (!a)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < a->argc; ++i)
|
||||
{
|
||||
const char *arg = a->argv[i];
|
||||
const size_t len = strlen (arg);
|
||||
nchars += len + 3;
|
||||
if (len > maxlen)
|
||||
maxlen = len;
|
||||
}
|
||||
|
||||
work = (char *) malloc (maxlen + 1);
|
||||
check_malloc_return (work);
|
||||
buf = alloc_buf (nchars);
|
||||
|
||||
for (i = 0; i < a->argc; ++i)
|
||||
{
|
||||
const char *arg = a->argv[i];
|
||||
strcpy (work, arg);
|
||||
string_mod (work, CC_PRINT, CC_DOUBLE_QUOTE|CC_CRLF, '_');
|
||||
if (i)
|
||||
buf_printf (&buf, " ");
|
||||
if (string_class (work, CC_ANY, CC_SPACE))
|
||||
buf_printf (&buf, "%s", work);
|
||||
else
|
||||
buf_printf (&buf, "\"%s\"", work);
|
||||
}
|
||||
|
||||
free (work);
|
||||
return BSTR(&buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to simulate fork/execve on Windows
|
||||
*/
|
||||
int
|
||||
openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags)
|
||||
{
|
||||
int ret = -1;
|
||||
if (a && a->argv[0])
|
||||
{
|
||||
if (openvpn_execve_allowed (flags))
|
||||
{
|
||||
STARTUPINFO start_info;
|
||||
PROCESS_INFORMATION proc_info;
|
||||
|
||||
char *env = env_block (es);
|
||||
char *cl = cmd_line (a);
|
||||
char *cmd = a->argv[0];
|
||||
|
||||
CLEAR (start_info);
|
||||
CLEAR (proc_info);
|
||||
|
||||
/* fill in STARTUPINFO struct */
|
||||
GetStartupInfo(&start_info);
|
||||
start_info.cb = sizeof(start_info);
|
||||
start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
|
||||
start_info.wShowWindow = SW_HIDE;
|
||||
start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
start_info.hStdOutput = start_info.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (CreateProcess (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info))
|
||||
{
|
||||
DWORD exit_status = 0;
|
||||
CloseHandle (proc_info.hThread);
|
||||
WaitForSingleObject (proc_info.hProcess, INFINITE);
|
||||
if (GetExitCodeProcess (proc_info.hProcess, &exit_status))
|
||||
ret = (int)exit_status;
|
||||
else
|
||||
msg (M_WARN|M_ERRNO, "openvpn_execve: GetExitCodeProcess %s failed", cmd);
|
||||
CloseHandle (proc_info.hProcess);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %s failed", cmd);
|
||||
}
|
||||
free (cl);
|
||||
free (env);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_WARN, "openvpn_execve: external program may not be called due to setting of --script-security level");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_WARN, "openvpn_execve: called with empty argv");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
get_win_sys_path (void)
|
||||
{
|
||||
ASSERT (win_sys_path);
|
||||
return win_sys_path;
|
||||
}
|
||||
|
||||
void
|
||||
set_win_sys_path (const char *newpath, struct env_set *es)
|
||||
{
|
||||
free (win_sys_path);
|
||||
win_sys_path = string_alloc (newpath, NULL);
|
||||
setenv_str (es, SYS_PATH_ENV_VAR_NAME, win_sys_path); /* route.exe needs this */
|
||||
}
|
||||
|
||||
void
|
||||
set_win_sys_path_via_env (struct env_set *es)
|
||||
{
|
||||
char buf[256];
|
||||
DWORD status = GetEnvironmentVariable (SYS_PATH_ENV_VAR_NAME, buf, sizeof(buf));
|
||||
if (!status)
|
||||
msg (M_ERR, "Cannot find environmental variable %s", SYS_PATH_ENV_VAR_NAME);
|
||||
if (status > sizeof (buf) - 1)
|
||||
msg (M_FATAL, "String overflow attempting to read environmental variable %s", SYS_PATH_ENV_VAR_NAME);
|
||||
set_win_sys_path (buf, es);
|
||||
}
|
||||
|
||||
void
|
||||
env_set_add_win32 (struct env_set *es)
|
||||
{
|
||||
set_win_sys_path (DEFAULT_WIN_SYS_PATH, es);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
15
win32.h
15
win32.h
@ -28,6 +28,12 @@
|
||||
|
||||
#include "mtu.h"
|
||||
|
||||
/* location of executables */
|
||||
#define SYS_PATH_ENV_VAR_NAME "SystemRoot" /* environmental variable name that normally contains the system path */
|
||||
#define DEFAULT_WIN_SYS_PATH "C:\\WINDOWS" /* --win-sys default value */
|
||||
#define NETSH_PATH_SUFFIX "\\system32\\netsh.exe"
|
||||
#define WIN_ROUTE_PATH_SUFFIX "\\system32\\route.exe"
|
||||
|
||||
/*
|
||||
* Win32-specific OpenVPN code, targetted at the mingw
|
||||
* development environment.
|
||||
@ -250,5 +256,14 @@ bool init_security_attributes_allow_all (struct security_attributes *obj);
|
||||
/* return true if filename is safe to be used on Windows */
|
||||
bool win_safe_filename (const char *fn);
|
||||
|
||||
/* add constant environmental variables needed by Windows */
|
||||
struct env_set;
|
||||
void env_set_add_win32 (struct env_set *es);
|
||||
|
||||
/* get and set the current windows system path */
|
||||
void set_win_sys_path (const char *newpath, struct env_set *es);
|
||||
void set_win_sys_path_via_env (struct env_set *es);
|
||||
char *get_win_sys_path (void);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user