* 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
| ... | ... |
@@ -240,6 +240,14 @@ argv_init (struct argv *a) |
| 240 | 240 |
a->argv = NULL; |
| 241 | 241 |
} |
| 242 | 242 |
|
| 243 |
+struct argv |
|
| 244 |
+argv_new (void) |
|
| 245 |
+{
|
|
| 246 |
+ struct argv ret; |
|
| 247 |
+ argv_init (&ret); |
|
| 248 |
+ return ret; |
|
| 249 |
+} |
|
| 250 |
+ |
|
| 243 | 251 |
void |
| 244 | 252 |
argv_reset (struct argv *a) |
| 245 | 253 |
{
|
| ... | ... |
@@ -266,6 +274,23 @@ argv_argc (const char *format) |
| 266 | 266 |
return argc; |
| 267 | 267 |
} |
| 268 | 268 |
|
| 269 |
+struct argv |
|
| 270 |
+argv_insert_head (const struct argv *a, const char *head) |
|
| 271 |
+{
|
|
| 272 |
+ struct argv r; |
|
| 273 |
+ size_t i; |
|
| 274 |
+ |
|
| 275 |
+ r.argc = (a ? a->argc : 0) + 1; |
|
| 276 |
+ ALLOC_ARRAY_CLEAR (r.argv, char *, r.argc + 1); |
|
| 277 |
+ r.argv[0] = string_alloc (head, NULL); |
|
| 278 |
+ if (a) |
|
| 279 |
+ {
|
|
| 280 |
+ for (i = 0; i < a->argc; ++i) |
|
| 281 |
+ r.argv[i+1] = string_alloc (a->argv[i], NULL); |
|
| 282 |
+ } |
|
| 283 |
+ return r; |
|
| 284 |
+} |
|
| 285 |
+ |
|
| 269 | 286 |
char * |
| 270 | 287 |
argv_term (const char **f) |
| 271 | 288 |
{
|
| ... | ... |
@@ -324,6 +349,22 @@ argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags) |
| 324 | 324 |
} |
| 325 | 325 |
|
| 326 | 326 |
void |
| 327 |
+argv_msg (const int msglev, const struct argv *a) |
|
| 328 |
+{
|
|
| 329 |
+ struct gc_arena gc = gc_new (); |
|
| 330 |
+ msg (msglev, "%s", argv_str (a, &gc, 0)); |
|
| 331 |
+ gc_free (&gc); |
|
| 332 |
+} |
|
| 333 |
+ |
|
| 334 |
+void |
|
| 335 |
+argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix) |
|
| 336 |
+{
|
|
| 337 |
+ struct gc_arena gc = gc_new (); |
|
| 338 |
+ msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0)); |
|
| 339 |
+ gc_free (&gc); |
|
| 340 |
+} |
|
| 341 |
+ |
|
| 342 |
+void |
|
| 327 | 343 |
argv_printf (struct argv *a, const char *format, ...) |
| 328 | 344 |
{
|
| 329 | 345 |
va_list arglist; |
| ... | ... |
@@ -373,7 +414,10 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag |
| 373 | 373 |
{
|
| 374 | 374 |
if (!strcmp (term, "%s")) |
| 375 | 375 |
{
|
| 376 |
- a->argv[argc++] = string_alloc (va_arg (arglist, char *), NULL); |
|
| 376 |
+ char *s = va_arg (arglist, char *); |
|
| 377 |
+ if (!s) |
|
| 378 |
+ s = ""; |
|
| 379 |
+ a->argv[argc++] = string_alloc (s, NULL); |
|
| 377 | 380 |
} |
| 378 | 381 |
else if (!strcmp (term, "%d")) |
| 379 | 382 |
{
|
| ... | ... |
@@ -387,6 +431,41 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag |
| 387 | 387 |
openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int)); |
| 388 | 388 |
a->argv[argc++] = string_alloc (numstr, NULL); |
| 389 | 389 |
} |
| 390 |
+ else if (!strcmp (term, "%s/%d")) |
|
| 391 |
+ {
|
|
| 392 |
+ char numstr[64]; |
|
| 393 |
+ char *s = va_arg (arglist, char *); |
|
| 394 |
+ |
|
| 395 |
+ if (!s) |
|
| 396 |
+ s = ""; |
|
| 397 |
+ |
|
| 398 |
+ openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int)); |
|
| 399 |
+ |
|
| 400 |
+ {
|
|
| 401 |
+ const size_t len = strlen(s) + strlen(numstr) + 2; |
|
| 402 |
+ char *combined = (char *) malloc (len); |
|
| 403 |
+ check_malloc_return (combined); |
|
| 404 |
+ |
|
| 405 |
+ strcpy (combined, s); |
|
| 406 |
+ strcat (combined, "/"); |
|
| 407 |
+ strcat (combined, numstr); |
|
| 408 |
+ a->argv[argc++] = combined; |
|
| 409 |
+ } |
|
| 410 |
+ } |
|
| 411 |
+ else if (!strcmp (term, "%s%s")) |
|
| 412 |
+ {
|
|
| 413 |
+ char *s1 = va_arg (arglist, char *); |
|
| 414 |
+ char *s2 = va_arg (arglist, char *); |
|
| 415 |
+ char *combined; |
|
| 416 |
+ |
|
| 417 |
+ if (!s1) s1 = ""; |
|
| 418 |
+ if (!s2) s2 = ""; |
|
| 419 |
+ combined = (char *) malloc (strlen(s1) + strlen(s2) + 1); |
|
| 420 |
+ check_malloc_return (combined); |
|
| 421 |
+ strcpy (combined, s1); |
|
| 422 |
+ strcat (combined, s2); |
|
| 423 |
+ a->argv[argc++] = combined; |
|
| 424 |
+ } |
|
| 390 | 425 |
else |
| 391 | 426 |
ASSERT (0); |
| 392 | 427 |
free (term); |
| ... | ... |
@@ -399,57 +478,6 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag |
| 399 | 399 |
ASSERT (argc == a->argc); |
| 400 | 400 |
} |
| 401 | 401 |
|
| 402 |
-#ifdef ARGV_TEST |
|
| 403 |
-void |
|
| 404 |
-argv_test (void) |
|
| 405 |
-{
|
|
| 406 |
- struct gc_arena gc = gc_new (); |
|
| 407 |
- char line[512]; |
|
| 408 |
- const char *s; |
|
| 409 |
- |
|
| 410 |
- struct argv a; |
|
| 411 |
- argv_init (&a); |
|
| 412 |
- argv_printf (&a, "this is a %s test of int %d unsigned %u", "FOO", -69, 42); |
|
| 413 |
- s = argv_str (&a, &gc, PA_BRACKET); |
|
| 414 |
- argv_reset (&a); |
|
| 415 |
- printf ("%s\n", s);
|
|
| 416 |
- |
|
| 417 |
- argv_init (&a); |
|
| 418 |
- argv_printf (&a, "foo bar %d", 99); |
|
| 419 |
- s = argv_str (&a, &gc, PA_BRACKET); |
|
| 420 |
- argv_reset (&a); |
|
| 421 |
- printf ("%s\n", s);
|
|
| 422 |
- |
|
| 423 |
- argv_init (&a); |
|
| 424 |
- s = argv_str (&a, &gc, PA_BRACKET); |
|
| 425 |
- argv_reset (&a); |
|
| 426 |
- printf ("%s\n", s);
|
|
| 427 |
- |
|
| 428 |
- argv_init (&a); |
|
| 429 |
- argv_printf (&a, "foo bar %d", 99); |
|
| 430 |
- argv_printf_cat (&a, "bar %d foo", 42); |
|
| 431 |
- argv_printf_cat (&a, "cool %s %d u", "frood", 4); |
|
| 432 |
- s = argv_str (&a, &gc, PA_BRACKET); |
|
| 433 |
- argv_reset (&a); |
|
| 434 |
- printf ("%s\n", s);
|
|
| 435 |
- |
|
| 436 |
- while (fgets (line, sizeof(line), stdin) != NULL) |
|
| 437 |
- {
|
|
| 438 |
- char *term; |
|
| 439 |
- const char *f = line; |
|
| 440 |
- int i = 0; |
|
| 441 |
- |
|
| 442 |
- while ((term = argv_term (&f)) != NULL) |
|
| 443 |
- {
|
|
| 444 |
- printf ("[%d] '%s'\n", i, term);
|
|
| 445 |
- ++i; |
|
| 446 |
- free (term); |
|
| 447 |
- } |
|
| 448 |
- } |
|
| 449 |
- gc_free (&gc); |
|
| 450 |
-} |
|
| 451 |
-#endif |
|
| 452 |
- |
|
| 453 | 402 |
/* |
| 454 | 403 |
* write a string to the end of a buffer that was |
| 455 | 404 |
* truncated by buf_printf |
| ... | ... |
@@ -234,10 +234,14 @@ int openvpn_snprintf(char *str, size_t size, const char *format, ...) |
| 234 | 234 |
* to execve. |
| 235 | 235 |
*/ |
| 236 | 236 |
void argv_init (struct argv *a); |
| 237 |
+struct argv argv_new (void); |
|
| 237 | 238 |
void argv_reset (struct argv *a); |
| 238 | 239 |
size_t argv_argc (const char *format); |
| 239 | 240 |
char *argv_term (const char **f); |
| 240 | 241 |
const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags); |
| 242 |
+struct argv argv_insert_head (const struct argv *a, const char *head); |
|
| 243 |
+void argv_msg (const int msglev, const struct argv *a); |
|
| 244 |
+void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix); |
|
| 241 | 245 |
|
| 242 | 246 |
#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */ |
| 243 | 247 |
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 |
| 462 | 462 |
getpass strerror syslog openlog mlockall getgrnam setgid dnl |
| 463 | 463 |
setgroups stat flock readv writev setsockopt getsockopt dnl |
| 464 | 464 |
setsid chdir putenv getpeername unlink dnl |
| 465 |
- poll chsize ftruncate sendmsg recvmsg getsockname) |
|
| 465 |
+ poll chsize ftruncate sendmsg recvmsg getsockname dnl |
|
| 466 |
+ execve) |
|
| 466 | 467 |
AC_CACHE_SAVE |
| 467 | 468 |
|
| 468 | 469 |
if test "${WIN32}" = "yes"; then
|
| ... | ... |
@@ -399,6 +399,24 @@ |
| 399 | 399 |
obj:/lib/ld-2.5.so |
| 400 | 400 |
obj:/lib/ld-2.5.so |
| 401 | 401 |
obj:/lib/ld-2.5.so |
| 402 |
+ obj:/lib/libc-2.5.so |
|
| 403 |
+ obj:/lib/libdl-2.5.so |
|
| 404 |
+ obj:/lib/ld-2.5.so |
|
| 405 |
+ obj:/lib/libdl-2.5.so |
|
| 406 |
+ fun:dlsym |
|
| 407 |
+ fun:libdl_resolve_symbol |
|
| 408 |
+ fun:plugin_list_init |
|
| 409 |
+ fun:init_plugins |
|
| 410 |
+ fun:main |
|
| 411 |
+} |
|
| 412 |
+ |
|
| 413 |
+{
|
|
| 414 |
+ <insert a suppression name here> |
|
| 415 |
+ Memcheck:Cond |
|
| 416 |
+ obj:/lib/ld-2.5.so |
|
| 417 |
+ obj:/lib/ld-2.5.so |
|
| 418 |
+ obj:/lib/ld-2.5.so |
|
| 419 |
+ obj:/lib/ld-2.5.so |
|
| 402 | 420 |
obj:/lib/libdl-2.5.so |
| 403 | 421 |
obj:/lib/ld-2.5.so |
| 404 | 422 |
obj:/lib/libdl-2.5.so |
| ... | ... |
@@ -370,7 +370,7 @@ init_port_share (struct context *c) |
| 370 | 370 |
bool |
| 371 | 371 |
init_static (void) |
| 372 | 372 |
{
|
| 373 |
- configure_path (); |
|
| 373 |
+ /* configure_path (); */ |
|
| 374 | 374 |
|
| 375 | 375 |
#if defined(USE_CRYPTO) && defined(DMALLOC) |
| 376 | 376 |
openssl_dmalloc_init (); |
| ... | ... |
@@ -921,8 +921,11 @@ do_route (const struct options *options, |
| 921 | 921 |
|
| 922 | 922 |
if (options->route_script) |
| 923 | 923 |
{
|
| 924 |
+ struct argv argv = argv_new (); |
|
| 924 | 925 |
setenv_str (es, "script_type", "route-up"); |
| 925 |
- system_check (options->route_script, es, S_SCRIPT, "Route script failed"); |
|
| 926 |
+ argv_printf (&argv, "%s", options->route_script); |
|
| 927 |
+ openvpn_execve_check (&argv, es, S_SCRIPT, "Route script failed"); |
|
| 928 |
+ argv_reset (&argv); |
|
| 926 | 929 |
} |
| 927 | 930 |
|
| 928 | 931 |
#ifdef WIN32 |
| ... | ... |
@@ -9,7 +9,7 @@ |
| 9 | 9 |
int set_lladdr(const char *ifname, const char *lladdr, |
| 10 | 10 |
const struct env_set *es) |
| 11 | 11 |
{
|
| 12 |
- char cmd[256]; |
|
| 12 |
+ struct argv argv = argv_new (); |
|
| 13 | 13 |
int r; |
| 14 | 14 |
|
| 15 | 15 |
if (!ifname || !lladdr) |
| ... | ... |
@@ -17,37 +17,45 @@ int set_lladdr(const char *ifname, const char *lladdr, |
| 17 | 17 |
|
| 18 | 18 |
#if defined(TARGET_LINUX) |
| 19 | 19 |
#ifdef CONFIG_FEATURE_IPROUTE |
| 20 |
- openvpn_snprintf (cmd, sizeof (cmd), |
|
| 20 |
+ argv_printf (&argv, |
|
| 21 | 21 |
"%s link set addr %s dev %s", |
| 22 | 22 |
iproute_path, lladdr, ifname); |
| 23 | 23 |
#else |
| 24 |
- openvpn_snprintf (cmd, sizeof (cmd), |
|
| 25 |
- IFCONFIG_PATH " %s hw ether %s", |
|
| 24 |
+ argv_printf (&argv, |
|
| 25 |
+ "%s %s hw ether %s", |
|
| 26 |
+ IFCONFIG_PATH, |
|
| 26 | 27 |
ifname, lladdr); |
| 27 | 28 |
#endif |
| 28 | 29 |
#elif defined(TARGET_SOLARIS) |
| 29 |
- openvpn_snprintf (cmd, sizeof (cmd), |
|
| 30 |
- IFCONFIG_PATH " %s ether %s", |
|
| 30 |
+ argv_printf (&argv, |
|
| 31 |
+ "%s %s ether %s", |
|
| 32 |
+ IFCONFIG_PATH, |
|
| 31 | 33 |
ifname, lladdr); |
| 32 | 34 |
#elif defined(TARGET_OPENBSD) |
| 33 |
- openvpn_snprintf (cmd, sizeof (cmd), |
|
| 34 |
- IFCONFIG_PATH " %s lladdr %s", |
|
| 35 |
+ argv_printf (&argv, |
|
| 36 |
+ "%s %s lladdr %s", |
|
| 37 |
+ IFCONFIG_PATH, |
|
| 35 | 38 |
ifname, lladdr); |
| 36 | 39 |
#elif defined(TARGET_DARWIN) |
| 37 |
- openvpn_snprintf (cmd, sizeof (cmd), |
|
| 38 |
- IFCONFIG_PATH " %s lladdr %s", |
|
| 40 |
+ argv_printf (&argv, |
|
| 41 |
+ "%s %s lladdr %s", |
|
| 42 |
+ IFCONFIG_PATH, |
|
| 39 | 43 |
ifname, lladdr); |
| 40 | 44 |
#elif defined(TARGET_FREEBSD) |
| 41 |
- openvpn_snprintf (cmd, sizeof (cmd), |
|
| 42 |
- IFCONFIG_PATH " %s ether %s", |
|
| 45 |
+ argv_printf (&argv, |
|
| 46 |
+ "%s %s ether %s", |
|
| 47 |
+ IFCONFIG_PATH, |
|
| 43 | 48 |
ifname, lladdr); |
| 44 | 49 |
#else |
| 45 | 50 |
msg (M_WARN, "Sorry, but I don't know how to configure link layer addresses on this operating system."); |
| 46 | 51 |
return -1; |
| 47 | 52 |
#endif |
| 48 | 53 |
|
| 49 |
- r = system_check (cmd, es, M_WARN, "ERROR: Unable to set link layer address."); |
|
| 54 |
+ argv_msg (M_INFO, &argv); |
|
| 55 |
+ r = openvpn_execve_check (&argv, es, M_WARN, "ERROR: Unable to set link layer address."); |
|
| 50 | 56 |
if (r) |
| 51 | 57 |
msg (M_INFO, "TUN/TAP link layer address set to %s", lladdr); |
| 58 |
+ |
|
| 59 |
+ argv_reset (&argv); |
|
| 52 | 60 |
return r; |
| 53 | 61 |
} |
| ... | ... |
@@ -43,6 +43,9 @@ |
| 43 | 43 |
const char *iproute_path = IPROUTE_PATH; |
| 44 | 44 |
#endif |
| 45 | 45 |
|
| 46 |
+/* contains an SSEC_x value defined in misc.h */ |
|
| 47 |
+int script_security = SSEC_BUILT_IN; /* GLOBAL */ |
|
| 48 |
+ |
|
| 46 | 49 |
/* Redefine the top level directory of the filesystem |
| 47 | 50 |
to restrict access to files for security */ |
| 48 | 51 |
void |
| ... | ... |
@@ -196,38 +199,36 @@ run_up_down (const char *command, |
| 196 | 196 |
|
| 197 | 197 |
if (plugin_defined (plugins, plugin_type)) |
| 198 | 198 |
{
|
| 199 |
- struct buffer cmd = alloc_buf_gc (256, &gc); |
|
| 200 |
- |
|
| 199 |
+ struct argv argv = argv_new (); |
|
| 201 | 200 |
ASSERT (arg); |
| 202 |
- |
|
| 203 |
- buf_printf (&cmd, |
|
| 204 |
- "\"%s\" %d %d %s %s %s", |
|
| 205 |
- arg, |
|
| 206 |
- tun_mtu, link_mtu, |
|
| 207 |
- ifconfig_local, ifconfig_remote, |
|
| 208 |
- context); |
|
| 209 |
- |
|
| 210 |
- if (plugin_call (plugins, plugin_type, BSTR (&cmd), NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 201 |
+ argv_printf (&argv, |
|
| 202 |
+ "%s %d %d %s %s %s", |
|
| 203 |
+ arg, |
|
| 204 |
+ tun_mtu, link_mtu, |
|
| 205 |
+ ifconfig_local, ifconfig_remote, |
|
| 206 |
+ context); |
|
| 207 |
+ |
|
| 208 |
+ if (plugin_call (plugins, plugin_type, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 211 | 209 |
msg (M_FATAL, "ERROR: up/down plugin call failed"); |
| 210 |
+ |
|
| 211 |
+ argv_reset (&argv); |
|
| 212 | 212 |
} |
| 213 | 213 |
|
| 214 | 214 |
if (command) |
| 215 | 215 |
{
|
| 216 |
- struct buffer cmd = alloc_buf_gc (256, &gc); |
|
| 217 |
- |
|
| 216 |
+ struct argv argv = argv_new (); |
|
| 218 | 217 |
ASSERT (arg); |
| 219 |
- |
|
| 220 | 218 |
setenv_str (es, "script_type", script_type); |
| 221 |
- |
|
| 222 |
- buf_printf (&cmd, |
|
| 223 |
- "%s \"%s\" %d %d %s %s %s", |
|
| 219 |
+ argv_printf (&argv, |
|
| 220 |
+ "%s %s %d %d %s %s %s", |
|
| 224 | 221 |
command, |
| 225 | 222 |
arg, |
| 226 | 223 |
tun_mtu, link_mtu, |
| 227 | 224 |
ifconfig_local, ifconfig_remote, |
| 228 | 225 |
context); |
| 229 |
- msg (M_INFO, "%s", BSTR (&cmd)); |
|
| 230 |
- system_check (BSTR (&cmd), es, S_SCRIPT|S_FATAL, "script failed"); |
|
| 226 |
+ argv_msg (M_INFO, &argv); |
|
| 227 |
+ openvpn_execve_check (&argv, es, S_SCRIPT|S_FATAL, "script failed"); |
|
| 228 |
+ argv_reset (&argv); |
|
| 231 | 229 |
} |
| 232 | 230 |
|
| 233 | 231 |
gc_free (&gc); |
| ... | ... |
@@ -375,59 +376,6 @@ save_inetd_socket_descriptor (void) |
| 375 | 375 |
} |
| 376 | 376 |
|
| 377 | 377 |
/* |
| 378 |
- * Wrapper around the system() call. |
|
| 379 |
- */ |
|
| 380 |
-int |
|
| 381 |
-openvpn_system (const char *command, const struct env_set *es, unsigned int flags) |
|
| 382 |
-{
|
|
| 383 |
-#ifdef HAVE_SYSTEM |
|
| 384 |
- int ret; |
|
| 385 |
- |
|
| 386 |
- /* |
|
| 387 |
- * We need to bracket this code by mutex because system() doesn't |
|
| 388 |
- * accept an environment list, so we have to use the process-wide |
|
| 389 |
- * list which is shared between all threads. |
|
| 390 |
- */ |
|
| 391 |
- mutex_lock_static (L_SYSTEM); |
|
| 392 |
- perf_push (PERF_SCRIPT); |
|
| 393 |
- |
|
| 394 |
- /* |
|
| 395 |
- * add env_set to environment. |
|
| 396 |
- */ |
|
| 397 |
- if (flags & S_SCRIPT) |
|
| 398 |
- env_set_add_to_environment (es); |
|
| 399 |
- |
|
| 400 |
- |
|
| 401 |
- /* debugging */ |
|
| 402 |
- dmsg (D_SCRIPT, "SYSTEM[%u] '%s'", flags, command); |
|
| 403 |
- if (flags & S_SCRIPT) |
|
| 404 |
- env_set_print (D_SCRIPT, es); |
|
| 405 |
- |
|
| 406 |
- /* |
|
| 407 |
- * execute the command |
|
| 408 |
- */ |
|
| 409 |
- ret = system (command); |
|
| 410 |
- |
|
| 411 |
- /* debugging */ |
|
| 412 |
- dmsg (D_SCRIPT, "SYSTEM return=%u", ret); |
|
| 413 |
- |
|
| 414 |
- /* |
|
| 415 |
- * remove env_set from environment |
|
| 416 |
- */ |
|
| 417 |
- if (flags & S_SCRIPT) |
|
| 418 |
- env_set_remove_from_environment (es); |
|
| 419 |
- |
|
| 420 |
- perf_pop (); |
|
| 421 |
- mutex_unlock_static (L_SYSTEM); |
|
| 422 |
- return ret; |
|
| 423 |
- |
|
| 424 |
-#else |
|
| 425 |
- 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); |
|
| 426 |
- return -1; /* NOTREACHED */ |
|
| 427 |
-#endif |
|
| 428 |
-} |
|
| 429 |
- |
|
| 430 |
-/* |
|
| 431 | 378 |
* Warn if a given file is group/others accessible. |
| 432 | 379 |
*/ |
| 433 | 380 |
void |
| ... | ... |
@@ -489,35 +437,35 @@ system_error_message (int stat, struct gc_arena *gc) |
| 489 | 489 |
struct buffer out = alloc_buf_gc (256, gc); |
| 490 | 490 |
#ifdef WIN32 |
| 491 | 491 |
if (stat == -1) |
| 492 |
- buf_printf (&out, "shell command did not execute -- "); |
|
| 493 |
- buf_printf (&out, "system() returned error code %d", stat); |
|
| 492 |
+ buf_printf (&out, "external program did not execute -- "); |
|
| 493 |
+ buf_printf (&out, "returned error code %d", stat); |
|
| 494 | 494 |
#else |
| 495 | 495 |
if (stat == -1) |
| 496 |
- buf_printf (&out, "shell command fork failed"); |
|
| 496 |
+ buf_printf (&out, "external program fork failed"); |
|
| 497 | 497 |
else if (!WIFEXITED (stat)) |
| 498 |
- buf_printf (&out, "shell command did not exit normally"); |
|
| 498 |
+ buf_printf (&out, "external program did not exit normally"); |
|
| 499 | 499 |
else |
| 500 | 500 |
{
|
| 501 | 501 |
const int cmd_ret = WEXITSTATUS (stat); |
| 502 | 502 |
if (!cmd_ret) |
| 503 |
- buf_printf (&out, "shell command exited normally"); |
|
| 503 |
+ buf_printf (&out, "external program exited normally"); |
|
| 504 | 504 |
else if (cmd_ret == 127) |
| 505 |
- buf_printf (&out, "could not execute shell command"); |
|
| 505 |
+ buf_printf (&out, "could not execute external program"); |
|
| 506 | 506 |
else |
| 507 |
- buf_printf (&out, "shell command exited with error status: %d", cmd_ret); |
|
| 507 |
+ buf_printf (&out, "external program exited with error status: %d", cmd_ret); |
|
| 508 | 508 |
} |
| 509 | 509 |
#endif |
| 510 | 510 |
return (const char *)out.data; |
| 511 | 511 |
} |
| 512 | 512 |
|
| 513 | 513 |
/* |
| 514 |
- * Run system(), exiting on error. |
|
| 514 |
+ * Wrapper around openvpn_execve |
|
| 515 | 515 |
*/ |
| 516 | 516 |
bool |
| 517 |
-system_check (const char *command, const struct env_set *es, unsigned int flags, const char *error_message) |
|
| 517 |
+openvpn_execve_check (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message) |
|
| 518 | 518 |
{
|
| 519 | 519 |
struct gc_arena gc = gc_new (); |
| 520 |
- const int stat = openvpn_system (command, es, flags); |
|
| 520 |
+ const int stat = openvpn_execve (a, es, flags); |
|
| 521 | 521 |
int ret = false; |
| 522 | 522 |
|
| 523 | 523 |
if (system_ok (stat)) |
| ... | ... |
@@ -533,6 +481,69 @@ system_check (const char *command, const struct env_set *es, unsigned int flags, |
| 533 | 533 |
return ret; |
| 534 | 534 |
} |
| 535 | 535 |
|
| 536 |
+bool |
|
| 537 |
+openvpn_execve_allowed (const unsigned int flags) |
|
| 538 |
+{
|
|
| 539 |
+ if (flags & S_SCRIPT) |
|
| 540 |
+ return script_security >= SSEC_SCRIPTS; |
|
| 541 |
+ else |
|
| 542 |
+ return script_security >= SSEC_BUILT_IN; |
|
| 543 |
+} |
|
| 544 |
+ |
|
| 545 |
+#ifndef WIN32 |
|
| 546 |
+/* |
|
| 547 |
+ * Run execve() inside a fork(). Designed to replicate the semantics of system() but |
|
| 548 |
+ * in a safer way that doesn't require the invocation of a shell or the risks |
|
| 549 |
+ * assocated with formatting and parsing a command line. |
|
| 550 |
+ */ |
|
| 551 |
+int |
|
| 552 |
+openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags) |
|
| 553 |
+{
|
|
| 554 |
+ struct gc_arena gc = gc_new (); |
|
| 555 |
+ int ret = -1; |
|
| 556 |
+ |
|
| 557 |
+ if (a && a->argv[0]) |
|
| 558 |
+ {
|
|
| 559 |
+#if defined(ENABLE_EXECVE) |
|
| 560 |
+ if (openvpn_execve_allowed (flags)) |
|
| 561 |
+ {
|
|
| 562 |
+ const char *cmd = a->argv[0]; |
|
| 563 |
+ char *const *argv = a->argv; |
|
| 564 |
+ char *const *envp = (char *const *)make_env_array (es, true, &gc); |
|
| 565 |
+ pid_t pid; |
|
| 566 |
+ |
|
| 567 |
+ pid = fork (); |
|
| 568 |
+ if (pid == (pid_t)0) /* child side */ |
|
| 569 |
+ {
|
|
| 570 |
+ execve (cmd, argv, envp); |
|
| 571 |
+ exit (127); |
|
| 572 |
+ } |
|
| 573 |
+ else if (pid < (pid_t)0) /* fork failed */ |
|
| 574 |
+ ; |
|
| 575 |
+ else /* parent side */ |
|
| 576 |
+ {
|
|
| 577 |
+ if (waitpid (pid, &ret, 0) != pid) |
|
| 578 |
+ ret = -1; |
|
| 579 |
+ } |
|
| 580 |
+ } |
|
| 581 |
+ else |
|
| 582 |
+ {
|
|
| 583 |
+ msg (M_WARN, "openvpn_execve: external program may not be called due to setting of --script-security level"); |
|
| 584 |
+ } |
|
| 585 |
+#else |
|
| 586 |
+ msg (M_WARN, "openvpn_execve: execve function not available"); |
|
| 587 |
+#endif |
|
| 588 |
+ } |
|
| 589 |
+ else |
|
| 590 |
+ {
|
|
| 591 |
+ msg (M_WARN, "openvpn_execve: called with empty argv"); |
|
| 592 |
+ } |
|
| 593 |
+ |
|
| 594 |
+ gc_free (&gc); |
|
| 595 |
+ return ret; |
|
| 596 |
+} |
|
| 597 |
+#endif |
|
| 598 |
+ |
|
| 536 | 599 |
/* |
| 537 | 600 |
* Initialize random number seed. random() is only used |
| 538 | 601 |
* when "weak" random numbers are acceptable. |
| ... | ... |
@@ -1479,11 +1490,23 @@ safe_print (const char *str, struct gc_arena *gc) |
| 1479 | 1479 |
return string_mod_const (str, CC_PRINT, CC_CRLF, '.', gc); |
| 1480 | 1480 |
} |
| 1481 | 1481 |
|
| 1482 |
+static bool |
|
| 1483 |
+is_password_env_var (const char *str) |
|
| 1484 |
+{
|
|
| 1485 |
+ return (strncmp (str, "password", 8) == 0); |
|
| 1486 |
+} |
|
| 1487 |
+ |
|
| 1488 |
+bool |
|
| 1489 |
+env_allowed (const char *str) |
|
| 1490 |
+{
|
|
| 1491 |
+ return (script_security >= SSEC_PW_ENV || !is_password_env_var (str)); |
|
| 1492 |
+} |
|
| 1493 |
+ |
|
| 1482 | 1494 |
bool |
| 1483 | 1495 |
env_safe_to_print (const char *str) |
| 1484 | 1496 |
{
|
| 1485 | 1497 |
#ifndef UNSAFE_DEBUG |
| 1486 |
- if (strncmp (str, "password", 8) == 0) |
|
| 1498 |
+ if (is_password_env_var (str)) |
|
| 1487 | 1499 |
return false; |
| 1488 | 1500 |
#endif |
| 1489 | 1501 |
return true; |
| ... | ... |
@@ -1492,7 +1515,9 @@ env_safe_to_print (const char *str) |
| 1492 | 1492 |
/* Make arrays of strings */ |
| 1493 | 1493 |
|
| 1494 | 1494 |
const char ** |
| 1495 |
-make_env_array (const struct env_set *es, struct gc_arena *gc) |
|
| 1495 |
+make_env_array (const struct env_set *es, |
|
| 1496 |
+ const bool check_allowed, |
|
| 1497 |
+ struct gc_arena *gc) |
|
| 1496 | 1498 |
{
|
| 1497 | 1499 |
char **ret = NULL; |
| 1498 | 1500 |
struct env_item *e = NULL; |
| ... | ... |
@@ -1511,12 +1536,14 @@ make_env_array (const struct env_set *es, struct gc_arena *gc) |
| 1511 | 1511 |
/* fill return array */ |
| 1512 | 1512 |
if (es) |
| 1513 | 1513 |
{
|
| 1514 |
- e = es->list; |
|
| 1515 |
- for (i = 0; i < n; ++i) |
|
| 1514 |
+ i = 0; |
|
| 1515 |
+ for (e = es->list; e != NULL; e = e->next) |
|
| 1516 | 1516 |
{
|
| 1517 |
- ASSERT (e); |
|
| 1518 |
- ret[i] = e->string; |
|
| 1519 |
- e = e->next; |
|
| 1517 |
+ if (!check_allowed || env_allowed (e->string)) |
|
| 1518 |
+ {
|
|
| 1519 |
+ ASSERT (i < n); |
|
| 1520 |
+ ret[i++] = e->string; |
|
| 1521 |
+ } |
|
| 1520 | 1522 |
} |
| 1521 | 1523 |
} |
| 1522 | 1524 |
|
| ... | ... |
@@ -1631,6 +1658,7 @@ openvpn_sleep (const int n) |
| 1631 | 1631 |
sleep (n); |
| 1632 | 1632 |
} |
| 1633 | 1633 |
|
| 1634 |
+#if 0 |
|
| 1634 | 1635 |
/* |
| 1635 | 1636 |
* Configure PATH. On Windows, sometimes PATH is not set correctly |
| 1636 | 1637 |
* by default. |
| ... | ... |
@@ -1672,3 +1700,72 @@ configure_path (void) |
| 1672 | 1672 |
} |
| 1673 | 1673 |
#endif |
| 1674 | 1674 |
} |
| 1675 |
+#endif |
|
| 1676 |
+ |
|
| 1677 |
+#ifdef ARGV_TEST |
|
| 1678 |
+void |
|
| 1679 |
+argv_test (void) |
|
| 1680 |
+{
|
|
| 1681 |
+ struct gc_arena gc = gc_new (); |
|
| 1682 |
+ char line[512]; |
|
| 1683 |
+ const char *s; |
|
| 1684 |
+ |
|
| 1685 |
+ struct argv a; |
|
| 1686 |
+ argv_init (&a); |
|
| 1687 |
+ |
|
| 1688 |
+#ifdef WIN32 |
|
| 1689 |
+ argv_printf (&a, "%s foo bar %s", "c:\\src\\test\\jyargs.exe", "foo bar"); |
|
| 1690 |
+ //argv_printf (&a, "%s %s %s", "c:\\src\\test files\\batargs.bat", "foo", "bar"); |
|
| 1691 |
+#else |
|
| 1692 |
+ argv_printf (&a, "./myechox foo bar"); |
|
| 1693 |
+#endif |
|
| 1694 |
+ |
|
| 1695 |
+ argv_msg_prefix (M_INFO, &a, "ARGV"); |
|
| 1696 |
+ openvpn_execve_check (&a, NULL, 0, "command failed"); |
|
| 1697 |
+ |
|
| 1698 |
+ argv_printf (&a, "this is a %s test of int %d unsigned %u", "FOO", -69, 42); |
|
| 1699 |
+ s = argv_str (&a, &gc, PA_BRACKET); |
|
| 1700 |
+ printf ("%s\n", s);
|
|
| 1701 |
+ |
|
| 1702 |
+ {
|
|
| 1703 |
+ struct argv b = argv_insert_head (&a, "MARK"); |
|
| 1704 |
+ s = argv_str (&b, &gc, PA_BRACKET); |
|
| 1705 |
+ argv_reset (&b); |
|
| 1706 |
+ printf ("%s\n", s);
|
|
| 1707 |
+ } |
|
| 1708 |
+ |
|
| 1709 |
+ argv_printf (&a, "foo bar %d", 99); |
|
| 1710 |
+ s = argv_str (&a, &gc, PA_BRACKET); |
|
| 1711 |
+ argv_reset (&a); |
|
| 1712 |
+ printf ("%s\n", s);
|
|
| 1713 |
+ |
|
| 1714 |
+ s = argv_str (&a, &gc, PA_BRACKET); |
|
| 1715 |
+ argv_reset (&a); |
|
| 1716 |
+ printf ("%s\n", s);
|
|
| 1717 |
+ |
|
| 1718 |
+ argv_printf (&a, "foo bar %d", 99); |
|
| 1719 |
+ argv_printf_cat (&a, "bar %d foo", 42); |
|
| 1720 |
+ argv_printf_cat (&a, "cool %s %d u %s/%d end", "frood", 4, "hello", 7); |
|
| 1721 |
+ s = argv_str (&a, &gc, PA_BRACKET); |
|
| 1722 |
+ printf ("%s\n", s);
|
|
| 1723 |
+ |
|
| 1724 |
+#if 0 |
|
| 1725 |
+ while (fgets (line, sizeof(line), stdin) != NULL) |
|
| 1726 |
+ {
|
|
| 1727 |
+ char *term; |
|
| 1728 |
+ const char *f = line; |
|
| 1729 |
+ int i = 0; |
|
| 1730 |
+ |
|
| 1731 |
+ while ((term = argv_term (&f)) != NULL) |
|
| 1732 |
+ {
|
|
| 1733 |
+ printf ("[%d] '%s'\n", i, term);
|
|
| 1734 |
+ ++i; |
|
| 1735 |
+ free (term); |
|
| 1736 |
+ } |
|
| 1737 |
+ } |
|
| 1738 |
+#endif |
|
| 1739 |
+ |
|
| 1740 |
+ argv_reset (&a); |
|
| 1741 |
+ gc_free (&gc); |
|
| 1742 |
+} |
|
| 1743 |
+#endif |
| ... | ... |
@@ -117,17 +117,15 @@ void warn_if_group_others_accessible(const char* filename); |
| 117 | 117 |
#define S_SCRIPT (1<<0) |
| 118 | 118 |
#define S_FATAL (1<<1) |
| 119 | 119 |
|
| 120 |
-/* wrapper around the system() call. */ |
|
| 121 |
-int openvpn_system (const char *command, const struct env_set *es, unsigned int flags); |
|
| 122 |
- |
|
| 123 |
-/* interpret the status code returned by system() */ |
|
| 120 |
+/* interpret the status code returned by system()/execve() */ |
|
| 124 | 121 |
bool system_ok(int); |
| 125 | 122 |
int system_executed (int stat); |
| 126 | 123 |
const char *system_error_message (int, struct gc_arena *gc); |
| 127 | 124 |
|
| 128 |
-/* run system() with error check, return true if success, |
|
| 129 |
- false if error, exit if error and fatal==true */ |
|
| 130 |
-bool system_check (const char *command, const struct env_set *es, unsigned int flags, const char *error_message); |
|
| 125 |
+/* wrapper around the execve() call */ |
|
| 126 |
+int openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags); |
|
| 127 |
+bool openvpn_execve_check (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message); |
|
| 128 |
+bool openvpn_execve_allowed (const unsigned int flags); |
|
| 131 | 129 |
|
| 132 | 130 |
#ifdef HAVE_STRERROR |
| 133 | 131 |
/* a thread-safe version of strerror */ |
| ... | ... |
@@ -184,7 +182,10 @@ void env_set_remove_from_environment (const struct env_set *es); |
| 184 | 184 |
|
| 185 | 185 |
/* Make arrays of strings */ |
| 186 | 186 |
|
| 187 |
-const char **make_env_array (const struct env_set *es, struct gc_arena *gc); |
|
| 187 |
+const char **make_env_array (const struct env_set *es, |
|
| 188 |
+ const bool check_allowed, |
|
| 189 |
+ struct gc_arena *gc); |
|
| 190 |
+ |
|
| 188 | 191 |
const char **make_arg_array (const char *first, const char *parms, struct gc_arena *gc); |
| 189 | 192 |
const char **make_extended_arg_array (char **p, struct gc_arena *gc); |
| 190 | 193 |
|
| ... | ... |
@@ -271,6 +272,9 @@ const char *safe_print (const char *str, struct gc_arena *gc); |
| 271 | 271 |
/* returns true if environmental variable safe to print to log */ |
| 272 | 272 |
bool env_safe_to_print (const char *str); |
| 273 | 273 |
|
| 274 |
+/* returns true if environmental variable may be passed to an external program */ |
|
| 275 |
+bool env_allowed (const char *str); |
|
| 276 |
+ |
|
| 274 | 277 |
/* |
| 275 | 278 |
* A sleep function that services the management layer for n |
| 276 | 279 |
* seconds rather than doing nothing. |
| ... | ... |
@@ -290,4 +294,10 @@ void get_user_pass_auto_userid (struct user_pass *up, const char *tag); |
| 290 | 290 |
extern const char *iproute_path; |
| 291 | 291 |
#endif |
| 292 | 292 |
|
| 293 |
+#define SSEC_NONE 0 /* strictly no calling of external programs */ |
|
| 294 |
+#define SSEC_BUILT_IN 1 /* only call built-in programs such as ifconfig, route, netsh, etc.*/ |
|
| 295 |
+#define SSEC_SCRIPTS 2 /* allow calling of built-in programs and user-defined scripts */ |
|
| 296 |
+#define SSEC_PW_ENV 3 /* allow calling of built-in programs and user-defined scripts that may receive a password as an environmental variable */ |
|
| 297 |
+extern int script_security; /* GLOBAL */ |
|
| 298 |
+ |
|
| 293 | 299 |
#endif |
| ... | ... |
@@ -85,36 +85,33 @@ learn_address_script (const struct multi_context *m, |
| 85 | 85 |
|
| 86 | 86 |
if (plugin_defined (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS)) |
| 87 | 87 |
{
|
| 88 |
- struct buffer cmd = alloc_buf_gc (256, &gc); |
|
| 89 |
- |
|
| 90 |
- buf_printf (&cmd, "\"%s\" \"%s\"", |
|
| 91 |
- op, |
|
| 92 |
- mroute_addr_print (addr, &gc)); |
|
| 88 |
+ struct argv argv = argv_new (); |
|
| 89 |
+ argv_printf (&argv, "%s %s", |
|
| 90 |
+ op, |
|
| 91 |
+ mroute_addr_print (addr, &gc)); |
|
| 93 | 92 |
if (mi) |
| 94 |
- buf_printf (&cmd, " \"%s\"", tls_common_name (mi->context.c2.tls_multi, false)); |
|
| 95 |
- |
|
| 96 |
- if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, BSTR (&cmd), NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 93 |
+ argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false)); |
|
| 94 |
+ if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 97 | 95 |
{
|
| 98 | 96 |
msg (M_WARN, "WARNING: learn-address plugin call failed"); |
| 99 | 97 |
ret = false; |
| 100 | 98 |
} |
| 99 |
+ argv_reset (&argv); |
|
| 101 | 100 |
} |
| 102 | 101 |
|
| 103 | 102 |
if (m->top.options.learn_address_script) |
| 104 | 103 |
{
|
| 105 |
- struct buffer cmd = alloc_buf_gc (256, &gc); |
|
| 106 |
- |
|
| 104 |
+ struct argv argv = argv_new (); |
|
| 107 | 105 |
setenv_str (es, "script_type", "learn-address"); |
| 108 |
- |
|
| 109 |
- buf_printf (&cmd, "%s \"%s\" \"%s\"", |
|
| 110 |
- m->top.options.learn_address_script, |
|
| 111 |
- op, |
|
| 112 |
- mroute_addr_print (addr, &gc)); |
|
| 106 |
+ argv_printf (&argv, "%s %s %s", |
|
| 107 |
+ m->top.options.learn_address_script, |
|
| 108 |
+ op, |
|
| 109 |
+ mroute_addr_print (addr, &gc)); |
|
| 113 | 110 |
if (mi) |
| 114 |
- buf_printf (&cmd, " \"%s\"", tls_common_name (mi->context.c2.tls_multi, false)); |
|
| 115 |
- |
|
| 116 |
- if (!system_check (BSTR (&cmd), es, S_SCRIPT, "WARNING: learn-address command failed")) |
|
| 111 |
+ argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false)); |
|
| 112 |
+ if (!openvpn_execve_check (&argv, es, S_SCRIPT, "WARNING: learn-address command failed")) |
|
| 117 | 113 |
ret = false; |
| 114 |
+ argv_reset (&argv); |
|
| 118 | 115 |
} |
| 119 | 116 |
|
| 120 | 117 |
gc_free (&gc); |
| ... | ... |
@@ -474,16 +471,11 @@ multi_client_disconnect_script (struct multi_context *m, |
| 474 | 474 |
|
| 475 | 475 |
if (mi->context.options.client_disconnect_script) |
| 476 | 476 |
{
|
| 477 |
- struct gc_arena gc = gc_new (); |
|
| 478 |
- struct buffer cmd = alloc_buf_gc (256, &gc); |
|
| 479 |
- |
|
| 477 |
+ struct argv argv = argv_new (); |
|
| 480 | 478 |
setenv_str (mi->context.c2.es, "script_type", "client-disconnect"); |
| 481 |
- |
|
| 482 |
- buf_printf (&cmd, "%s", mi->context.options.client_disconnect_script); |
|
| 483 |
- |
|
| 484 |
- system_check (BSTR (&cmd), mi->context.c2.es, S_SCRIPT, "client-disconnect command failed"); |
|
| 485 |
- |
|
| 486 |
- gc_free (&gc); |
|
| 479 |
+ argv_printf (&argv, "%s", mi->context.options.client_disconnect_script); |
|
| 480 |
+ openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-disconnect command failed"); |
|
| 481 |
+ argv_reset (&argv); |
|
| 487 | 482 |
} |
| 488 | 483 |
#ifdef MANAGEMENT_DEF_AUTH |
| 489 | 484 |
if (management) |
| ... | ... |
@@ -1523,11 +1515,11 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi |
| 1523 | 1523 |
/* deprecated callback, use a file for passing back return info */ |
| 1524 | 1524 |
if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) |
| 1525 | 1525 |
{
|
| 1526 |
+ struct argv argv = argv_new (); |
|
| 1526 | 1527 |
const char *dc_file = create_temp_filename (mi->context.options.tmp_dir, "cc", &gc); |
| 1527 |
- |
|
| 1528 |
+ argv_printf (&argv, "%s", dc_file); |
|
| 1528 | 1529 |
delete_file (dc_file); |
| 1529 |
- |
|
| 1530 |
- if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, dc_file, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 1530 |
+ if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, &argv, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 1531 | 1531 |
{
|
| 1532 | 1532 |
msg (M_WARN, "WARNING: client-connect plugin call failed"); |
| 1533 | 1533 |
cc_succeeded = false; |
| ... | ... |
@@ -1537,6 +1529,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi |
| 1537 | 1537 |
multi_client_connect_post (m, mi, dc_file, option_permissions_mask, &option_types_found); |
| 1538 | 1538 |
++cc_succeeded_count; |
| 1539 | 1539 |
} |
| 1540 |
+ argv_reset (&argv); |
|
| 1540 | 1541 |
} |
| 1541 | 1542 |
|
| 1542 | 1543 |
/* 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 |
| 1566 | 1566 |
*/ |
| 1567 | 1567 |
if (mi->context.options.client_connect_script && cc_succeeded) |
| 1568 | 1568 |
{
|
| 1569 |
- struct buffer cmd = alloc_buf_gc (256, &gc); |
|
| 1569 |
+ struct argv argv = argv_new (); |
|
| 1570 | 1570 |
const char *dc_file = NULL; |
| 1571 | 1571 |
|
| 1572 | 1572 |
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 |
| 1575 | 1575 |
|
| 1576 | 1576 |
delete_file (dc_file); |
| 1577 | 1577 |
|
| 1578 |
- buf_printf (&cmd, "%s %s", |
|
| 1579 |
- mi->context.options.client_connect_script, |
|
| 1580 |
- dc_file); |
|
| 1578 |
+ argv_printf (&argv, "%s %s", |
|
| 1579 |
+ mi->context.options.client_connect_script, |
|
| 1580 |
+ dc_file); |
|
| 1581 | 1581 |
|
| 1582 |
- if (system_check (BSTR (&cmd), mi->context.c2.es, S_SCRIPT, "client-connect command failed")) |
|
| 1582 |
+ if (openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-connect command failed")) |
|
| 1583 | 1583 |
{
|
| 1584 | 1584 |
multi_client_connect_post (m, mi, dc_file, option_permissions_mask, &option_types_found); |
| 1585 | 1585 |
++cc_succeeded_count; |
| 1586 | 1586 |
} |
| 1587 | 1587 |
else |
| 1588 | 1588 |
cc_succeeded = false; |
| 1589 |
+ |
|
| 1590 |
+ argv_reset (&argv); |
|
| 1589 | 1591 |
} |
| 1590 | 1592 |
|
| 1591 | 1593 |
/* |
| ... | ... |
@@ -252,6 +252,7 @@ openvpn \- secure IP tunnel daemon. |
| 252 | 252 |
[\ \fB\-\-route\-up\fR\ \fIcmd\fR\ ] |
| 253 | 253 |
[\ \fB\-\-route\fR\ \fInetwork\ [netmask]\ [gateway]\ [metric]\fR\ ] |
| 254 | 254 |
[\ \fB\-\-rport\fR\ \fIport\fR\ ] |
| 255 |
+[\ \fB\-\-script\-security\fR\ \fIlevel\fR\ ] |
|
| 255 | 256 |
[\ \fB\-\-secret\fR\ \fIfile\ [direction]\fR\ ] |
| 256 | 257 |
[\ \fB\-\-secret\fR\ \fIfile\fR\ ] |
| 257 | 258 |
[\ \fB\-\-server\-bridge\fR\ \fIgateway\ netmask\ pool\-start\-IP\ pool\-end\-IP\fR\ ] |
| ... | ... |
@@ -300,6 +301,7 @@ openvpn \- secure IP tunnel daemon. |
| 300 | 300 |
[\ \fB\-\-user\fR\ \fIuser\fR\ ] |
| 301 | 301 |
[\ \fB\-\-username\-as\-common\-name\fR\ ] |
| 302 | 302 |
[\ \fB\-\-verb\fR\ \fIn\fR\ ] |
| 303 |
+[\ \fB\-\-win\-sys\fR\ \fIpath|'env'\fR\ ] |
|
| 303 | 304 |
[\ \fB\-\-writepid\fR\ \fIfile\fR\ ] |
| 304 | 305 |
.in -4 |
| 305 | 306 |
.ti +4 |
| ... | ... |
@@ -1998,6 +2000,24 @@ is a safety precaution to prevent a LD_PRELOAD style attack |
| 1998 | 1998 |
from a malicious or compromised server. |
| 1999 | 1999 |
.\"********************************************************* |
| 2000 | 2000 |
.TP |
| 2001 |
+.B --script-security level |
|
| 2002 |
+This directive offers policy-level control over OpenVPN's usage of external programs |
|
| 2003 |
+and scripts. Lower values are more restrictive, higher values are more permissive. Settings for |
|
| 2004 |
+.B level: |
|
| 2005 |
+ |
|
| 2006 |
+.B 0 -- |
|
| 2007 |
+Strictly no calling of external programs. |
|
| 2008 |
+.br |
|
| 2009 |
+.B 1 -- |
|
| 2010 |
+(Default) Only call built-in executables such as ifconfig, ip, route, or netsh. |
|
| 2011 |
+.br |
|
| 2012 |
+.B 2 -- |
|
| 2013 |
+Allow calling of built-in executables and user-defined scripts. |
|
| 2014 |
+.br |
|
| 2015 |
+.B 3 -- |
|
| 2016 |
+Allow passwords to be passed to scripts via environmental variables (potentially unsafe). |
|
| 2017 |
+.\"********************************************************* |
|
| 2018 |
+.TP |
|
| 2001 | 2019 |
.B --disable-occ |
| 2002 | 2020 |
Don't output a warning message if option inconsistencies are detected between |
| 2003 | 2021 |
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. |
| 4481 | 4481 |
.SS Windows-Specific Options: |
| 4482 | 4482 |
.\"********************************************************* |
| 4483 | 4483 |
.TP |
| 4484 |
+.B --win-sys path|'env' |
|
| 4485 |
+Set the Windows system directory pathname to use when looking for system |
|
| 4486 |
+executables such as |
|
| 4487 |
+.B route.exe |
|
| 4488 |
+and |
|
| 4489 |
+.B netsh.exe. |
|
| 4490 |
+By default, if this directive is |
|
| 4491 |
+not specified, the pathname will be set to "C:\\WINDOWS" |
|
| 4492 |
+ |
|
| 4493 |
+The special string |
|
| 4494 |
+.B 'env' |
|
| 4495 |
+indicates that the pathname should be read from the |
|
| 4496 |
+.B SystemRoot |
|
| 4497 |
+environmental variable. |
|
| 4498 |
+.\"********************************************************* |
|
| 4499 |
+.TP |
|
| 4484 | 4500 |
.B --ip-win32 method |
| 4485 | 4501 |
When using |
| 4486 | 4502 |
.B --ifconfig |
| ... | ... |
@@ -27,6 +27,7 @@ |
| 27 | 27 |
#include "init.h" |
| 28 | 28 |
#include "forward.h" |
| 29 | 29 |
#include "multi.h" |
| 30 |
+#include "win32.h" |
|
| 30 | 31 |
|
| 31 | 32 |
#include "memdbg.h" |
| 32 | 33 |
|
| ... | ... |
@@ -131,6 +132,9 @@ main (int argc, char *argv[]) |
| 131 | 131 |
|
| 132 | 132 |
/* initialize environmental variable store */ |
| 133 | 133 |
c.es = env_set_create (NULL); |
| 134 |
+#ifdef WIN32 |
|
| 135 |
+ env_set_add_win32 (c.es); |
|
| 136 |
+#endif |
|
| 134 | 137 |
|
| 135 | 138 |
#ifdef ENABLE_MANAGEMENT |
| 136 | 139 |
/* initialize management subsystem */ |
| ... | ... |
@@ -189,6 +189,10 @@ static const char usage_message[] = |
| 189 | 189 |
" flag to add a direct route to DHCP server, bypassing tunnel.\n" |
| 190 | 190 |
" Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n" |
| 191 | 191 |
"--setenv name value : Set a custom environmental variable to pass to script.\n" |
| 192 |
+ "--script-security level : 0 -- strictly no calling of external programs\n" |
|
| 193 |
+ " 1 -- (default) only call built-ins such as ifconfig\n" |
|
| 194 |
+ " 2 -- allow calling of built-ins and scripts\n" |
|
| 195 |
+ " 3 -- allow password to be passed to scripts via env\n" |
|
| 192 | 196 |
"--shaper n : Restrict output to peer to n bytes per second.\n" |
| 193 | 197 |
"--keepalive n m : Helper option for setting timeouts in server mode. Send\n" |
| 194 | 198 |
" ping once every n seconds, restart if ping not received\n" |
| ... | ... |
@@ -536,6 +540,8 @@ static const char usage_message[] = |
| 536 | 536 |
#ifdef WIN32 |
| 537 | 537 |
"\n" |
| 538 | 538 |
"Windows Specific:\n" |
| 539 |
+ "--win-sys path|'env' : Pathname of Windows system directory, C:\\WINDOWS by default.\n" |
|
| 540 |
+ " If specified as 'env', read the pathname from SystemRoot env var.\n" |
|
| 539 | 541 |
"--ip-win32 method : When using --ifconfig on Windows, set TAP-Win32 adapter\n" |
| 540 | 542 |
" IP address using method = manual, netsh, ipapi,\n" |
| 541 | 543 |
" dynamic, or adaptive (default = adaptive).\n" |
| ... | ... |
@@ -4249,6 +4255,11 @@ add_option (struct options *options, |
| 4249 | 4249 |
VERIFY_PERMISSION (OPT_P_SETENV); |
| 4250 | 4250 |
setenv_str_safe (es, p[1], p[2] ? p[2] : ""); |
| 4251 | 4251 |
} |
| 4252 |
+ else if (streq (p[0], "script-security") && p[1]) |
|
| 4253 |
+ {
|
|
| 4254 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
| 4255 |
+ script_security = atoi (p[1]); |
|
| 4256 |
+ } |
|
| 4252 | 4257 |
else if (streq (p[0], "mssfix")) |
| 4253 | 4258 |
{
|
| 4254 | 4259 |
VERIFY_PERMISSION (OPT_P_GENERAL); |
| ... | ... |
@@ -4618,6 +4629,14 @@ add_option (struct options *options, |
| 4618 | 4618 |
} |
| 4619 | 4619 |
#endif |
| 4620 | 4620 |
#ifdef WIN32 |
| 4621 |
+ else if (streq (p[0], "win-sys") && p[1]) |
|
| 4622 |
+ {
|
|
| 4623 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
| 4624 |
+ if (streq (p[1], "env")) |
|
| 4625 |
+ set_win_sys_path_via_env (es); |
|
| 4626 |
+ else |
|
| 4627 |
+ set_win_sys_path (p[1], es); |
|
| 4628 |
+ } |
|
| 4621 | 4629 |
else if (streq (p[0], "route-method") && p[1]) |
| 4622 | 4630 |
{
|
| 4623 | 4631 |
VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS); |
| ... | ... |
@@ -327,7 +327,7 @@ static int |
| 327 | 327 |
plugin_call_item (const struct plugin *p, |
| 328 | 328 |
void *per_client_context, |
| 329 | 329 |
const int type, |
| 330 |
- const char *args, |
|
| 330 |
+ const struct argv *av, |
|
| 331 | 331 |
struct openvpn_plugin_string_list **retlist, |
| 332 | 332 |
const char **envp) |
| 333 | 333 |
{
|
| ... | ... |
@@ -340,18 +340,18 @@ plugin_call_item (const struct plugin *p, |
| 340 | 340 |
if (p->plugin_handle && (p->plugin_type_mask & OPENVPN_PLUGIN_MASK (type))) |
| 341 | 341 |
{
|
| 342 | 342 |
struct gc_arena gc = gc_new (); |
| 343 |
- const char **argv = make_arg_array (p->so_pathname, args, &gc); |
|
| 343 |
+ struct argv a = argv_insert_head (av, p->so_pathname); |
|
| 344 | 344 |
|
| 345 | 345 |
dmsg (D_PLUGIN_DEBUG, "PLUGIN_CALL: PRE type=%s", plugin_type_name (type)); |
| 346 |
- plugin_show_args_env (D_PLUGIN_DEBUG, argv, envp); |
|
| 346 |
+ plugin_show_args_env (D_PLUGIN_DEBUG, (const char **)a.argv, envp); |
|
| 347 | 347 |
|
| 348 | 348 |
/* |
| 349 | 349 |
* Call the plugin work function |
| 350 | 350 |
*/ |
| 351 | 351 |
if (p->func2) |
| 352 |
- status = (*p->func2)(p->plugin_handle, type, argv, envp, per_client_context, retlist); |
|
| 352 |
+ status = (*p->func2)(p->plugin_handle, type, (const char **)a.argv, envp, per_client_context, retlist); |
|
| 353 | 353 |
else if (p->func1) |
| 354 |
- status = (*p->func1)(p->plugin_handle, type, argv, envp); |
|
| 354 |
+ status = (*p->func1)(p->plugin_handle, type, (const char **)a.argv, envp); |
|
| 355 | 355 |
else |
| 356 | 356 |
ASSERT (0); |
| 357 | 357 |
|
| ... | ... |
@@ -366,6 +366,7 @@ plugin_call_item (const struct plugin *p, |
| 366 | 366 |
status, |
| 367 | 367 |
p->so_pathname); |
| 368 | 368 |
|
| 369 |
+ argv_reset (&a); |
|
| 369 | 370 |
gc_free (&gc); |
| 370 | 371 |
} |
| 371 | 372 |
return status; |
| ... | ... |
@@ -482,7 +483,7 @@ plugin_common_open (struct plugin_common *pc, |
| 482 | 482 |
int i; |
| 483 | 483 |
const char **envp; |
| 484 | 484 |
|
| 485 |
- envp = make_env_array (es, &gc); |
|
| 485 |
+ envp = make_env_array (es, false, &gc); |
|
| 486 | 486 |
|
| 487 | 487 |
if (pr) |
| 488 | 488 |
plugin_return_init (pr); |
| ... | ... |
@@ -540,7 +541,7 @@ plugin_list_open (struct plugin_list *pl, |
| 540 | 540 |
int |
| 541 | 541 |
plugin_call (const struct plugin_list *pl, |
| 542 | 542 |
const int type, |
| 543 |
- const char *args, |
|
| 543 |
+ const struct argv *av, |
|
| 544 | 544 |
struct plugin_return *pr, |
| 545 | 545 |
struct env_set *es) |
| 546 | 546 |
{
|
| ... | ... |
@@ -560,14 +561,14 @@ plugin_call (const struct plugin_list *pl, |
| 560 | 560 |
mutex_lock_static (L_PLUGIN); |
| 561 | 561 |
|
| 562 | 562 |
setenv_del (es, "script_type"); |
| 563 |
- envp = make_env_array (es, &gc); |
|
| 563 |
+ envp = make_env_array (es, false, &gc); |
|
| 564 | 564 |
|
| 565 | 565 |
for (i = 0; i < n; ++i) |
| 566 | 566 |
{
|
| 567 | 567 |
const int status = plugin_call_item (&pl->common->plugins[i], |
| 568 | 568 |
pl->per_client.per_client_context[i], |
| 569 | 569 |
type, |
| 570 |
- args, |
|
| 570 |
+ av, |
|
| 571 | 571 |
pr ? &pr->list[i] : NULL, |
| 572 | 572 |
envp); |
| 573 | 573 |
switch (status) |
| ... | ... |
@@ -116,7 +116,7 @@ struct plugin_list *plugin_list_inherit (const struct plugin_list *src); |
| 116 | 116 |
|
| 117 | 117 |
int plugin_call (const struct plugin_list *pl, |
| 118 | 118 |
const int type, |
| 119 |
- const char *args, |
|
| 119 |
+ const struct argv *av, |
|
| 120 | 120 |
struct plugin_return *pr, |
| 121 | 121 |
struct env_set *es); |
| 122 | 122 |
|
| ... | ... |
@@ -168,7 +168,7 @@ plugin_defined (const struct plugin_list *pl, const int type) |
| 168 | 168 |
static inline int |
| 169 | 169 |
plugin_call (const struct plugin_list *pl, |
| 170 | 170 |
const int type, |
| 171 |
- const char *args, |
|
| 171 |
+ const struct argv *av, |
|
| 172 | 172 |
struct plugin_return *pr, |
| 173 | 173 |
struct env_set *es) |
| 174 | 174 |
{
|
| 175 | 175 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,184 @@ |
| 0 |
+/* |
|
| 1 |
+ * OpenVPN -- An application to securely tunnel IP networks |
|
| 2 |
+ * over a single TCP/UDP port, with support for SSL/TLS-based |
|
| 3 |
+ * session authentication and key exchange, |
|
| 4 |
+ * packet encryption, packet authentication, and |
|
| 5 |
+ * packet compression. |
|
| 6 |
+ * |
|
| 7 |
+ * Copyright (C) 2002-2008 Telethra, Inc. <sales@openvpn.net> |
|
| 8 |
+ * |
|
| 9 |
+ * This program is free software; you can redistribute it and/or modify |
|
| 10 |
+ * it under the terms of the GNU General Public License version 2 |
|
| 11 |
+ * as published by the Free Software Foundation. |
|
| 12 |
+ * |
|
| 13 |
+ * This program is distributed in the hope that it will be useful, |
|
| 14 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
+ * GNU General Public License for more details. |
|
| 17 |
+ * |
|
| 18 |
+ * You should have received a copy of the GNU General Public License |
|
| 19 |
+ * along with this program (see the file COPYING included with this |
|
| 20 |
+ * distribution); if not, write to the Free Software Foundation, Inc., |
|
| 21 |
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
| 22 |
+ */ |
|
| 23 |
+ |
|
| 24 |
+/* |
|
| 25 |
+ * This plugin is similar to simple.c, except it also logs extra information |
|
| 26 |
+ * to stdout for every plugin method called by OpenVPN. |
|
| 27 |
+ * |
|
| 28 |
+ * See the README file for build instructions. |
|
| 29 |
+ */ |
|
| 30 |
+ |
|
| 31 |
+#include <stdio.h> |
|
| 32 |
+#include <string.h> |
|
| 33 |
+#include <stdlib.h> |
|
| 34 |
+ |
|
| 35 |
+#include "openvpn-plugin.h" |
|
| 36 |
+ |
|
| 37 |
+/* |
|
| 38 |
+ * Our context, where we keep our state. |
|
| 39 |
+ */ |
|
| 40 |
+struct plugin_context {
|
|
| 41 |
+ const char *username; |
|
| 42 |
+ const char *password; |
|
| 43 |
+}; |
|
| 44 |
+ |
|
| 45 |
+/* |
|
| 46 |
+ * Given an environmental variable name, search |
|
| 47 |
+ * the envp array for its value, returning it |
|
| 48 |
+ * if found or NULL otherwise. |
|
| 49 |
+ */ |
|
| 50 |
+static const char * |
|
| 51 |
+get_env (const char *name, const char *envp[]) |
|
| 52 |
+{
|
|
| 53 |
+ if (envp) |
|
| 54 |
+ {
|
|
| 55 |
+ int i; |
|
| 56 |
+ const int namelen = strlen (name); |
|
| 57 |
+ for (i = 0; envp[i]; ++i) |
|
| 58 |
+ {
|
|
| 59 |
+ if (!strncmp (envp[i], name, namelen)) |
|
| 60 |
+ {
|
|
| 61 |
+ const char *cp = envp[i] + namelen; |
|
| 62 |
+ if (*cp == '=') |
|
| 63 |
+ return cp + 1; |
|
| 64 |
+ } |
|
| 65 |
+ } |
|
| 66 |
+ } |
|
| 67 |
+ return NULL; |
|
| 68 |
+} |
|
| 69 |
+ |
|
| 70 |
+OPENVPN_EXPORT openvpn_plugin_handle_t |
|
| 71 |
+openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]) |
|
| 72 |
+{
|
|
| 73 |
+ struct plugin_context *context; |
|
| 74 |
+ |
|
| 75 |
+ /* |
|
| 76 |
+ * Allocate our context |
|
| 77 |
+ */ |
|
| 78 |
+ context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context)); |
|
| 79 |
+ |
|
| 80 |
+ /* |
|
| 81 |
+ * Set the username/password we will require. |
|
| 82 |
+ */ |
|
| 83 |
+ context->username = "foo"; |
|
| 84 |
+ context->password = "bar"; |
|
| 85 |
+ |
|
| 86 |
+ /* |
|
| 87 |
+ * Which callbacks to intercept. |
|
| 88 |
+ */ |
|
| 89 |
+ *type_mask = |
|
| 90 |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) | |
|
| 91 |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN) | |
|
| 92 |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ROUTE_UP) | |
|
| 93 |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_IPCHANGE) | |
|
| 94 |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_VERIFY) | |
|
| 95 |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) | |
|
| 96 |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) | |
|
| 97 |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) | |
|
| 98 |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_LEARN_ADDRESS) | |
|
| 99 |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_FINAL); |
|
| 100 |
+ |
|
| 101 |
+ return (openvpn_plugin_handle_t) context; |
|
| 102 |
+} |
|
| 103 |
+ |
|
| 104 |
+void |
|
| 105 |
+show (const int type, const char *argv[], const char *envp[]) |
|
| 106 |
+{
|
|
| 107 |
+ size_t i; |
|
| 108 |
+ switch (type) |
|
| 109 |
+ {
|
|
| 110 |
+ case OPENVPN_PLUGIN_UP: |
|
| 111 |
+ printf ("OPENVPN_PLUGIN_UP\n");
|
|
| 112 |
+ break; |
|
| 113 |
+ case OPENVPN_PLUGIN_DOWN: |
|
| 114 |
+ printf ("OPENVPN_PLUGIN_DOWN\n");
|
|
| 115 |
+ break; |
|
| 116 |
+ case OPENVPN_PLUGIN_ROUTE_UP: |
|
| 117 |
+ printf ("OPENVPN_PLUGIN_ROUTE_UP\n");
|
|
| 118 |
+ break; |
|
| 119 |
+ case OPENVPN_PLUGIN_IPCHANGE: |
|
| 120 |
+ printf ("OPENVPN_PLUGIN_IPCHANGE\n");
|
|
| 121 |
+ break; |
|
| 122 |
+ case OPENVPN_PLUGIN_TLS_VERIFY: |
|
| 123 |
+ printf ("OPENVPN_PLUGIN_TLS_VERIFY\n");
|
|
| 124 |
+ break; |
|
| 125 |
+ case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: |
|
| 126 |
+ printf ("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
|
|
| 127 |
+ break; |
|
| 128 |
+ case OPENVPN_PLUGIN_CLIENT_CONNECT_V2: |
|
| 129 |
+ printf ("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
|
|
| 130 |
+ break; |
|
| 131 |
+ case OPENVPN_PLUGIN_CLIENT_DISCONNECT: |
|
| 132 |
+ printf ("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n");
|
|
| 133 |
+ break; |
|
| 134 |
+ case OPENVPN_PLUGIN_LEARN_ADDRESS: |
|
| 135 |
+ printf ("OPENVPN_PLUGIN_LEARN_ADDRESS\n");
|
|
| 136 |
+ break; |
|
| 137 |
+ case OPENVPN_PLUGIN_TLS_FINAL: |
|
| 138 |
+ printf ("OPENVPN_PLUGIN_TLS_FINAL\n");
|
|
| 139 |
+ break; |
|
| 140 |
+ default: |
|
| 141 |
+ printf ("OPENVPN_PLUGIN_?\n");
|
|
| 142 |
+ break; |
|
| 143 |
+ } |
|
| 144 |
+ |
|
| 145 |
+ printf ("ARGV\n");
|
|
| 146 |
+ for (i = 0; argv[i] != NULL; ++i) |
|
| 147 |
+ printf ("%d '%s'\n", (int)i, argv[i]);
|
|
| 148 |
+ |
|
| 149 |
+ printf ("ENVP\n");
|
|
| 150 |
+ for (i = 0; envp[i] != NULL; ++i) |
|
| 151 |
+ printf ("%d '%s'\n", (int)i, envp[i]);
|
|
| 152 |
+} |
|
| 153 |
+ |
|
| 154 |
+OPENVPN_EXPORT int |
|
| 155 |
+openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) |
|
| 156 |
+{
|
|
| 157 |
+ struct plugin_context *context = (struct plugin_context *) handle; |
|
| 158 |
+ |
|
| 159 |
+ show (type, argv, envp); |
|
| 160 |
+ |
|
| 161 |
+ /* check entered username/password against what we require */ |
|
| 162 |
+ if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) |
|
| 163 |
+ {
|
|
| 164 |
+ /* get username/password from envp string array */ |
|
| 165 |
+ const char *username = get_env ("username", envp);
|
|
| 166 |
+ const char *password = get_env ("password", envp);
|
|
| 167 |
+ |
|
| 168 |
+ if (username && !strcmp (username, context->username) |
|
| 169 |
+ && password && !strcmp (password, context->password)) |
|
| 170 |
+ return OPENVPN_PLUGIN_FUNC_SUCCESS; |
|
| 171 |
+ else |
|
| 172 |
+ return OPENVPN_PLUGIN_FUNC_ERROR; |
|
| 173 |
+ } |
|
| 174 |
+ else |
|
| 175 |
+ return OPENVPN_PLUGIN_FUNC_SUCCESS; |
|
| 176 |
+} |
|
| 177 |
+ |
|
| 178 |
+OPENVPN_EXPORT void |
|
| 179 |
+openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) |
|
| 180 |
+{
|
|
| 181 |
+ struct plugin_context *context = (struct plugin_context *) handle; |
|
| 182 |
+ free (context); |
|
| 183 |
+} |
| ... | ... |
@@ -34,6 +34,7 @@ |
| 34 | 34 |
#include "misc.h" |
| 35 | 35 |
#include "socket.h" |
| 36 | 36 |
#include "manage.h" |
| 37 |
+#include "win32.h" |
|
| 37 | 38 |
|
| 38 | 39 |
#include "memdbg.h" |
| 39 | 40 |
|
| ... | ... |
@@ -743,7 +744,7 @@ void |
| 743 | 743 |
add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es) |
| 744 | 744 |
{
|
| 745 | 745 |
struct gc_arena gc; |
| 746 |
- struct buffer buf; |
|
| 746 |
+ struct argv argv; |
|
| 747 | 747 |
const char *network; |
| 748 | 748 |
const char *netmask; |
| 749 | 749 |
const char *gateway; |
| ... | ... |
@@ -753,7 +754,7 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s |
| 753 | 753 |
return; |
| 754 | 754 |
|
| 755 | 755 |
gc_init (&gc); |
| 756 |
- buf = alloc_buf_gc (256, &gc); |
|
| 756 |
+ argv_init (&argv); |
|
| 757 | 757 |
|
| 758 | 758 |
network = print_in_addr_t (r->network, 0, &gc); |
| 759 | 759 |
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 |
| 771 | 771 |
|
| 772 | 772 |
#if defined(TARGET_LINUX) |
| 773 | 773 |
#ifdef CONFIG_FEATURE_IPROUTE |
| 774 |
- buf_printf (&buf, "%s route add %s/%d via %s", |
|
| 774 |
+ argv_printf (&argv, "%s route add %s/%d via %s", |
|
| 775 | 775 |
iproute_path, |
| 776 | 776 |
network, |
| 777 | 777 |
count_netmask_bits(netmask), |
| 778 | 778 |
gateway); |
| 779 | 779 |
if (r->metric_defined) |
| 780 |
- buf_printf (&buf, " metric %d", r->metric); |
|
| 780 |
+ argv_printf_cat (&argv, "metric %d", r->metric); |
|
| 781 | 781 |
|
| 782 | 782 |
#else |
| 783 |
- buf_printf (&buf, ROUTE_PATH " add -net %s netmask %s gw %s", |
|
| 783 |
+ argv_printf (&argv, "%s add -net %s netmask %s gw %s", |
|
| 784 |
+ ROUTE_PATH, |
|
| 784 | 785 |
network, |
| 785 | 786 |
netmask, |
| 786 | 787 |
gateway); |
| 787 | 788 |
if (r->metric_defined) |
| 788 |
- buf_printf (&buf, " metric %d", r->metric); |
|
| 789 |
+ argv_printf_cat (&argv, "metric %d", r->metric); |
|
| 789 | 790 |
#endif /*CONFIG_FEATURE_IPROUTE*/ |
| 790 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 791 |
- status = system_check (BSTR (&buf), es, 0, "ERROR: Linux route add command failed"); |
|
| 791 |
+ argv_msg (D_ROUTE, &argv); |
|
| 792 |
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route add command failed"); |
|
| 792 | 793 |
|
| 793 | 794 |
#elif defined (WIN32) |
| 794 | 795 |
|
| 795 |
- buf_printf (&buf, ROUTE_PATH " ADD %s MASK %s %s", |
|
| 796 |
- network, |
|
| 797 |
- netmask, |
|
| 798 |
- gateway); |
|
| 796 |
+ argv_printf (&argv, "%s%s ADD %s MASK %s %s", |
|
| 797 |
+ get_win_sys_path(), |
|
| 798 |
+ WIN_ROUTE_PATH_SUFFIX, |
|
| 799 |
+ network, |
|
| 800 |
+ netmask, |
|
| 801 |
+ gateway); |
|
| 799 | 802 |
if (r->metric_defined) |
| 800 |
- buf_printf (&buf, " METRIC %d", r->metric); |
|
| 803 |
+ argv_printf_cat (&argv, "METRIC %d", r->metric); |
|
| 801 | 804 |
|
| 802 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 805 |
+ argv_msg (D_ROUTE, &argv); |
|
| 803 | 806 |
|
| 804 | 807 |
if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI) |
| 805 | 808 |
{
|
| ... | ... |
@@ -809,7 +813,7 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s |
| 809 | 809 |
else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_EXE) |
| 810 | 810 |
{
|
| 811 | 811 |
netcmd_semaphore_lock (); |
| 812 |
- status = system_check (BSTR (&buf), es, 0, "ERROR: Windows route add command failed"); |
|
| 812 |
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add command failed"); |
|
| 813 | 813 |
netcmd_semaphore_release (); |
| 814 | 814 |
} |
| 815 | 815 |
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 |
| 820 | 820 |
{
|
| 821 | 821 |
msg (D_ROUTE, "Route addition fallback to route.exe"); |
| 822 | 822 |
netcmd_semaphore_lock (); |
| 823 |
- status = system_check (BSTR (&buf), es, 0, "ERROR: Windows route add command failed [adaptive]"); |
|
| 823 |
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add command failed [adaptive]"); |
|
| 824 | 824 |
netcmd_semaphore_release (); |
| 825 | 825 |
} |
| 826 | 826 |
} |
| ... | ... |
@@ -833,88 +837,93 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s |
| 833 | 833 |
|
| 834 | 834 |
/* example: route add 192.0.2.32 -netmask 255.255.255.224 somegateway */ |
| 835 | 835 |
|
| 836 |
- buf_printf (&buf, ROUTE_PATH " add"); |
|
| 836 |
+ argv_printf (&argv, "%s add", |
|
| 837 |
+ ROUTE_PATH); |
|
| 837 | 838 |
|
| 838 | 839 |
#if 0 |
| 839 | 840 |
if (r->metric_defined) |
| 840 |
- buf_printf (&buf, " -rtt %d", r->metric); |
|
| 841 |
+ argv_printf_cat (&argv, "-rtt %d", r->metric); |
|
| 841 | 842 |
#endif |
| 842 | 843 |
|
| 843 |
- buf_printf (&buf, " %s -netmask %s %s", |
|
| 844 |
+ argv_printf_cat (&argv, "%s -netmask %s %s", |
|
| 844 | 845 |
network, |
| 845 | 846 |
netmask, |
| 846 | 847 |
gateway); |
| 847 | 848 |
|
| 848 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 849 |
- status = system_check (BSTR (&buf), es, 0, "ERROR: Solaris route add command failed"); |
|
| 849 |
+ argv_msg (D_ROUTE, &argv); |
|
| 850 |
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route add command failed"); |
|
| 850 | 851 |
|
| 851 | 852 |
#elif defined(TARGET_FREEBSD) |
| 852 | 853 |
|
| 853 |
- buf_printf (&buf, ROUTE_PATH " add"); |
|
| 854 |
+ argv_printf (&argv, "%s add", |
|
| 855 |
+ ROUTE_PATH); |
|
| 854 | 856 |
|
| 855 | 857 |
#if 0 |
| 856 | 858 |
if (r->metric_defined) |
| 857 |
- buf_printf (&buf, " -rtt %d", r->metric); |
|
| 859 |
+ argv_printf_cat (&argv, "-rtt %d", r->metric); |
|
| 858 | 860 |
#endif |
| 859 | 861 |
|
| 860 |
- buf_printf (&buf, " -net %s %s %s", |
|
| 862 |
+ argv_printf_cat (&argv, "-net %s %s %s", |
|
| 861 | 863 |
network, |
| 862 | 864 |
gateway, |
| 863 | 865 |
netmask); |
| 864 | 866 |
|
| 865 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 866 |
- status = system_check (BSTR (&buf), es, 0, "ERROR: FreeBSD route add command failed"); |
|
| 867 |
+ argv_msg (D_ROUTE, &argv); |
|
| 868 |
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: FreeBSD route add command failed"); |
|
| 867 | 869 |
|
| 868 | 870 |
#elif defined(TARGET_DRAGONFLY) |
| 869 | 871 |
|
| 870 |
- buf_printf (&buf, ROUTE_PATH " add"); |
|
| 872 |
+ argv_printf (&argv, "%s add", |
|
| 873 |
+ ROUTE_PATH); |
|
| 871 | 874 |
|
| 872 | 875 |
#if 0 |
| 873 | 876 |
if (r->metric_defined) |
| 874 |
- buf_printf (&buf, " -rtt %d", r->metric); |
|
| 877 |
+ argv_printf_cat (&argv, "-rtt %d", r->metric); |
|
| 875 | 878 |
#endif |
| 876 | 879 |
|
| 877 |
- buf_printf (&buf, " -net %s %s %s", |
|
| 880 |
+ argv_printf_cat (&argv, "-net %s %s %s", |
|
| 878 | 881 |
network, |
| 879 | 882 |
gateway, |
| 880 | 883 |
netmask); |
| 881 | 884 |
|
| 882 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 883 |
- status = system_check (BSTR (&buf), es, 0, "ERROR: DragonFly route add command failed"); |
|
| 885 |
+ argv_msg (D_ROUTE, &argv); |
|
| 886 |
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: DragonFly route add command failed"); |
|
| 884 | 887 |
|
| 885 | 888 |
#elif defined(TARGET_DARWIN) |
| 886 | 889 |
|
| 887 |
- buf_printf (&buf, ROUTE_PATH " add"); |
|
| 890 |
+ argv_printf (&argv, "%s add", |
|
| 891 |
+ ROUTE_PATH); |
|
| 888 | 892 |
|
| 889 | 893 |
#if 0 |
| 890 | 894 |
if (r->metric_defined) |
| 891 |
- buf_printf (&buf, " -rtt %d", r->metric); |
|
| 895 |
+ argv_printf_cat (&argv, "-rtt %d", r->metric); |
|
| 892 | 896 |
#endif |
| 893 | 897 |
|
| 894 |
- buf_printf (&buf, " -net %s %s %s", |
|
| 898 |
+ argv_printf_cat (&argv, "-net %s %s %s", |
|
| 895 | 899 |
network, |
| 896 | 900 |
gateway, |
| 897 | 901 |
netmask); |
| 898 | 902 |
|
| 899 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 900 |
- status = system_check (BSTR (&buf), es, 0, "ERROR: OS X route add command failed"); |
|
| 903 |
+ argv_msg (D_ROUTE, &argv); |
|
| 904 |
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: OS X route add command failed"); |
|
| 901 | 905 |
|
| 902 | 906 |
#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) |
| 903 | 907 |
|
| 904 |
- buf_printf (&buf, ROUTE_PATH " add"); |
|
| 908 |
+ argv_printf (&argv, "%s add", |
|
| 909 |
+ ROUTE_PATH); |
|
| 905 | 910 |
|
| 906 | 911 |
#if 0 |
| 907 | 912 |
if (r->metric_defined) |
| 908 |
- buf_printf (&buf, " -rtt %d", r->metric); |
|
| 913 |
+ argv_printf_cat (&argv, "-rtt %d", r->metric); |
|
| 909 | 914 |
#endif |
| 910 | 915 |
|
| 911 |
- buf_printf (&buf, " -net %s %s -netmask %s", |
|
| 916 |
+ argv_printf_cat (&argv, "-net %s %s -netmask %s", |
|
| 912 | 917 |
network, |
| 913 | 918 |
gateway, |
| 914 | 919 |
netmask); |
| 915 | 920 |
|
| 916 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 917 |
- status = system_check (BSTR (&buf), es, 0, "ERROR: OpenBSD/NetBSD route add command failed"); |
|
| 921 |
+ argv_msg (D_ROUTE, &argv); |
|
| 922 |
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD/NetBSD route add command failed"); |
|
| 918 | 923 |
|
| 919 | 924 |
#else |
| 920 | 925 |
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 |
| 922 | 922 |
|
| 923 | 923 |
done: |
| 924 | 924 |
r->defined = status; |
| 925 |
+ argv_reset (&argv); |
|
| 925 | 926 |
gc_free (&gc); |
| 926 | 927 |
} |
| 927 | 928 |
|
| ... | ... |
@@ -929,7 +939,7 @@ static void |
| 929 | 929 |
delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es) |
| 930 | 930 |
{
|
| 931 | 931 |
struct gc_arena gc; |
| 932 |
- struct buffer buf; |
|
| 932 |
+ struct argv argv; |
|
| 933 | 933 |
const char *network; |
| 934 | 934 |
const char *netmask; |
| 935 | 935 |
const char *gateway; |
| ... | ... |
@@ -938,37 +948,40 @@ delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags |
| 938 | 938 |
return; |
| 939 | 939 |
|
| 940 | 940 |
gc_init (&gc); |
| 941 |
+ argv_init (&argv); |
|
| 941 | 942 |
|
| 942 |
- buf = alloc_buf_gc (256, &gc); |
|
| 943 | 943 |
network = print_in_addr_t (r->network, 0, &gc); |
| 944 | 944 |
netmask = print_in_addr_t (r->netmask, 0, &gc); |
| 945 | 945 |
gateway = print_in_addr_t (r->gateway, 0, &gc); |
| 946 | 946 |
|
| 947 | 947 |
#if defined(TARGET_LINUX) |
| 948 | 948 |
#ifdef CONFIG_FEATURE_IPROUTE |
| 949 |
- buf_printf (&buf, "%s route del %s/%d", |
|
| 949 |
+ argv_printf (&argv, "%s route del %s/%d", |
|
| 950 | 950 |
iproute_path, |
| 951 | 951 |
network, |
| 952 | 952 |
count_netmask_bits(netmask)); |
| 953 | 953 |
#else |
| 954 | 954 |
|
| 955 |
- buf_printf (&buf, ROUTE_PATH " del -net %s netmask %s", |
|
| 955 |
+ argv_printf (&argv, "%s del -net %s netmask %s", |
|
| 956 |
+ ROUTE_PATH, |
|
| 956 | 957 |
network, |
| 957 | 958 |
netmask); |
| 958 | 959 |
#endif /*CONFIG_FEATURE_IPROUTE*/ |
| 959 | 960 |
if (r->metric_defined) |
| 960 |
- buf_printf (&buf, " metric %d", r->metric); |
|
| 961 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 962 |
- system_check (BSTR (&buf), es, 0, "ERROR: Linux route delete command failed"); |
|
| 961 |
+ argv_printf_cat (&argv, "metric %d", r->metric); |
|
| 962 |
+ argv_msg (D_ROUTE, &argv); |
|
| 963 |
+ openvpn_execve_check (&argv, es, 0, "ERROR: Linux route delete command failed"); |
|
| 963 | 964 |
|
| 964 | 965 |
#elif defined (WIN32) |
| 965 | 966 |
|
| 966 |
- buf_printf (&buf, ROUTE_PATH " DELETE %s MASK %s %s", |
|
| 967 |
- network, |
|
| 968 |
- netmask, |
|
| 969 |
- gateway); |
|
| 967 |
+ argv_printf (&argv, "%s%s DELETE %s MASK %s %s", |
|
| 968 |
+ get_win_sys_path(), |
|
| 969 |
+ WIN_ROUTE_PATH_SUFFIX, |
|
| 970 |
+ network, |
|
| 971 |
+ netmask, |
|
| 972 |
+ gateway); |
|
| 970 | 973 |
|
| 971 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 974 |
+ argv_msg (D_ROUTE, &argv); |
|
| 972 | 975 |
|
| 973 | 976 |
if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI) |
| 974 | 977 |
{
|
| ... | ... |
@@ -978,7 +991,7 @@ delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags |
| 978 | 978 |
else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_EXE) |
| 979 | 979 |
{
|
| 980 | 980 |
netcmd_semaphore_lock (); |
| 981 |
- system_check (BSTR (&buf), es, 0, "ERROR: Windows route delete command failed"); |
|
| 981 |
+ openvpn_execve_check (&argv, es, 0, "ERROR: Windows route delete command failed"); |
|
| 982 | 982 |
netcmd_semaphore_release (); |
| 983 | 983 |
} |
| 984 | 984 |
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 |
| 989 | 989 |
{
|
| 990 | 990 |
msg (D_ROUTE, "Route deletion fallback to route.exe"); |
| 991 | 991 |
netcmd_semaphore_lock (); |
| 992 |
- system_check (BSTR (&buf), es, 0, "ERROR: Windows route delete command failed [adaptive]"); |
|
| 992 |
+ openvpn_execve_check (&argv, es, 0, "ERROR: Windows route delete command failed [adaptive]"); |
|
| 993 | 993 |
netcmd_semaphore_release (); |
| 994 | 994 |
} |
| 995 | 995 |
} |
| ... | ... |
@@ -1000,58 +1013,64 @@ delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags |
| 1000 | 1000 |
|
| 1001 | 1001 |
#elif defined (TARGET_SOLARIS) |
| 1002 | 1002 |
|
| 1003 |
- buf_printf (&buf, ROUTE_PATH " delete %s -netmask %s %s", |
|
| 1003 |
+ argv_printf (&argv, "%s delete %s -netmask %s %s", |
|
| 1004 |
+ ROUTE_PATH, |
|
| 1004 | 1005 |
network, |
| 1005 | 1006 |
netmask, |
| 1006 | 1007 |
gateway); |
| 1007 | 1008 |
|
| 1008 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 1009 |
- system_check (BSTR (&buf), es, 0, "ERROR: Solaris route delete command failed"); |
|
| 1009 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1010 |
+ openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route delete command failed"); |
|
| 1010 | 1011 |
|
| 1011 | 1012 |
#elif defined(TARGET_FREEBSD) |
| 1012 | 1013 |
|
| 1013 |
- buf_printf (&buf, ROUTE_PATH " delete -net %s %s %s", |
|
| 1014 |
+ argv_printf (&argv, "%s delete -net %s %s %s", |
|
| 1015 |
+ ROUTE_PATH, |
|
| 1014 | 1016 |
network, |
| 1015 | 1017 |
gateway, |
| 1016 | 1018 |
netmask); |
| 1017 | 1019 |
|
| 1018 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 1019 |
- system_check (BSTR (&buf), es, 0, "ERROR: FreeBSD route delete command failed"); |
|
| 1020 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1021 |
+ openvpn_execve_check (&argv, es, 0, "ERROR: FreeBSD route delete command failed"); |
|
| 1020 | 1022 |
|
| 1021 | 1023 |
#elif defined(TARGET_DRAGONFLY) |
| 1022 | 1024 |
|
| 1023 |
- buf_printf (&buf, ROUTE_PATH " delete -net %s %s %s", |
|
| 1025 |
+ argv_printf (&argv, "%s delete -net %s %s %s", |
|
| 1026 |
+ ROUTE_PATH, |
|
| 1024 | 1027 |
network, |
| 1025 | 1028 |
gateway, |
| 1026 | 1029 |
netmask); |
| 1027 | 1030 |
|
| 1028 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 1029 |
- system_check (BSTR (&buf), es, 0, "ERROR: DragonFly route delete command failed"); |
|
| 1031 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1032 |
+ openvpn_execve_check (&argv, es, 0, "ERROR: DragonFly route delete command failed"); |
|
| 1030 | 1033 |
|
| 1031 | 1034 |
#elif defined(TARGET_DARWIN) |
| 1032 | 1035 |
|
| 1033 |
- buf_printf (&buf, ROUTE_PATH " delete -net %s %s %s", |
|
| 1036 |
+ argv_printf (&argv, "%s delete -net %s %s %s", |
|
| 1037 |
+ ROUTE_PATH, |
|
| 1034 | 1038 |
network, |
| 1035 | 1039 |
gateway, |
| 1036 | 1040 |
netmask); |
| 1037 | 1041 |
|
| 1038 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 1039 |
- system_check (BSTR (&buf), es, 0, "ERROR: OS X route delete command failed"); |
|
| 1042 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1043 |
+ openvpn_execve_check (&argv, es, 0, "ERROR: OS X route delete command failed"); |
|
| 1040 | 1044 |
|
| 1041 | 1045 |
#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) |
| 1042 | 1046 |
|
| 1043 |
- buf_printf (&buf, ROUTE_PATH " delete -net %s %s -netmask %s", |
|
| 1047 |
+ argv_printf (&argv, "%s delete -net %s %s -netmask %s", |
|
| 1048 |
+ ROUTE_PATH, |
|
| 1044 | 1049 |
network, |
| 1045 | 1050 |
gateway, |
| 1046 | 1051 |
netmask); |
| 1047 | 1052 |
|
| 1048 |
- msg (D_ROUTE, "%s", BSTR (&buf)); |
|
| 1049 |
- system_check (BSTR (&buf), es, 0, "ERROR: OpenBSD/NetBSD route delete command failed"); |
|
| 1053 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1054 |
+ openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD/NetBSD route delete command failed"); |
|
| 1050 | 1055 |
|
| 1051 | 1056 |
#else |
| 1052 | 1057 |
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"); |
| 1053 | 1058 |
#endif |
| 1054 | 1059 |
|
| 1060 |
+ argv_reset (&argv); |
|
| 1055 | 1061 |
gc_free (&gc); |
| 1056 | 1062 |
} |
| 1057 | 1063 |
|
| ... | ... |
@@ -1480,6 +1480,22 @@ setenv_trusted (struct env_set *es, const struct link_socket_info *info) |
| 1480 | 1480 |
setenv_link_socket_actual (es, "trusted", &info->lsa->actual, SA_IP_PORT); |
| 1481 | 1481 |
} |
| 1482 | 1482 |
|
| 1483 |
+static void |
|
| 1484 |
+ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc) |
|
| 1485 |
+{
|
|
| 1486 |
+ const char *ip = print_sockaddr_ex (&info->lsa->actual.dest, NULL, 0, gc); |
|
| 1487 |
+ const char *port = print_sockaddr_ex (&info->lsa->actual.dest, NULL, PS_DONT_SHOW_ADDR|PS_SHOW_PORT, gc); |
|
| 1488 |
+ if (include_cmd) |
|
| 1489 |
+ argv_printf (argv, "%s %s %s", |
|
| 1490 |
+ info->ipchange_command, |
|
| 1491 |
+ ip, |
|
| 1492 |
+ port); |
|
| 1493 |
+ else |
|
| 1494 |
+ argv_printf (argv, "%s %s", |
|
| 1495 |
+ ip, |
|
| 1496 |
+ port); |
|
| 1497 |
+} |
|
| 1498 |
+ |
|
| 1483 | 1499 |
void |
| 1484 | 1500 |
link_socket_connection_initiated (const struct buffer *buf, |
| 1485 | 1501 |
struct link_socket_info *info, |
| ... | ... |
@@ -1508,20 +1524,21 @@ link_socket_connection_initiated (const struct buffer *buf, |
| 1508 | 1508 |
/* Process --ipchange plugin */ |
| 1509 | 1509 |
if (plugin_defined (info->plugins, OPENVPN_PLUGIN_IPCHANGE)) |
| 1510 | 1510 |
{
|
| 1511 |
- const char *addr_ascii = print_sockaddr_ex (&info->lsa->actual.dest, " ", PS_SHOW_PORT, &gc); |
|
| 1512 |
- if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, addr_ascii, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 1511 |
+ struct argv argv = argv_new (); |
|
| 1512 |
+ ipchange_fmt (false, &argv, info, &gc); |
|
| 1513 |
+ if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 1513 | 1514 |
msg (M_WARN, "WARNING: ipchange plugin call failed"); |
| 1515 |
+ argv_reset (&argv); |
|
| 1514 | 1516 |
} |
| 1515 | 1517 |
|
| 1516 | 1518 |
/* Process --ipchange option */ |
| 1517 | 1519 |
if (info->ipchange_command) |
| 1518 | 1520 |
{
|
| 1519 |
- struct buffer out = alloc_buf_gc (256, &gc); |
|
| 1521 |
+ struct argv argv = argv_new (); |
|
| 1520 | 1522 |
setenv_str (es, "script_type", "ipchange"); |
| 1521 |
- buf_printf (&out, "%s %s", |
|
| 1522 |
- info->ipchange_command, |
|
| 1523 |
- print_sockaddr_ex (&info->lsa->actual.dest, " ", PS_SHOW_PORT, &gc)); |
|
| 1524 |
- system_check (BSTR (&out), es, S_SCRIPT, "ip-change command failed"); |
|
| 1523 |
+ ipchange_fmt (true, &argv, info, &gc); |
|
| 1524 |
+ openvpn_execve_check (&argv, es, S_SCRIPT, "ip-change command failed"); |
|
| 1525 |
+ argv_reset (&argv); |
|
| 1525 | 1526 |
} |
| 1526 | 1527 |
|
| 1527 | 1528 |
gc_free (&gc); |
| ... | ... |
@@ -1791,7 +1808,8 @@ print_sockaddr_ex (const struct openvpn_sockaddr *addr, |
| 1791 | 1791 |
const int port = ntohs (addr->sa.sin_port); |
| 1792 | 1792 |
|
| 1793 | 1793 |
mutex_lock_static (L_INET_NTOA); |
| 1794 |
- buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sa.sin_addr) : "[undef]")); |
|
| 1794 |
+ if (!(flags & PS_DONT_SHOW_ADDR)) |
|
| 1795 |
+ buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sa.sin_addr) : "[undef]")); |
|
| 1795 | 1796 |
mutex_unlock_static (L_INET_NTOA); |
| 1796 | 1797 |
|
| 1797 | 1798 |
if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED))) |
| ... | ... |
@@ -325,6 +325,7 @@ void link_socket_close (struct link_socket *sock); |
| 325 | 325 |
#define PS_SHOW_PORT_IF_DEFINED (1<<0) |
| 326 | 326 |
#define PS_SHOW_PORT (1<<1) |
| 327 | 327 |
#define PS_SHOW_PKTINFO (1<<2) |
| 328 |
+#define PS_DONT_SHOW_ADDR (1<<3) |
|
| 328 | 329 |
|
| 329 | 330 |
const char *print_sockaddr_ex (const struct openvpn_sockaddr *addr, |
| 330 | 331 |
const char* separator, |
| ... | ... |
@@ -544,6 +544,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) |
| 544 | 544 |
struct tls_session *session; |
| 545 | 545 |
const struct tls_options *opt; |
| 546 | 546 |
const int max_depth = 8; |
| 547 |
+ struct argv argv = argv_new (); |
|
| 547 | 548 |
|
| 548 | 549 |
/* get the tls_session pointer */ |
| 549 | 550 |
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) |
| 689 | 689 |
/* call --tls-verify plug-in(s) */ |
| 690 | 690 |
if (plugin_defined (opt->plugins, OPENVPN_PLUGIN_TLS_VERIFY)) |
| 691 | 691 |
{
|
| 692 |
- char command[256]; |
|
| 693 |
- struct buffer out; |
|
| 694 | 692 |
int ret; |
| 695 | 693 |
|
| 696 |
- buf_set_write (&out, (uint8_t*)command, sizeof (command)); |
|
| 697 |
- buf_printf (&out, "%d %s", |
|
| 698 |
- ctx->error_depth, |
|
| 699 |
- subject); |
|
| 694 |
+ argv_printf (&argv, "%d %s", |
|
| 695 |
+ ctx->error_depth, |
|
| 696 |
+ subject); |
|
| 700 | 697 |
|
| 701 |
- ret = plugin_call (opt->plugins, OPENVPN_PLUGIN_TLS_VERIFY, command, NULL, opt->es); |
|
| 698 |
+ ret = plugin_call (opt->plugins, OPENVPN_PLUGIN_TLS_VERIFY, &argv, NULL, opt->es); |
|
| 702 | 699 |
|
| 703 | 700 |
if (ret == OPENVPN_PLUGIN_FUNC_SUCCESS) |
| 704 | 701 |
{
|
| ... | ... |
@@ -716,19 +714,16 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) |
| 716 | 716 |
/* run --tls-verify script */ |
| 717 | 717 |
if (opt->verify_command) |
| 718 | 718 |
{
|
| 719 |
- char command[256]; |
|
| 720 |
- struct buffer out; |
|
| 721 | 719 |
int ret; |
| 722 | 720 |
|
| 723 | 721 |
setenv_str (opt->es, "script_type", "tls-verify"); |
| 724 | 722 |
|
| 725 |
- buf_set_write (&out, (uint8_t*)command, sizeof (command)); |
|
| 726 |
- buf_printf (&out, "%s %d %s", |
|
| 727 |
- opt->verify_command, |
|
| 728 |
- ctx->error_depth, |
|
| 729 |
- subject); |
|
| 730 |
- dmsg (D_TLS_DEBUG, "TLS: executing verify command: %s", command); |
|
| 731 |
- ret = openvpn_system (command, opt->es, S_SCRIPT); |
|
| 723 |
+ argv_printf (&argv, "%s %d %s", |
|
| 724 |
+ opt->verify_command, |
|
| 725 |
+ ctx->error_depth, |
|
| 726 |
+ subject); |
|
| 727 |
+ argv_msg_prefix (D_TLS_DEBUG, &argv, "TLS: executing verify command"); |
|
| 728 |
+ ret = openvpn_execve (&argv, opt->es, S_SCRIPT); |
|
| 732 | 729 |
|
| 733 | 730 |
if (system_ok (ret)) |
| 734 | 731 |
{
|
| ... | ... |
@@ -738,7 +733,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) |
| 738 | 738 |
else |
| 739 | 739 |
{
|
| 740 | 740 |
if (!system_executed (ret)) |
| 741 |
- msg (M_ERR, "Verify command failed to execute: %s", command); |
|
| 741 |
+ argv_msg_prefix (M_ERR, &argv, "Verify command failed to execute"); |
|
| 742 | 742 |
msg (D_HANDSHAKE, "VERIFY SCRIPT ERROR: depth=%d, %s", |
| 743 | 743 |
ctx->error_depth, subject); |
| 744 | 744 |
goto err; /* Reject connection */ |
| ... | ... |
@@ -801,11 +796,13 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) |
| 801 | 801 |
|
| 802 | 802 |
session->verified = true; |
| 803 | 803 |
free (subject); |
| 804 |
+ argv_reset (&argv); |
|
| 804 | 805 |
return 1; /* Accept connection */ |
| 805 | 806 |
|
| 806 | 807 |
err: |
| 807 | 808 |
ERR_clear_error (); |
| 808 | 809 |
free (subject); |
| 810 |
+ argv_reset (&argv); |
|
| 809 | 811 |
return 0; /* Reject connection */ |
| 810 | 812 |
} |
| 811 | 813 |
|
| ... | ... |
@@ -2901,7 +2898,7 @@ static bool |
| 2901 | 2901 |
verify_user_pass_script (struct tls_session *session, const struct user_pass *up) |
| 2902 | 2902 |
{
|
| 2903 | 2903 |
struct gc_arena gc = gc_new (); |
| 2904 |
- struct buffer cmd = alloc_buf_gc (256, &gc); |
|
| 2904 |
+ struct argv argv = argv_new (); |
|
| 2905 | 2905 |
const char *tmp_file = ""; |
| 2906 | 2906 |
int retval; |
| 2907 | 2907 |
bool ret = false; |
| ... | ... |
@@ -2940,16 +2937,16 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up |
| 2940 | 2940 |
setenv_untrusted (session); |
| 2941 | 2941 |
|
| 2942 | 2942 |
/* format command line */ |
| 2943 |
- buf_printf (&cmd, "%s %s", session->opt->auth_user_pass_verify_script, tmp_file); |
|
| 2943 |
+ argv_printf (&argv, "%s %s", session->opt->auth_user_pass_verify_script, tmp_file); |
|
| 2944 | 2944 |
|
| 2945 | 2945 |
/* call command */ |
| 2946 |
- retval = openvpn_system (BSTR (&cmd), session->opt->es, S_SCRIPT); |
|
| 2946 |
+ retval = openvpn_execve (&argv, session->opt->es, S_SCRIPT); |
|
| 2947 | 2947 |
|
| 2948 | 2948 |
/* test return status of command */ |
| 2949 | 2949 |
if (system_ok (retval)) |
| 2950 | 2950 |
ret = true; |
| 2951 | 2951 |
else if (!system_executed (retval)) |
| 2952 |
- msg (D_TLS_ERRORS, "TLS Auth Error: user-pass-verify script failed to execute: %s", BSTR (&cmd)); |
|
| 2952 |
+ argv_msg_prefix (D_TLS_ERRORS, &argv, "TLS Auth Error: user-pass-verify script failed to execute"); |
|
| 2953 | 2953 |
|
| 2954 | 2954 |
if (!session->opt->auth_user_pass_verify_script_via_file) |
| 2955 | 2955 |
setenv_del (session->opt->es, "password"); |
| ... | ... |
@@ -2963,6 +2960,7 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up |
| 2963 | 2963 |
if (strlen (tmp_file) > 0) |
| 2964 | 2964 |
delete_file (tmp_file); |
| 2965 | 2965 |
|
| 2966 |
+ argv_reset (&argv); |
|
| 2966 | 2967 |
gc_free (&gc); |
| 2967 | 2968 |
return ret; |
| 2968 | 2969 |
} |
| ... | ... |
@@ -448,6 +448,14 @@ socket_defined (const socket_descriptor_t sd) |
| 448 | 448 |
#define USE_64_BIT_COUNTERS |
| 449 | 449 |
|
| 450 | 450 |
/* |
| 451 |
+ * Should we enable the use of execve() for calling subprocesses, |
|
| 452 |
+ * instead of system()? |
|
| 453 |
+ */ |
|
| 454 |
+#if defined(HAVE_EXECVE) && defined(HAVE_FORK) |
|
| 455 |
+#define ENABLE_EXECVE |
|
| 456 |
+#endif |
|
| 457 |
+ |
|
| 458 |
+/* |
|
| 451 | 459 |
* Do we have point-to-multipoint capability? |
| 452 | 460 |
*/ |
| 453 | 461 |
|
| ... | ... |
@@ -39,6 +39,7 @@ |
| 39 | 39 |
#include "socket.h" |
| 40 | 40 |
#include "manage.h" |
| 41 | 41 |
#include "route.h" |
| 42 |
+#include "win32.h" |
|
| 42 | 43 |
|
| 43 | 44 |
#include "memdbg.h" |
| 44 | 45 |
|
| ... | ... |
@@ -534,7 +535,9 @@ do_ifconfig (struct tuntap *tt, |
| 534 | 534 |
const char *ifconfig_local = NULL; |
| 535 | 535 |
const char *ifconfig_remote_netmask = NULL; |
| 536 | 536 |
const char *ifconfig_broadcast = NULL; |
| 537 |
- char command_line[256]; |
|
| 537 |
+ struct argv argv; |
|
| 538 |
+ |
|
| 539 |
+ argv_init (&argv); |
|
| 538 | 540 |
|
| 539 | 541 |
/* |
| 540 | 542 |
* We only handle TUN/TAP devices here, not --dev null devices. |
| ... | ... |
@@ -570,31 +573,31 @@ do_ifconfig (struct tuntap *tt, |
| 570 | 570 |
/* |
| 571 | 571 |
* Set the MTU for the device |
| 572 | 572 |
*/ |
| 573 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 573 |
+ argv_printf (&argv, |
|
| 574 | 574 |
"%s link set dev %s up mtu %d", |
| 575 | 575 |
iproute_path, |
| 576 | 576 |
actual, |
| 577 | 577 |
tun_mtu |
| 578 | 578 |
); |
| 579 |
- msg (M_INFO, "%s", command_line); |
|
| 580 |
- system_check (command_line, es, S_FATAL, "Linux ip link set failed"); |
|
| 579 |
+ argv_msg (M_INFO, &argv); |
|
| 580 |
+ openvpn_execve_check (&argv, es, S_FATAL, "Linux ip link set failed"); |
|
| 581 | 581 |
|
| 582 | 582 |
if (tun) {
|
| 583 | 583 |
|
| 584 | 584 |
/* |
| 585 | 585 |
* Set the address for the device |
| 586 | 586 |
*/ |
| 587 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 587 |
+ argv_printf (&argv, |
|
| 588 | 588 |
"%s addr add dev %s local %s peer %s", |
| 589 | 589 |
iproute_path, |
| 590 | 590 |
actual, |
| 591 | 591 |
ifconfig_local, |
| 592 | 592 |
ifconfig_remote_netmask |
| 593 | 593 |
); |
| 594 |
- msg (M_INFO, "%s", command_line); |
|
| 595 |
- system_check (command_line, es, S_FATAL, "Linux ip addr add failed"); |
|
| 594 |
+ argv_msg (M_INFO, &argv); |
|
| 595 |
+ openvpn_execve_check (&argv, es, S_FATAL, "Linux ip addr add failed"); |
|
| 596 | 596 |
} else {
|
| 597 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 597 |
+ argv_printf (&argv, |
|
| 598 | 598 |
"%s addr add dev %s %s/%d broadcast %s", |
| 599 | 599 |
iproute_path, |
| 600 | 600 |
actual, |
| ... | ... |
@@ -602,30 +605,32 @@ do_ifconfig (struct tuntap *tt, |
| 602 | 602 |
count_netmask_bits(ifconfig_remote_netmask), |
| 603 | 603 |
ifconfig_broadcast |
| 604 | 604 |
); |
| 605 |
- msg (M_INFO, "%s", command_line); |
|
| 606 |
- system_check (command_line, es, S_FATAL, "Linux ip addr add failed"); |
|
| 605 |
+ argv_msg (M_INFO, &argv); |
|
| 606 |
+ openvpn_execve_check (&argv, es, S_FATAL, "Linux ip addr add failed"); |
|
| 607 | 607 |
} |
| 608 | 608 |
tt->did_ifconfig = true; |
| 609 | 609 |
#else |
| 610 | 610 |
if (tun) |
| 611 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 612 |
- IFCONFIG_PATH " %s %s pointopoint %s mtu %d", |
|
| 611 |
+ argv_printf (&argv, |
|
| 612 |
+ "%s %s %s pointopoint %s mtu %d", |
|
| 613 |
+ IFCONFIG_PATH, |
|
| 613 | 614 |
actual, |
| 614 | 615 |
ifconfig_local, |
| 615 | 616 |
ifconfig_remote_netmask, |
| 616 | 617 |
tun_mtu |
| 617 | 618 |
); |
| 618 | 619 |
else |
| 619 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 620 |
- IFCONFIG_PATH " %s %s netmask %s mtu %d broadcast %s", |
|
| 620 |
+ argv_printf (&argv, |
|
| 621 |
+ "%s %s %s netmask %s mtu %d broadcast %s", |
|
| 622 |
+ IFCONFIG_PATH, |
|
| 621 | 623 |
actual, |
| 622 | 624 |
ifconfig_local, |
| 623 | 625 |
ifconfig_remote_netmask, |
| 624 | 626 |
tun_mtu, |
| 625 | 627 |
ifconfig_broadcast |
| 626 | 628 |
); |
| 627 |
- msg (M_INFO, "%s", command_line); |
|
| 628 |
- system_check (command_line, es, S_FATAL, "Linux ifconfig failed"); |
|
| 629 |
+ argv_msg (M_INFO, &argv); |
|
| 630 |
+ openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig failed"); |
|
| 629 | 631 |
tt->did_ifconfig = true; |
| 630 | 632 |
|
| 631 | 633 |
#endif /*CONFIG_FEATURE_IPROUTE*/ |
| ... | ... |
@@ -638,28 +643,30 @@ do_ifconfig (struct tuntap *tt, |
| 638 | 638 |
*/ |
| 639 | 639 |
if (tun) |
| 640 | 640 |
{
|
| 641 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 642 |
- IFCONFIG_PATH " %s %s %s mtu %d up", |
|
| 641 |
+ argv_printf (&argv, |
|
| 642 |
+ "%s %s %s %s mtu %d up", |
|
| 643 |
+ IFCONFIG_PATH, |
|
| 643 | 644 |
actual, |
| 644 | 645 |
ifconfig_local, |
| 645 | 646 |
ifconfig_remote_netmask, |
| 646 | 647 |
tun_mtu |
| 647 | 648 |
); |
| 648 | 649 |
|
| 649 |
- msg (M_INFO, "%s", command_line); |
|
| 650 |
- if (!system_check (command_line, es, 0, "Solaris ifconfig phase-1 failed")) |
|
| 650 |
+ argv_msg (M_INFO, &argv); |
|
| 651 |
+ if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-1 failed")) |
|
| 651 | 652 |
solaris_error_close (tt, es, actual); |
| 652 | 653 |
|
| 653 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 654 |
- IFCONFIG_PATH " %s netmask 255.255.255.255", |
|
| 654 |
+ argv_printf (&argv, |
|
| 655 |
+ "%s %s netmask 255.255.255.255", |
|
| 656 |
+ IFCONFIG_PATH, |
|
| 655 | 657 |
actual |
| 656 | 658 |
); |
| 657 | 659 |
} |
| 658 | 660 |
else |
| 659 | 661 |
no_tap_ifconfig (); |
| 660 | 662 |
|
| 661 |
- msg (M_INFO, "%s", command_line); |
|
| 662 |
- if (!system_check (command_line, es, 0, "Solaris ifconfig phase-2 failed")) |
|
| 663 |
+ argv_msg (M_INFO, &argv); |
|
| 664 |
+ if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-2 failed")) |
|
| 663 | 665 |
solaris_error_close (tt, es, actual); |
| 664 | 666 |
|
| 665 | 667 |
tt->did_ifconfig = true; |
| ... | ... |
@@ -672,45 +679,50 @@ do_ifconfig (struct tuntap *tt, |
| 672 | 672 |
* (if it exists), and re-ifconfig. Let me know if you know a better way. |
| 673 | 673 |
*/ |
| 674 | 674 |
|
| 675 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 676 |
- IFCONFIG_PATH " %s destroy", |
|
| 675 |
+ argv_printf (&argv, |
|
| 676 |
+ "%s %s destroy", |
|
| 677 |
+ IFCONFIG_PATH, |
|
| 677 | 678 |
actual); |
| 678 |
- msg (M_INFO, "%s", command_line); |
|
| 679 |
- system_check (command_line, es, 0, NULL); |
|
| 680 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 681 |
- IFCONFIG_PATH " %s create", |
|
| 679 |
+ argv_msg (M_INFO, &argv); |
|
| 680 |
+ openvpn_execve_check (&argv, es, 0, NULL); |
|
| 681 |
+ argv_printf (&argv, |
|
| 682 |
+ "%s %s create", |
|
| 683 |
+ IFCONFIG_PATH, |
|
| 682 | 684 |
actual); |
| 683 |
- msg (M_INFO, "%s", command_line); |
|
| 684 |
- system_check (command_line, es, 0, NULL); |
|
| 685 |
+ argv_msg (M_INFO, &argv); |
|
| 686 |
+ openvpn_execve_check (&argv, es, 0, NULL); |
|
| 685 | 687 |
msg (M_INFO, "NOTE: Tried to delete pre-existing tun/tap instance -- No Problem if failure"); |
| 686 | 688 |
|
| 687 | 689 |
/* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */ |
| 688 | 690 |
if (tun) |
| 689 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 690 |
- IFCONFIG_PATH " %s %s %s mtu %d netmask 255.255.255.255 up", |
|
| 691 |
+ argv_printf (&argv, |
|
| 692 |
+ "%s %s %s %s mtu %d netmask 255.255.255.255 up", |
|
| 693 |
+ IFCONFIG_PATH, |
|
| 691 | 694 |
actual, |
| 692 | 695 |
ifconfig_local, |
| 693 | 696 |
ifconfig_remote_netmask, |
| 694 | 697 |
tun_mtu |
| 695 | 698 |
); |
| 696 | 699 |
else |
| 697 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 698 |
- IFCONFIG_PATH " %s %s netmask %s mtu %d broadcast %s link0", |
|
| 700 |
+ argv_printf (&argv, |
|
| 701 |
+ "%s %s %s netmask %s mtu %d broadcast %s link0", |
|
| 702 |
+ IFCONFIG_PATH, |
|
| 699 | 703 |
actual, |
| 700 | 704 |
ifconfig_local, |
| 701 | 705 |
ifconfig_remote_netmask, |
| 702 | 706 |
tun_mtu, |
| 703 | 707 |
ifconfig_broadcast |
| 704 | 708 |
); |
| 705 |
- msg (M_INFO, "%s", command_line); |
|
| 706 |
- system_check (command_line, es, S_FATAL, "OpenBSD ifconfig failed"); |
|
| 709 |
+ argv_msg (M_INFO, &argv); |
|
| 710 |
+ openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig failed"); |
|
| 707 | 711 |
tt->did_ifconfig = true; |
| 708 | 712 |
|
| 709 | 713 |
#elif defined(TARGET_NETBSD) |
| 710 | 714 |
|
| 711 | 715 |
if (tun) |
| 712 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 713 |
- IFCONFIG_PATH " %s %s %s mtu %d netmask 255.255.255.255 up", |
|
| 716 |
+ argv_printf (&argv, |
|
| 717 |
+ "%s %s %s %s mtu %d netmask 255.255.255.255 up", |
|
| 718 |
+ IFCONFIG_PATH, |
|
| 714 | 719 |
actual, |
| 715 | 720 |
ifconfig_local, |
| 716 | 721 |
ifconfig_remote_netmask, |
| ... | ... |
@@ -722,16 +734,17 @@ do_ifconfig (struct tuntap *tt, |
| 722 | 722 |
* so we don't need the "link0" extra parameter to specify we want to do |
| 723 | 723 |
* tunneling at the ethernet level |
| 724 | 724 |
*/ |
| 725 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 726 |
- IFCONFIG_PATH " %s %s netmask %s mtu %d broadcast %s", |
|
| 725 |
+ argv_printf (&argv, |
|
| 726 |
+ "%s %s %s netmask %s mtu %d broadcast %s", |
|
| 727 |
+ IFCONFIG_PATH, |
|
| 727 | 728 |
actual, |
| 728 | 729 |
ifconfig_local, |
| 729 | 730 |
ifconfig_remote_netmask, |
| 730 | 731 |
tun_mtu, |
| 731 | 732 |
ifconfig_broadcast |
| 732 | 733 |
); |
| 733 |
- msg (M_INFO, "%s", command_line); |
|
| 734 |
- system_check (command_line, es, S_FATAL, "NetBSD ifconfig failed"); |
|
| 734 |
+ argv_msg (M_INFO, &argv); |
|
| 735 |
+ openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig failed"); |
|
| 735 | 736 |
tt->did_ifconfig = true; |
| 736 | 737 |
|
| 737 | 738 |
#elif defined(TARGET_DARWIN) |
| ... | ... |
@@ -740,18 +753,20 @@ do_ifconfig (struct tuntap *tt, |
| 740 | 740 |
* Darwin (i.e. Mac OS X) seems to exhibit similar behaviour to OpenBSD... |
| 741 | 741 |
*/ |
| 742 | 742 |
|
| 743 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 744 |
- IFCONFIG_PATH " %s delete", |
|
| 743 |
+ argv_printf (&argv, |
|
| 744 |
+ "%s %s delete", |
|
| 745 |
+ IFCONFIG_PATH, |
|
| 745 | 746 |
actual); |
| 746 |
- msg (M_INFO, "%s", command_line); |
|
| 747 |
- system_check (command_line, es, 0, NULL); |
|
| 747 |
+ argv_msg (M_INFO, &argv); |
|
| 748 |
+ openvpn_execve_check (&argv, es, 0, NULL); |
|
| 748 | 749 |
msg (M_INFO, "NOTE: Tried to delete pre-existing tun/tap instance -- No Problem if failure"); |
| 749 | 750 |
|
| 750 | 751 |
|
| 751 | 752 |
/* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */ |
| 752 | 753 |
if (tun) |
| 753 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 754 |
- IFCONFIG_PATH " %s %s %s mtu %d netmask 255.255.255.255 up", |
|
| 754 |
+ argv_printf (&argv, |
|
| 755 |
+ "%s %s %s %s mtu %d netmask 255.255.255.255 up", |
|
| 756 |
+ IFCONFIG_PATH, |
|
| 755 | 757 |
actual, |
| 756 | 758 |
ifconfig_local, |
| 757 | 759 |
ifconfig_remote_netmask, |
| ... | ... |
@@ -760,8 +775,9 @@ do_ifconfig (struct tuntap *tt, |
| 760 | 760 |
else |
| 761 | 761 |
{
|
| 762 | 762 |
if (tt->topology == TOP_SUBNET) |
| 763 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 764 |
- IFCONFIG_PATH " %s %s %s netmask %s mtu %d up", |
|
| 763 |
+ argv_printf (&argv, |
|
| 764 |
+ "%s %s %s %s netmask %s mtu %d up", |
|
| 765 |
+ IFCONFIG_PATH, |
|
| 765 | 766 |
actual, |
| 766 | 767 |
ifconfig_local, |
| 767 | 768 |
ifconfig_local, |
| ... | ... |
@@ -769,16 +785,17 @@ do_ifconfig (struct tuntap *tt, |
| 769 | 769 |
tun_mtu |
| 770 | 770 |
); |
| 771 | 771 |
else |
| 772 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 773 |
- IFCONFIG_PATH " %s %s netmask %s mtu %d up", |
|
| 772 |
+ argv_printf (&argv, |
|
| 773 |
+ "%s %s %s netmask %s mtu %d up", |
|
| 774 |
+ IFCONFIG_PATH, |
|
| 774 | 775 |
actual, |
| 775 | 776 |
ifconfig_local, |
| 776 | 777 |
ifconfig_remote_netmask, |
| 777 | 778 |
tun_mtu |
| 778 | 779 |
); |
| 779 | 780 |
} |
| 780 |
- msg (M_INFO, "%s", command_line); |
|
| 781 |
- system_check (command_line, es, S_FATAL, "Mac OS X ifconfig failed"); |
|
| 781 |
+ argv_msg (M_INFO, &argv); |
|
| 782 |
+ openvpn_execve_check (&argv, es, S_FATAL, "Mac OS X ifconfig failed"); |
|
| 782 | 783 |
tt->did_ifconfig = true; |
| 783 | 784 |
|
| 784 | 785 |
/* Add a network route for the local tun interface */ |
| ... | ... |
@@ -797,8 +814,9 @@ do_ifconfig (struct tuntap *tt, |
| 797 | 797 |
|
| 798 | 798 |
/* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */ |
| 799 | 799 |
if (tun) |
| 800 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 801 |
- IFCONFIG_PATH " %s %s %s mtu %d netmask 255.255.255.255 up", |
|
| 800 |
+ argv_printf (&argv, |
|
| 801 |
+ "%s %s %s %s mtu %d netmask 255.255.255.255 up", |
|
| 802 |
+ IFCONFIG_PATH, |
|
| 802 | 803 |
actual, |
| 803 | 804 |
ifconfig_local, |
| 804 | 805 |
ifconfig_remote_netmask, |
| ... | ... |
@@ -806,8 +824,9 @@ do_ifconfig (struct tuntap *tt, |
| 806 | 806 |
); |
| 807 | 807 |
else {
|
| 808 | 808 |
if (tt->topology == TOP_SUBNET) |
| 809 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 810 |
- IFCONFIG_PATH " %s %s %s netmask %s mtu %d up", |
|
| 809 |
+ argv_printf (&argv, |
|
| 810 |
+ "%s %s %s %s netmask %s mtu %d up", |
|
| 811 |
+ IFCONFIG_PATH, |
|
| 811 | 812 |
actual, |
| 812 | 813 |
ifconfig_local, |
| 813 | 814 |
ifconfig_local, |
| ... | ... |
@@ -815,8 +834,9 @@ do_ifconfig (struct tuntap *tt, |
| 815 | 815 |
tun_mtu |
| 816 | 816 |
); |
| 817 | 817 |
else |
| 818 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 819 |
- IFCONFIG_PATH " %s %s netmask %s mtu %d up", |
|
| 818 |
+ argv_printf (&argv, |
|
| 819 |
+ "%s %s %s netmask %s mtu %d up", |
|
| 820 |
+ IFCONFIG_PATH, |
|
| 820 | 821 |
actual, |
| 821 | 822 |
ifconfig_local, |
| 822 | 823 |
ifconfig_remote_netmask, |
| ... | ... |
@@ -824,8 +844,8 @@ do_ifconfig (struct tuntap *tt, |
| 824 | 824 |
); |
| 825 | 825 |
} |
| 826 | 826 |
|
| 827 |
- msg (M_INFO, "%s", command_line); |
|
| 828 |
- system_check (command_line, es, S_FATAL, "FreeBSD ifconfig failed"); |
|
| 827 |
+ argv_msg (M_INFO, &argv); |
|
| 828 |
+ openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig failed"); |
|
| 829 | 829 |
tt->did_ifconfig = true; |
| 830 | 830 |
|
| 831 | 831 |
/* Add a network route for the local tun interface */ |
| ... | ... |
@@ -882,6 +902,7 @@ do_ifconfig (struct tuntap *tt, |
| 882 | 882 |
#else |
| 883 | 883 |
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."); |
| 884 | 884 |
#endif |
| 885 |
+ argv_reset (&argv); |
|
| 885 | 886 |
} |
| 886 | 887 |
gc_free (&gc); |
| 887 | 888 |
} |
| ... | ... |
@@ -1216,13 +1237,14 @@ close_tun (struct tuntap *tt) |
| 1216 | 1216 |
{
|
| 1217 | 1217 |
if (tt->type != DEV_TYPE_NULL && tt->did_ifconfig) |
| 1218 | 1218 |
{
|
| 1219 |
- char command_line[256]; |
|
| 1219 |
+ struct argv argv; |
|
| 1220 | 1220 |
struct gc_arena gc = gc_new (); |
| 1221 |
+ argv_init (&argv); |
|
| 1221 | 1222 |
|
| 1222 | 1223 |
#ifdef CONFIG_FEATURE_IPROUTE |
| 1223 | 1224 |
if (is_tun_p2p (tt)) |
| 1224 | 1225 |
{
|
| 1225 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 1226 |
+ argv_printf (&argv, |
|
| 1226 | 1227 |
"%s addr del dev %s local %s peer %s", |
| 1227 | 1228 |
iproute_path, |
| 1228 | 1229 |
tt->actual_name, |
| ... | ... |
@@ -1232,7 +1254,7 @@ close_tun (struct tuntap *tt) |
| 1232 | 1232 |
} |
| 1233 | 1233 |
else |
| 1234 | 1234 |
{
|
| 1235 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 1235 |
+ argv_printf (&argv, |
|
| 1236 | 1236 |
"%s addr del dev %s %s/%d", |
| 1237 | 1237 |
iproute_path, |
| 1238 | 1238 |
tt->actual_name, |
| ... | ... |
@@ -1241,15 +1263,17 @@ close_tun (struct tuntap *tt) |
| 1241 | 1241 |
); |
| 1242 | 1242 |
} |
| 1243 | 1243 |
#else |
| 1244 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 1245 |
- IFCONFIG_PATH " %s 0.0.0.0", |
|
| 1244 |
+ argv_printf (&argv, |
|
| 1245 |
+ "%s %s 0.0.0.0", |
|
| 1246 |
+ IFCONFIG_PATH, |
|
| 1246 | 1247 |
tt->actual_name |
| 1247 | 1248 |
); |
| 1248 | 1249 |
#endif |
| 1249 | 1250 |
|
| 1250 |
- msg (M_INFO, "%s", command_line); |
|
| 1251 |
- system_check (command_line, NULL, 0, "Linux ip addr del failed"); |
|
| 1251 |
+ argv_msg (M_INFO, &argv); |
|
| 1252 |
+ openvpn_execve_check (&argv, NULL, 0, "Linux ip addr del failed"); |
|
| 1252 | 1253 |
|
| 1254 |
+ argv_reset (&argv); |
|
| 1253 | 1255 |
gc_free (&gc); |
| 1254 | 1256 |
} |
| 1255 | 1257 |
close_tun_generic (tt); |
| ... | ... |
@@ -1471,16 +1495,19 @@ close_tun (struct tuntap *tt) |
| 1471 | 1471 |
static void |
| 1472 | 1472 |
solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual) |
| 1473 | 1473 |
{
|
| 1474 |
- char command_line[256]; |
|
| 1474 |
+ struct argv argv; |
|
| 1475 |
+ argv_init (&argv); |
|
| 1475 | 1476 |
|
| 1476 |
- openvpn_snprintf (command_line, sizeof (command_line), |
|
| 1477 |
- IFCONFIG_PATH " %s unplumb", |
|
| 1477 |
+ argv_printf (&argv, |
|
| 1478 |
+ "%s %s unplumb", |
|
| 1479 |
+ IFCONFIG_PATH, |
|
| 1478 | 1480 |
actual); |
| 1479 | 1481 |
|
| 1480 |
- msg (M_INFO, "%s", command_line); |
|
| 1481 |
- system_check (command_line, es, 0, "Solaris ifconfig unplumb failed"); |
|
| 1482 |
+ argv_msg (M_INFO, &argv); |
|
| 1483 |
+ openvpn_execve_check (&argv, es, 0, "Solaris ifconfig unplumb failed"); |
|
| 1482 | 1484 |
close_tun (tt); |
| 1483 | 1485 |
msg (M_FATAL, "Solaris ifconfig failed"); |
| 1486 |
+ argv_reset (&argv); |
|
| 1484 | 1487 |
} |
| 1485 | 1488 |
|
| 1486 | 1489 |
int |
| ... | ... |
@@ -3275,7 +3302,7 @@ dhcp_renew (const struct tuntap *tt) |
| 3275 | 3275 |
*/ |
| 3276 | 3276 |
|
| 3277 | 3277 |
static void |
| 3278 |
-netsh_command (const char *cmd, int n) |
|
| 3278 |
+netsh_command (const struct argv *a, int n) |
|
| 3279 | 3279 |
{
|
| 3280 | 3280 |
int i; |
| 3281 | 3281 |
for (i = 0; i < n; ++i) |
| ... | ... |
@@ -3283,8 +3310,8 @@ netsh_command (const char *cmd, int n) |
| 3283 | 3283 |
bool status; |
| 3284 | 3284 |
openvpn_sleep (1); |
| 3285 | 3285 |
netcmd_semaphore_lock (); |
| 3286 |
- msg (M_INFO, "NETSH: %s", cmd); |
|
| 3287 |
- status = system_check (cmd, NULL, 0, "ERROR: netsh command failed"); |
|
| 3286 |
+ argv_msg_prefix (M_INFO, a, "NETSH"); |
|
| 3287 |
+ status = openvpn_execve_check (a, NULL, 0, "ERROR: netsh command failed"); |
|
| 3288 | 3288 |
netcmd_semaphore_release (); |
| 3289 | 3289 |
if (status) |
| 3290 | 3290 |
return; |
| ... | ... |
@@ -3376,7 +3403,7 @@ netsh_ifconfig_options (const char *type, |
| 3376 | 3376 |
const bool test_first) |
| 3377 | 3377 |
{
|
| 3378 | 3378 |
struct gc_arena gc = gc_new (); |
| 3379 |
- struct buffer out = alloc_buf_gc (256, &gc); |
|
| 3379 |
+ struct argv argv = argv_new (); |
|
| 3380 | 3380 |
bool delete_first = false; |
| 3381 | 3381 |
|
| 3382 | 3382 |
/* first check if we should delete existing DNS/WINS settings from TAP interface */ |
| ... | ... |
@@ -3391,11 +3418,12 @@ netsh_ifconfig_options (const char *type, |
| 3391 | 3391 |
/* delete existing DNS/WINS settings from TAP interface */ |
| 3392 | 3392 |
if (delete_first) |
| 3393 | 3393 |
{
|
| 3394 |
- buf_init (&out, 0); |
|
| 3395 |
- buf_printf (&out, "netsh interface ip delete %s \"%s\" all", |
|
| 3396 |
- type, |
|
| 3397 |
- flex_name); |
|
| 3398 |
- netsh_command (BSTR(&out), 2); |
|
| 3394 |
+ argv_printf (&argv, "%s%s interface ip delete %s %s all", |
|
| 3395 |
+ get_win_sys_path(), |
|
| 3396 |
+ NETSH_PATH_SUFFIX, |
|
| 3397 |
+ type, |
|
| 3398 |
+ flex_name); |
|
| 3399 |
+ netsh_command (&argv, 2); |
|
| 3399 | 3400 |
} |
| 3400 | 3401 |
|
| 3401 | 3402 |
/* add new DNS/WINS settings to TAP interface */ |
| ... | ... |
@@ -3407,15 +3435,16 @@ netsh_ifconfig_options (const char *type, |
| 3407 | 3407 |
if (delete_first || !test_first || !ip_addr_member_of (addr_list[i], current)) |
| 3408 | 3408 |
{
|
| 3409 | 3409 |
const char *fmt = count ? |
| 3410 |
- "netsh interface ip add %s \"%s\" %s" |
|
| 3411 |
- : "netsh interface ip set %s \"%s\" static %s"; |
|
| 3412 |
- |
|
| 3413 |
- buf_init (&out, 0); |
|
| 3414 |
- buf_printf (&out, fmt, |
|
| 3415 |
- type, |
|
| 3416 |
- flex_name, |
|
| 3417 |
- print_in_addr_t (addr_list[i], 0, &gc)); |
|
| 3418 |
- netsh_command (BSTR(&out), 2); |
|
| 3410 |
+ "%s%s interface ip add %s %s %s" |
|
| 3411 |
+ : "%s%s interface ip set %s %s static %s"; |
|
| 3412 |
+ |
|
| 3413 |
+ argv_printf (&argv, fmt, |
|
| 3414 |
+ get_win_sys_path(), |
|
| 3415 |
+ NETSH_PATH_SUFFIX, |
|
| 3416 |
+ type, |
|
| 3417 |
+ flex_name, |
|
| 3418 |
+ print_in_addr_t (addr_list[i], 0, &gc)); |
|
| 3419 |
+ netsh_command (&argv, 2); |
|
| 3419 | 3420 |
|
| 3420 | 3421 |
++count; |
| 3421 | 3422 |
} |
| ... | ... |
@@ -3429,6 +3458,7 @@ netsh_ifconfig_options (const char *type, |
| 3429 | 3429 |
} |
| 3430 | 3430 |
} |
| 3431 | 3431 |
|
| 3432 |
+ argv_reset (&argv); |
|
| 3432 | 3433 |
gc_free (&gc); |
| 3433 | 3434 |
} |
| 3434 | 3435 |
|
| ... | ... |
@@ -3458,7 +3488,7 @@ netsh_ifconfig (const struct tuntap_options *to, |
| 3458 | 3458 |
const unsigned int flags) |
| 3459 | 3459 |
{
|
| 3460 | 3460 |
struct gc_arena gc = gc_new (); |
| 3461 |
- struct buffer out = alloc_buf_gc (256, &gc); |
|
| 3461 |
+ struct argv argv = argv_new (); |
|
| 3462 | 3462 |
const IP_ADAPTER_INFO *ai = NULL; |
| 3463 | 3463 |
const IP_PER_ADAPTER_INFO *pai = NULL; |
| 3464 | 3464 |
|
| ... | ... |
@@ -3482,14 +3512,15 @@ netsh_ifconfig (const struct tuntap_options *to, |
| 3482 | 3482 |
else |
| 3483 | 3483 |
{
|
| 3484 | 3484 |
/* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */ |
| 3485 |
- buf_init (&out, 0); |
|
| 3486 |
- buf_printf (&out, |
|
| 3487 |
- "netsh interface ip set address \"%s\" static %s %s", |
|
| 3488 |
- flex_name, |
|
| 3489 |
- print_in_addr_t (ip, 0, &gc), |
|
| 3490 |
- print_in_addr_t (netmask, 0, &gc)); |
|
| 3491 |
- |
|
| 3492 |
- netsh_command (BSTR(&out), 4); |
|
| 3485 |
+ argv_printf (&argv, |
|
| 3486 |
+ "%s%s interface ip set address %s static %s %s", |
|
| 3487 |
+ get_win_sys_path(), |
|
| 3488 |
+ NETSH_PATH_SUFFIX, |
|
| 3489 |
+ flex_name, |
|
| 3490 |
+ print_in_addr_t (ip, 0, &gc), |
|
| 3491 |
+ print_in_addr_t (netmask, 0, &gc)); |
|
| 3492 |
+ |
|
| 3493 |
+ netsh_command (&argv, 4); |
|
| 3493 | 3494 |
} |
| 3494 | 3495 |
} |
| 3495 | 3496 |
|
| ... | ... |
@@ -3517,6 +3548,7 @@ netsh_ifconfig (const struct tuntap_options *to, |
| 3517 | 3517 |
BOOL_CAST (flags & NI_TEST_FIRST)); |
| 3518 | 3518 |
} |
| 3519 | 3519 |
|
| 3520 |
+ argv_reset (&argv); |
|
| 3520 | 3521 |
gc_free (&gc); |
| 3521 | 3522 |
} |
| 3522 | 3523 |
|
| ... | ... |
@@ -3524,17 +3556,19 @@ static void |
| 3524 | 3524 |
netsh_enable_dhcp (const struct tuntap_options *to, |
| 3525 | 3525 |
const char *actual_name) |
| 3526 | 3526 |
{
|
| 3527 |
- struct gc_arena gc = gc_new (); |
|
| 3528 |
- struct buffer out = alloc_buf_gc (256, &gc); |
|
| 3527 |
+ struct argv argv; |
|
| 3528 |
+ argv_init (&argv); |
|
| 3529 | 3529 |
|
| 3530 | 3530 |
/* example: netsh interface ip set address my-tap dhcp */ |
| 3531 |
- buf_printf (&out, |
|
| 3532 |
- "netsh interface ip set address \"%s\" dhcp", |
|
| 3533 |
- actual_name); |
|
| 3531 |
+ argv_printf (&argv, |
|
| 3532 |
+ "%s%s interface ip set address %s dhcp", |
|
| 3533 |
+ get_win_sys_path(), |
|
| 3534 |
+ NETSH_PATH_SUFFIX, |
|
| 3535 |
+ actual_name); |
|
| 3534 | 3536 |
|
| 3535 |
- netsh_command (BSTR(&out), 4); |
|
| 3537 |
+ netsh_command (&argv, 4); |
|
| 3536 | 3538 |
|
| 3537 |
- gc_free (&gc); |
|
| 3539 |
+ argv_reset (&argv); |
|
| 3538 | 3540 |
} |
| 3539 | 3541 |
|
| 3540 | 3542 |
/* |
| ... | ... |
@@ -35,6 +35,7 @@ |
| 35 | 35 |
#include "mtu.h" |
| 36 | 36 |
#include "sig.h" |
| 37 | 37 |
#include "win32.h" |
| 38 |
+#include "misc.h" |
|
| 38 | 39 |
|
| 39 | 40 |
#include "memdbg.h" |
| 40 | 41 |
|
| ... | ... |
@@ -69,6 +70,11 @@ struct window_title window_title; /* GLOBAL*/ |
| 69 | 69 |
|
| 70 | 70 |
struct semaphore netcmd_semaphore; /* GLOBAL */ |
| 71 | 71 |
|
| 72 |
+/* |
|
| 73 |
+ * Windows system pathname such as c:\windows |
|
| 74 |
+ */ |
|
| 75 |
+static char *win_sys_path = NULL; /* GLOBAL */ |
|
| 76 |
+ |
|
| 72 | 77 |
void |
| 73 | 78 |
init_win32 (void) |
| 74 | 79 |
{
|
| ... | ... |
@@ -100,6 +106,7 @@ uninit_win32 (void) |
| 100 | 100 |
window_title_restore (&window_title); |
| 101 | 101 |
win32_signal_close (&win32_signal); |
| 102 | 102 |
WSACleanup (); |
| 103 |
+ free (win_sys_path); |
|
| 103 | 104 |
} |
| 104 | 105 |
|
| 105 | 106 |
void |
| ... | ... |
@@ -816,4 +823,174 @@ win_safe_filename (const char *fn) |
| 816 | 816 |
return true; |
| 817 | 817 |
} |
| 818 | 818 |
|
| 819 |
+/* |
|
| 820 |
+ * Service functions for openvpn_execve |
|
| 821 |
+ */ |
|
| 822 |
+ |
|
| 823 |
+static char * |
|
| 824 |
+env_block (const struct env_set *es) |
|
| 825 |
+{
|
|
| 826 |
+ if (es) |
|
| 827 |
+ {
|
|
| 828 |
+ struct env_item *e; |
|
| 829 |
+ char *ret; |
|
| 830 |
+ char *p; |
|
| 831 |
+ size_t nchars = 1; |
|
| 832 |
+ |
|
| 833 |
+ for (e = es->list; e != NULL; e = e->next) |
|
| 834 |
+ nchars += strlen (e->string) + 1; |
|
| 835 |
+ |
|
| 836 |
+ ret = (char *) malloc (nchars); |
|
| 837 |
+ check_malloc_return (ret); |
|
| 838 |
+ |
|
| 839 |
+ p = ret; |
|
| 840 |
+ for (e = es->list; e != NULL; e = e->next) |
|
| 841 |
+ {
|
|
| 842 |
+ if (env_allowed (e->string)) |
|
| 843 |
+ {
|
|
| 844 |
+ strcpy (p, e->string); |
|
| 845 |
+ p += strlen (e->string) + 1; |
|
| 846 |
+ } |
|
| 847 |
+ } |
|
| 848 |
+ *p = '\0'; |
|
| 849 |
+ return ret; |
|
| 850 |
+ } |
|
| 851 |
+ else |
|
| 852 |
+ return NULL; |
|
| 853 |
+} |
|
| 854 |
+ |
|
| 855 |
+static char * |
|
| 856 |
+cmd_line (const struct argv *a) |
|
| 857 |
+{
|
|
| 858 |
+ size_t nchars = 1; |
|
| 859 |
+ size_t maxlen = 0; |
|
| 860 |
+ size_t i; |
|
| 861 |
+ struct buffer buf; |
|
| 862 |
+ char *work = NULL; |
|
| 863 |
+ |
|
| 864 |
+ if (!a) |
|
| 865 |
+ return NULL; |
|
| 866 |
+ |
|
| 867 |
+ for (i = 0; i < a->argc; ++i) |
|
| 868 |
+ {
|
|
| 869 |
+ const char *arg = a->argv[i]; |
|
| 870 |
+ const size_t len = strlen (arg); |
|
| 871 |
+ nchars += len + 3; |
|
| 872 |
+ if (len > maxlen) |
|
| 873 |
+ maxlen = len; |
|
| 874 |
+ } |
|
| 875 |
+ |
|
| 876 |
+ work = (char *) malloc (maxlen + 1); |
|
| 877 |
+ check_malloc_return (work); |
|
| 878 |
+ buf = alloc_buf (nchars); |
|
| 879 |
+ |
|
| 880 |
+ for (i = 0; i < a->argc; ++i) |
|
| 881 |
+ {
|
|
| 882 |
+ const char *arg = a->argv[i]; |
|
| 883 |
+ strcpy (work, arg); |
|
| 884 |
+ string_mod (work, CC_PRINT, CC_DOUBLE_QUOTE|CC_CRLF, '_'); |
|
| 885 |
+ if (i) |
|
| 886 |
+ buf_printf (&buf, " "); |
|
| 887 |
+ if (string_class (work, CC_ANY, CC_SPACE)) |
|
| 888 |
+ buf_printf (&buf, "%s", work); |
|
| 889 |
+ else |
|
| 890 |
+ buf_printf (&buf, "\"%s\"", work); |
|
| 891 |
+ } |
|
| 892 |
+ |
|
| 893 |
+ free (work); |
|
| 894 |
+ return BSTR(&buf); |
|
| 895 |
+} |
|
| 896 |
+ |
|
| 897 |
+/* |
|
| 898 |
+ * Attempt to simulate fork/execve on Windows |
|
| 899 |
+ */ |
|
| 900 |
+int |
|
| 901 |
+openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags) |
|
| 902 |
+{
|
|
| 903 |
+ int ret = -1; |
|
| 904 |
+ if (a && a->argv[0]) |
|
| 905 |
+ {
|
|
| 906 |
+ if (openvpn_execve_allowed (flags)) |
|
| 907 |
+ {
|
|
| 908 |
+ STARTUPINFO start_info; |
|
| 909 |
+ PROCESS_INFORMATION proc_info; |
|
| 910 |
+ |
|
| 911 |
+ char *env = env_block (es); |
|
| 912 |
+ char *cl = cmd_line (a); |
|
| 913 |
+ char *cmd = a->argv[0]; |
|
| 914 |
+ |
|
| 915 |
+ CLEAR (start_info); |
|
| 916 |
+ CLEAR (proc_info); |
|
| 917 |
+ |
|
| 918 |
+ /* fill in STARTUPINFO struct */ |
|
| 919 |
+ GetStartupInfo(&start_info); |
|
| 920 |
+ start_info.cb = sizeof(start_info); |
|
| 921 |
+ start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; |
|
| 922 |
+ start_info.wShowWindow = SW_HIDE; |
|
| 923 |
+ start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); |
|
| 924 |
+ start_info.hStdOutput = start_info.hStdError = GetStdHandle(STD_OUTPUT_HANDLE); |
|
| 925 |
+ |
|
| 926 |
+ if (CreateProcess (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info)) |
|
| 927 |
+ {
|
|
| 928 |
+ DWORD exit_status = 0; |
|
| 929 |
+ CloseHandle (proc_info.hThread); |
|
| 930 |
+ WaitForSingleObject (proc_info.hProcess, INFINITE); |
|
| 931 |
+ if (GetExitCodeProcess (proc_info.hProcess, &exit_status)) |
|
| 932 |
+ ret = (int)exit_status; |
|
| 933 |
+ else |
|
| 934 |
+ msg (M_WARN|M_ERRNO, "openvpn_execve: GetExitCodeProcess %s failed", cmd); |
|
| 935 |
+ CloseHandle (proc_info.hProcess); |
|
| 936 |
+ } |
|
| 937 |
+ else |
|
| 938 |
+ {
|
|
| 939 |
+ msg (M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %s failed", cmd); |
|
| 940 |
+ } |
|
| 941 |
+ free (cl); |
|
| 942 |
+ free (env); |
|
| 943 |
+ } |
|
| 944 |
+ else |
|
| 945 |
+ {
|
|
| 946 |
+ msg (M_WARN, "openvpn_execve: external program may not be called due to setting of --script-security level"); |
|
| 947 |
+ } |
|
| 948 |
+ } |
|
| 949 |
+ else |
|
| 950 |
+ {
|
|
| 951 |
+ msg (M_WARN, "openvpn_execve: called with empty argv"); |
|
| 952 |
+ } |
|
| 953 |
+ return ret; |
|
| 954 |
+} |
|
| 955 |
+ |
|
| 956 |
+char * |
|
| 957 |
+get_win_sys_path (void) |
|
| 958 |
+{
|
|
| 959 |
+ ASSERT (win_sys_path); |
|
| 960 |
+ return win_sys_path; |
|
| 961 |
+} |
|
| 962 |
+ |
|
| 963 |
+void |
|
| 964 |
+set_win_sys_path (const char *newpath, struct env_set *es) |
|
| 965 |
+{
|
|
| 966 |
+ free (win_sys_path); |
|
| 967 |
+ win_sys_path = string_alloc (newpath, NULL); |
|
| 968 |
+ setenv_str (es, SYS_PATH_ENV_VAR_NAME, win_sys_path); /* route.exe needs this */ |
|
| 969 |
+} |
|
| 970 |
+ |
|
| 971 |
+void |
|
| 972 |
+set_win_sys_path_via_env (struct env_set *es) |
|
| 973 |
+{
|
|
| 974 |
+ char buf[256]; |
|
| 975 |
+ DWORD status = GetEnvironmentVariable (SYS_PATH_ENV_VAR_NAME, buf, sizeof(buf)); |
|
| 976 |
+ if (!status) |
|
| 977 |
+ msg (M_ERR, "Cannot find environmental variable %s", SYS_PATH_ENV_VAR_NAME); |
|
| 978 |
+ if (status > sizeof (buf) - 1) |
|
| 979 |
+ msg (M_FATAL, "String overflow attempting to read environmental variable %s", SYS_PATH_ENV_VAR_NAME); |
|
| 980 |
+ set_win_sys_path (buf, es); |
|
| 981 |
+} |
|
| 982 |
+ |
|
| 983 |
+void |
|
| 984 |
+env_set_add_win32 (struct env_set *es) |
|
| 985 |
+{
|
|
| 986 |
+ set_win_sys_path (DEFAULT_WIN_SYS_PATH, es); |
|
| 987 |
+} |
|
| 988 |
+ |
|
| 819 | 989 |
#endif |
| ... | ... |
@@ -28,6 +28,12 @@ |
| 28 | 28 |
|
| 29 | 29 |
#include "mtu.h" |
| 30 | 30 |
|
| 31 |
+/* location of executables */ |
|
| 32 |
+#define SYS_PATH_ENV_VAR_NAME "SystemRoot" /* environmental variable name that normally contains the system path */ |
|
| 33 |
+#define DEFAULT_WIN_SYS_PATH "C:\\WINDOWS" /* --win-sys default value */ |
|
| 34 |
+#define NETSH_PATH_SUFFIX "\\system32\\netsh.exe" |
|
| 35 |
+#define WIN_ROUTE_PATH_SUFFIX "\\system32\\route.exe" |
|
| 36 |
+ |
|
| 31 | 37 |
/* |
| 32 | 38 |
* Win32-specific OpenVPN code, targetted at the mingw |
| 33 | 39 |
* development environment. |
| ... | ... |
@@ -250,5 +256,14 @@ bool init_security_attributes_allow_all (struct security_attributes *obj); |
| 250 | 250 |
/* return true if filename is safe to be used on Windows */ |
| 251 | 251 |
bool win_safe_filename (const char *fn); |
| 252 | 252 |
|
| 253 |
+/* add constant environmental variables needed by Windows */ |
|
| 254 |
+struct env_set; |
|
| 255 |
+void env_set_add_win32 (struct env_set *es); |
|
| 256 |
+ |
|
| 257 |
+/* get and set the current windows system path */ |
|
| 258 |
+void set_win_sys_path (const char *newpath, struct env_set *es); |
|
| 259 |
+void set_win_sys_path_via_env (struct env_set *es); |
|
| 260 |
+char *get_win_sys_path (void); |
|
| 261 |
+ |
|
| 253 | 262 |
#endif |
| 254 | 263 |
#endif |