mirror of
https://github.com/OpenVPN/openvpn.git
synced 2025-05-09 13:41:06 +08:00
2.1_rc8 and earlier did implicit shell expansion on script
arguments since all scripts were called by system(). The security hardening changes made to 2.1_rc9 no longer use system(), but rather use the safer execve or CreateProcess system calls. The security hardening also introduced a backward incompatibility with 2.1_rc8 and earlier in that script parameters were no longer shell-expanded, so for example: client-connect "docc CLIENT-CONNECT" would fail to work because execve would try to execute a script called "docc CLIENT-CONNECT" instead of "docc" with "CLIENT-CONNECT" as the first argument. This patch fixes the issue, bringing the script argument semantics back to pre 2.1_rc9 behavior in order to preserve backward compatibility while still using execve or CreateProcess to execute the script/executable. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@3311 e7ae566f-a301-0410-adde-c780ea21d3b5
This commit is contained in:
parent
0a838de8ad
commit
b8fb090c16
252
buffer.c
252
buffer.c
@ -234,258 +234,6 @@ int openvpn_snprintf(char *str, size_t size, const char *format, ...)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* A printf-like function (that only recognizes a subset of standard printf
|
|
||||||
* format operators) that prints arguments to an argv list instead
|
|
||||||
* of a standard string. This is used to build up argv arrays for passing
|
|
||||||
* to execve.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
|
||||||
argv_init (struct argv *a)
|
|
||||||
{
|
|
||||||
a->argc = 0;
|
|
||||||
a->argv = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct argv
|
|
||||||
argv_new (void)
|
|
||||||
{
|
|
||||||
struct argv ret;
|
|
||||||
argv_init (&ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
argv_reset (struct argv *a)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < a->argc; ++i)
|
|
||||||
free (a->argv[i]);
|
|
||||||
free (a->argv);
|
|
||||||
a->argc = 0;
|
|
||||||
a->argv = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
argv_argc (const char *format)
|
|
||||||
{
|
|
||||||
char *term;
|
|
||||||
const char *f = format;
|
|
||||||
size_t argc = 0;
|
|
||||||
|
|
||||||
while ((term = argv_term (&f)) != NULL)
|
|
||||||
{
|
|
||||||
++argc;
|
|
||||||
free (term);
|
|
||||||
}
|
|
||||||
return argc;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct argv
|
|
||||||
argv_insert_head (const struct argv *a, const char *head)
|
|
||||||
{
|
|
||||||
struct argv r;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
r.argc = (a ? a->argc : 0) + 1;
|
|
||||||
ALLOC_ARRAY_CLEAR (r.argv, char *, r.argc + 1);
|
|
||||||
r.argv[0] = string_alloc (head, NULL);
|
|
||||||
if (a)
|
|
||||||
{
|
|
||||||
for (i = 0; i < a->argc; ++i)
|
|
||||||
r.argv[i+1] = string_alloc (a->argv[i], NULL);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
|
||||||
argv_term (const char **f)
|
|
||||||
{
|
|
||||||
const char *p = *f;
|
|
||||||
const char *term = NULL;
|
|
||||||
size_t termlen = 0;
|
|
||||||
|
|
||||||
if (*p == '\0')
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
const int c = *p;
|
|
||||||
if (c == '\0')
|
|
||||||
break;
|
|
||||||
if (term)
|
|
||||||
{
|
|
||||||
if (!isspace (c))
|
|
||||||
++termlen;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!isspace (c))
|
|
||||||
{
|
|
||||||
term = p;
|
|
||||||
termlen = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
*f = p;
|
|
||||||
|
|
||||||
if (term)
|
|
||||||
{
|
|
||||||
char *ret;
|
|
||||||
ASSERT (termlen > 0);
|
|
||||||
ret = malloc (termlen + 1);
|
|
||||||
check_malloc_return (ret);
|
|
||||||
memcpy (ret, term, termlen);
|
|
||||||
ret[termlen] = '\0';
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *
|
|
||||||
argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
|
|
||||||
{
|
|
||||||
if (a->argv)
|
|
||||||
return print_argv ((const char **)a->argv, gc, flags);
|
|
||||||
else
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
argv_msg (const int msglev, const struct argv *a)
|
|
||||||
{
|
|
||||||
struct gc_arena gc = gc_new ();
|
|
||||||
msg (msglev, "%s", argv_str (a, &gc, 0));
|
|
||||||
gc_free (&gc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
|
|
||||||
{
|
|
||||||
struct gc_arena gc = gc_new ();
|
|
||||||
msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0));
|
|
||||||
gc_free (&gc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
argv_printf (struct argv *a, const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list arglist;
|
|
||||||
va_start (arglist, format);
|
|
||||||
argv_printf_arglist (a, format, 0, arglist);
|
|
||||||
va_end (arglist);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
argv_printf_cat (struct argv *a, const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list arglist;
|
|
||||||
va_start (arglist, format);
|
|
||||||
argv_printf_arglist (a, format, APA_CAT, arglist);
|
|
||||||
va_end (arglist);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist)
|
|
||||||
{
|
|
||||||
char *term;
|
|
||||||
const char *f = format;
|
|
||||||
size_t argc = 0;
|
|
||||||
|
|
||||||
if (flags & APA_CAT)
|
|
||||||
{
|
|
||||||
char **old_argv = a->argv;
|
|
||||||
size_t i;
|
|
||||||
argc = a->argc;
|
|
||||||
a->argc += argv_argc (format);
|
|
||||||
ALLOC_ARRAY_CLEAR (a->argv, char *, a->argc + 1);
|
|
||||||
for (i = 0; i < argc; ++i)
|
|
||||||
a->argv[i] = old_argv[i];
|
|
||||||
free (old_argv);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
argv_reset (a);
|
|
||||||
a->argc = argv_argc (format);
|
|
||||||
ALLOC_ARRAY_CLEAR (a->argv, char *, a->argc + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((term = argv_term (&f)) != NULL)
|
|
||||||
{
|
|
||||||
ASSERT (argc < a->argc);
|
|
||||||
if (term[0] == '%')
|
|
||||||
{
|
|
||||||
if (!strcmp (term, "%s"))
|
|
||||||
{
|
|
||||||
char *s = va_arg (arglist, char *);
|
|
||||||
if (!s)
|
|
||||||
s = "";
|
|
||||||
a->argv[argc++] = string_alloc (s, NULL);
|
|
||||||
}
|
|
||||||
else if (!strcmp (term, "%d"))
|
|
||||||
{
|
|
||||||
char numstr[64];
|
|
||||||
openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
|
|
||||||
a->argv[argc++] = string_alloc (numstr, NULL);
|
|
||||||
}
|
|
||||||
else if (!strcmp (term, "%u"))
|
|
||||||
{
|
|
||||||
char numstr[64];
|
|
||||||
openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int));
|
|
||||||
a->argv[argc++] = string_alloc (numstr, NULL);
|
|
||||||
}
|
|
||||||
else if (!strcmp (term, "%s/%d"))
|
|
||||||
{
|
|
||||||
char numstr[64];
|
|
||||||
char *s = va_arg (arglist, char *);
|
|
||||||
|
|
||||||
if (!s)
|
|
||||||
s = "";
|
|
||||||
|
|
||||||
openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
|
|
||||||
|
|
||||||
{
|
|
||||||
const size_t len = strlen(s) + strlen(numstr) + 2;
|
|
||||||
char *combined = (char *) malloc (len);
|
|
||||||
check_malloc_return (combined);
|
|
||||||
|
|
||||||
strcpy (combined, s);
|
|
||||||
strcat (combined, "/");
|
|
||||||
strcat (combined, numstr);
|
|
||||||
a->argv[argc++] = combined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!strcmp (term, "%s%s"))
|
|
||||||
{
|
|
||||||
char *s1 = va_arg (arglist, char *);
|
|
||||||
char *s2 = va_arg (arglist, char *);
|
|
||||||
char *combined;
|
|
||||||
|
|
||||||
if (!s1) s1 = "";
|
|
||||||
if (!s2) s2 = "";
|
|
||||||
combined = (char *) malloc (strlen(s1) + strlen(s2) + 1);
|
|
||||||
check_malloc_return (combined);
|
|
||||||
strcpy (combined, s1);
|
|
||||||
strcat (combined, s2);
|
|
||||||
a->argv[argc++] = combined;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ASSERT (0);
|
|
||||||
free (term);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a->argv[argc++] = term;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ASSERT (argc == a->argc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* write a string to the end of a buffer that was
|
* write a string to the end of a buffer that was
|
||||||
* truncated by buf_printf
|
* truncated by buf_printf
|
||||||
|
32
buffer.h
32
buffer.h
@ -60,6 +60,7 @@ struct buffer
|
|||||||
|
|
||||||
/* used by argv_x functions */
|
/* used by argv_x functions */
|
||||||
struct argv {
|
struct argv {
|
||||||
|
size_t capacity;
|
||||||
size_t argc;
|
size_t argc;
|
||||||
char **argv;
|
char **argv;
|
||||||
};
|
};
|
||||||
@ -292,37 +293,6 @@ int openvpn_snprintf(char *str, size_t size, const char *format, ...)
|
|||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
/*
|
|
||||||
* A printf-like function (that only recognizes a subset of standard printf
|
|
||||||
* format operators) that prints arguments to an argv list instead
|
|
||||||
* of a standard string. This is used to build up argv arrays for passing
|
|
||||||
* to execve.
|
|
||||||
*/
|
|
||||||
void argv_init (struct argv *a);
|
|
||||||
struct argv argv_new (void);
|
|
||||||
void argv_reset (struct argv *a);
|
|
||||||
size_t argv_argc (const char *format);
|
|
||||||
char *argv_term (const char **f);
|
|
||||||
const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags);
|
|
||||||
struct argv argv_insert_head (const struct argv *a, const char *head);
|
|
||||||
void argv_msg (const int msglev, const struct argv *a);
|
|
||||||
void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix);
|
|
||||||
|
|
||||||
#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */
|
|
||||||
void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist);
|
|
||||||
|
|
||||||
void argv_printf (struct argv *a, const char *format, ...)
|
|
||||||
#ifdef __GNUC__
|
|
||||||
__attribute__ ((format (printf, 2, 3)))
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
|
|
||||||
void argv_printf_cat (struct argv *a, const char *format, ...)
|
|
||||||
#ifdef __GNUC__
|
|
||||||
__attribute__ ((format (printf, 2, 3)))
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* remove/add trailing characters
|
* remove/add trailing characters
|
||||||
*/
|
*/
|
||||||
|
@ -75,6 +75,7 @@
|
|||||||
#define D_CLOSE LOGLEV(2, 22, 0) /* show socket and TUN/TAP close */
|
#define D_CLOSE LOGLEV(2, 22, 0) /* show socket and TUN/TAP close */
|
||||||
#define D_SHOW_OCC_HASH LOGLEV(2, 23, 0) /* show MD5 hash of option compatibility string */
|
#define D_SHOW_OCC_HASH LOGLEV(2, 23, 0) /* show MD5 hash of option compatibility string */
|
||||||
#define D_PROXY LOGLEV(2, 24, 0) /* show http proxy control packets */
|
#define D_PROXY LOGLEV(2, 24, 0) /* show http proxy control packets */
|
||||||
|
#define D_ARGV LOGLEV(2, 25, 0) /* show struct argv errors */
|
||||||
|
|
||||||
#define D_TLS_DEBUG_LOW LOGLEV(3, 20, 0) /* low frequency info from tls_session routines */
|
#define D_TLS_DEBUG_LOW LOGLEV(3, 20, 0) /* low frequency info from tls_session routines */
|
||||||
#define D_GREMLIN LOGLEV(3, 30, 0) /* show simulated outage info from gremlin module */
|
#define D_GREMLIN LOGLEV(3, 30, 0) /* show simulated outage info from gremlin module */
|
||||||
|
2
init.c
2
init.c
@ -923,7 +923,7 @@ do_route (const struct options *options,
|
|||||||
{
|
{
|
||||||
struct argv argv = argv_new ();
|
struct argv argv = argv_new ();
|
||||||
setenv_str (es, "script_type", "route-up");
|
setenv_str (es, "script_type", "route-up");
|
||||||
argv_printf (&argv, "%s", options->route_script);
|
argv_printf (&argv, "%sc", options->route_script);
|
||||||
openvpn_execve_check (&argv, es, S_SCRIPT, "Route script failed");
|
openvpn_execve_check (&argv, es, S_SCRIPT, "Route script failed");
|
||||||
argv_reset (&argv);
|
argv_reset (&argv);
|
||||||
}
|
}
|
||||||
|
382
misc.c
382
misc.c
@ -220,7 +220,7 @@ run_up_down (const char *command,
|
|||||||
ASSERT (arg);
|
ASSERT (arg);
|
||||||
setenv_str (es, "script_type", script_type);
|
setenv_str (es, "script_type", script_type);
|
||||||
argv_printf (&argv,
|
argv_printf (&argv,
|
||||||
"%s %s %d %d %s %s %s",
|
"%sc %s %d %d %s %s %s",
|
||||||
command,
|
command,
|
||||||
arg,
|
arg,
|
||||||
tun_mtu, link_mtu,
|
tun_mtu, link_mtu,
|
||||||
@ -1190,24 +1190,6 @@ absolute_pathname (const char *pathname)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Return the next largest power of 2
|
|
||||||
* or u if u is a power of 2.
|
|
||||||
*/
|
|
||||||
unsigned int
|
|
||||||
adjust_power_of_2 (unsigned int u)
|
|
||||||
{
|
|
||||||
unsigned int ret = 1;
|
|
||||||
|
|
||||||
while (ret < u)
|
|
||||||
{
|
|
||||||
ret <<= 1;
|
|
||||||
ASSERT (ret > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_GETPASS
|
#ifdef HAVE_GETPASS
|
||||||
|
|
||||||
static FILE *
|
static FILE *
|
||||||
@ -1666,56 +1648,309 @@ openvpn_sleep (const int n)
|
|||||||
sleep (n);
|
sleep (n);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/*
|
/*
|
||||||
* Configure PATH. On Windows, sometimes PATH is not set correctly
|
* Return the next largest power of 2
|
||||||
* by default.
|
* or u if u is a power of 2.
|
||||||
*/
|
*/
|
||||||
void
|
size_t
|
||||||
configure_path (void)
|
adjust_power_of_2 (size_t u)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
size_t ret = 1;
|
||||||
FILE *fp;
|
|
||||||
fp = fopen ("c:\\windows\\system32\\route.exe", "rb");
|
while (ret < u)
|
||||||
if (fp)
|
|
||||||
{
|
{
|
||||||
const int bufsiz = 4096;
|
ret <<= 1;
|
||||||
struct gc_arena gc = gc_new ();
|
ASSERT (ret > 0);
|
||||||
struct buffer oldpath = alloc_buf_gc (bufsiz, &gc);
|
|
||||||
struct buffer newpath = alloc_buf_gc (bufsiz, &gc);
|
|
||||||
const char* delim = ";";
|
|
||||||
DWORD status;
|
|
||||||
fclose (fp);
|
|
||||||
status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath));
|
|
||||||
#if 0
|
|
||||||
status = 0;
|
|
||||||
#endif
|
|
||||||
if (!status)
|
|
||||||
{
|
|
||||||
*BPTR(&oldpath) = '\0';
|
|
||||||
delim = "";
|
|
||||||
}
|
|
||||||
buf_printf (&newpath, "C:\\WINDOWS\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem%s%s",
|
|
||||||
delim,
|
|
||||||
BSTR(&oldpath));
|
|
||||||
SetEnvironmentVariable ("PATH", BSTR(&newpath));
|
|
||||||
#if 0
|
|
||||||
status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath));
|
|
||||||
if (status > 0)
|
|
||||||
printf ("PATH: %s\n", BSTR(&oldpath));
|
|
||||||
#endif
|
|
||||||
gc_free (&gc);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A printf-like function (that only recognizes a subset of standard printf
|
||||||
|
* format operators) that prints arguments to an argv list instead
|
||||||
|
* of a standard string. This is used to build up argv arrays for passing
|
||||||
|
* to execve.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
argv_init (struct argv *a)
|
||||||
|
{
|
||||||
|
a->capacity = 0;
|
||||||
|
a->argc = 0;
|
||||||
|
a->argv = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct argv
|
||||||
|
argv_new (void)
|
||||||
|
{
|
||||||
|
struct argv ret;
|
||||||
|
argv_init (&ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
argv_reset (struct argv *a)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < a->argc; ++i)
|
||||||
|
free (a->argv[i]);
|
||||||
|
free (a->argv);
|
||||||
|
argv_init (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
argv_extend (struct argv *a, const size_t newcap)
|
||||||
|
{
|
||||||
|
if (newcap > a->capacity)
|
||||||
|
{
|
||||||
|
char **newargv;
|
||||||
|
size_t i;
|
||||||
|
ALLOC_ARRAY_CLEAR (newargv, char *, newcap);
|
||||||
|
for (i = 0; i < a->argc; ++i)
|
||||||
|
newargv[i] = a->argv[i];
|
||||||
|
free (a->argv);
|
||||||
|
a->argv = newargv;
|
||||||
|
a->capacity = newcap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
argv_grow (struct argv *a, const size_t add)
|
||||||
|
{
|
||||||
|
const size_t newargc = a->argc + add + 1;
|
||||||
|
ASSERT (newargc > a->argc);
|
||||||
|
argv_extend (a, adjust_power_of_2 (newargc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
argv_append (struct argv *a, char *str) /* str must have been malloced or be NULL */
|
||||||
|
{
|
||||||
|
argv_grow (a, 1);
|
||||||
|
a->argv[a->argc++] = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct argv
|
||||||
|
argv_clone (const struct argv *a, const size_t headroom)
|
||||||
|
{
|
||||||
|
struct argv r;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
argv_init (&r);
|
||||||
|
for (i = 0; i < headroom; ++i)
|
||||||
|
argv_append (&r, NULL);
|
||||||
|
if (a)
|
||||||
|
{
|
||||||
|
for (i = 0; i < a->argc; ++i)
|
||||||
|
argv_append (&r, string_alloc (a->argv[i], NULL));
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct argv
|
||||||
|
argv_insert_head (const struct argv *a, const char *head)
|
||||||
|
{
|
||||||
|
struct argv r;
|
||||||
|
|
||||||
|
r = argv_clone (a, 1);
|
||||||
|
r.argv[0] = string_alloc (head, NULL);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
argv_term (const char **f)
|
||||||
|
{
|
||||||
|
const char *p = *f;
|
||||||
|
const char *term = NULL;
|
||||||
|
size_t termlen = 0;
|
||||||
|
|
||||||
|
if (*p == '\0')
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
const int c = *p;
|
||||||
|
if (c == '\0')
|
||||||
|
break;
|
||||||
|
if (term)
|
||||||
|
{
|
||||||
|
if (!isspace (c))
|
||||||
|
++termlen;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!isspace (c))
|
||||||
|
{
|
||||||
|
term = p;
|
||||||
|
termlen = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
*f = p;
|
||||||
|
|
||||||
|
if (term)
|
||||||
|
{
|
||||||
|
char *ret;
|
||||||
|
ASSERT (termlen > 0);
|
||||||
|
ret = malloc (termlen + 1);
|
||||||
|
check_malloc_return (ret);
|
||||||
|
memcpy (ret, term, termlen);
|
||||||
|
ret[termlen] = '\0';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
|
||||||
|
{
|
||||||
|
if (a->argv)
|
||||||
|
return print_argv ((const char **)a->argv, gc, flags);
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
argv_msg (const int msglev, const struct argv *a)
|
||||||
|
{
|
||||||
|
struct gc_arena gc = gc_new ();
|
||||||
|
msg (msglev, "%s", argv_str (a, &gc, 0));
|
||||||
|
gc_free (&gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
|
||||||
|
{
|
||||||
|
struct gc_arena gc = gc_new ();
|
||||||
|
msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0));
|
||||||
|
gc_free (&gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
argv_printf (struct argv *a, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list arglist;
|
||||||
|
va_start (arglist, format);
|
||||||
|
argv_printf_arglist (a, format, 0, arglist);
|
||||||
|
va_end (arglist);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
argv_printf_cat (struct argv *a, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list arglist;
|
||||||
|
va_start (arglist, format);
|
||||||
|
argv_printf_arglist (a, format, APA_CAT, arglist);
|
||||||
|
va_end (arglist);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist)
|
||||||
|
{
|
||||||
|
struct gc_arena gc = gc_new ();
|
||||||
|
char *term;
|
||||||
|
const char *f = format;
|
||||||
|
|
||||||
|
if (!(flags & APA_CAT))
|
||||||
|
argv_reset (a);
|
||||||
|
argv_extend (a, 1); /* ensure trailing NULL */
|
||||||
|
|
||||||
|
while ((term = argv_term (&f)) != NULL)
|
||||||
|
{
|
||||||
|
if (term[0] == '%')
|
||||||
|
{
|
||||||
|
if (!strcmp (term, "%s"))
|
||||||
|
{
|
||||||
|
char *s = va_arg (arglist, char *);
|
||||||
|
if (!s)
|
||||||
|
s = "";
|
||||||
|
argv_append (a, string_alloc (s, NULL));
|
||||||
|
}
|
||||||
|
else if (!strcmp (term, "%sc"))
|
||||||
|
{
|
||||||
|
char *s = va_arg (arglist, char *);
|
||||||
|
if (s)
|
||||||
|
{
|
||||||
|
int nparms;
|
||||||
|
char *parms[MAX_PARMS+1];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, M_FATAL, &gc);
|
||||||
|
for (i = 0; i < nparms; ++i)
|
||||||
|
argv_append (a, string_alloc (parms[i], NULL));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
argv_append (a, string_alloc ("", NULL));
|
||||||
|
}
|
||||||
|
else if (!strcmp (term, "%d"))
|
||||||
|
{
|
||||||
|
char numstr[64];
|
||||||
|
openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
|
||||||
|
argv_append (a, string_alloc (numstr, NULL));
|
||||||
|
}
|
||||||
|
else if (!strcmp (term, "%u"))
|
||||||
|
{
|
||||||
|
char numstr[64];
|
||||||
|
openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int));
|
||||||
|
argv_append (a, string_alloc (numstr, NULL));
|
||||||
|
}
|
||||||
|
else if (!strcmp (term, "%s/%d"))
|
||||||
|
{
|
||||||
|
char numstr[64];
|
||||||
|
char *s = va_arg (arglist, char *);
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
s = "";
|
||||||
|
|
||||||
|
openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
|
||||||
|
|
||||||
|
{
|
||||||
|
const size_t len = strlen(s) + strlen(numstr) + 2;
|
||||||
|
char *combined = (char *) malloc (len);
|
||||||
|
check_malloc_return (combined);
|
||||||
|
|
||||||
|
strcpy (combined, s);
|
||||||
|
strcat (combined, "/");
|
||||||
|
strcat (combined, numstr);
|
||||||
|
argv_append (a, combined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcmp (term, "%s%s"))
|
||||||
|
{
|
||||||
|
char *s1 = va_arg (arglist, char *);
|
||||||
|
char *s2 = va_arg (arglist, char *);
|
||||||
|
char *combined;
|
||||||
|
|
||||||
|
if (!s1) s1 = "";
|
||||||
|
if (!s2) s2 = "";
|
||||||
|
combined = (char *) malloc (strlen(s1) + strlen(s2) + 1);
|
||||||
|
check_malloc_return (combined);
|
||||||
|
strcpy (combined, s1);
|
||||||
|
strcat (combined, s2);
|
||||||
|
argv_append (a, combined);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ASSERT (0);
|
||||||
|
free (term);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
argv_append (a, term);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gc_free (&gc);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ARGV_TEST
|
#ifdef ARGV_TEST
|
||||||
void
|
void
|
||||||
argv_test (void)
|
argv_test (void)
|
||||||
{
|
{
|
||||||
struct gc_arena gc = gc_new ();
|
struct gc_arena gc = gc_new ();
|
||||||
char line[512];
|
|
||||||
const char *s;
|
const char *s;
|
||||||
|
|
||||||
struct argv a;
|
struct argv a;
|
||||||
@ -1729,7 +1964,7 @@ argv_test (void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
argv_msg_prefix (M_INFO, &a, "ARGV");
|
argv_msg_prefix (M_INFO, &a, "ARGV");
|
||||||
openvpn_execve_check (&a, NULL, 0, "command failed");
|
//openvpn_execve_check (&a, NULL, 0, "command failed");
|
||||||
|
|
||||||
argv_printf (&a, "this is a %s test of int %d unsigned %u", "FOO", -69, 42);
|
argv_printf (&a, "this is a %s test of int %d unsigned %u", "FOO", -69, 42);
|
||||||
s = argv_str (&a, &gc, PA_BRACKET);
|
s = argv_str (&a, &gc, PA_BRACKET);
|
||||||
@ -1742,7 +1977,7 @@ argv_test (void)
|
|||||||
printf ("%s\n", s);
|
printf ("%s\n", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
argv_printf (&a, "foo bar %d", 99);
|
argv_printf (&a, "%sc foo bar %d", "\"multi term\" command following \\\"spaces", 99);
|
||||||
s = argv_str (&a, &gc, PA_BRACKET);
|
s = argv_str (&a, &gc, PA_BRACKET);
|
||||||
argv_reset (&a);
|
argv_reset (&a);
|
||||||
printf ("%s\n", s);
|
printf ("%s\n", s);
|
||||||
@ -1752,25 +1987,28 @@ argv_test (void)
|
|||||||
printf ("%s\n", s);
|
printf ("%s\n", s);
|
||||||
|
|
||||||
argv_printf (&a, "foo bar %d", 99);
|
argv_printf (&a, "foo bar %d", 99);
|
||||||
argv_printf_cat (&a, "bar %d foo", 42);
|
argv_printf_cat (&a, "bar %d foo %sc", 42, "nonesuch");
|
||||||
argv_printf_cat (&a, "cool %s %d u %s/%d end", "frood", 4, "hello", 7);
|
argv_printf_cat (&a, "cool %s %d u %s/%d end", "frood", 4, "hello", 7);
|
||||||
s = argv_str (&a, &gc, PA_BRACKET);
|
s = argv_str (&a, &gc, PA_BRACKET);
|
||||||
printf ("%s\n", s);
|
printf ("%s\n", s);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
while (fgets (line, sizeof(line), stdin) != NULL)
|
{
|
||||||
{
|
char line[512];
|
||||||
char *term;
|
while (fgets (line, sizeof(line), stdin) != NULL)
|
||||||
const char *f = line;
|
{
|
||||||
int i = 0;
|
char *term;
|
||||||
|
const char *f = line;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
while ((term = argv_term (&f)) != NULL)
|
while ((term = argv_term (&f)) != NULL)
|
||||||
{
|
{
|
||||||
printf ("[%d] '%s'\n", i, term);
|
printf ("[%d] '%s'\n", i, term);
|
||||||
++i;
|
++i;
|
||||||
free (term);
|
free (term);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
argv_reset (&a);
|
argv_reset (&a);
|
||||||
|
36
misc.h
36
misc.h
@ -221,9 +221,6 @@ bool delete_file (const char *filename);
|
|||||||
/* return true if pathname is absolute */
|
/* return true if pathname is absolute */
|
||||||
bool absolute_pathname (const char *pathname);
|
bool absolute_pathname (const char *pathname);
|
||||||
|
|
||||||
/* return the next largest power of 2 */
|
|
||||||
unsigned int adjust_power_of_2 (unsigned int u);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get and store a username/password
|
* Get and store a username/password
|
||||||
*/
|
*/
|
||||||
@ -300,4 +297,37 @@ extern const char *iproute_path;
|
|||||||
#define SSEC_PW_ENV 3 /* allow calling of built-in programs and user-defined scripts that may receive a password as an environmental variable */
|
#define SSEC_PW_ENV 3 /* allow calling of built-in programs and user-defined scripts that may receive a password as an environmental variable */
|
||||||
extern int script_security; /* GLOBAL */
|
extern int script_security; /* GLOBAL */
|
||||||
|
|
||||||
|
/* return the next largest power of 2 */
|
||||||
|
size_t adjust_power_of_2 (size_t u);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A printf-like function (that only recognizes a subset of standard printf
|
||||||
|
* format operators) that prints arguments to an argv list instead
|
||||||
|
* of a standard string. This is used to build up argv arrays for passing
|
||||||
|
* to execve.
|
||||||
|
*/
|
||||||
|
void argv_init (struct argv *a);
|
||||||
|
struct argv argv_new (void);
|
||||||
|
void argv_reset (struct argv *a);
|
||||||
|
char *argv_term (const char **f);
|
||||||
|
const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags);
|
||||||
|
struct argv argv_insert_head (const struct argv *a, const char *head);
|
||||||
|
void argv_msg (const int msglev, const struct argv *a);
|
||||||
|
void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix);
|
||||||
|
|
||||||
|
#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */
|
||||||
|
void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist);
|
||||||
|
|
||||||
|
void argv_printf (struct argv *a, const char *format, ...)
|
||||||
|
#ifdef __GNUC__
|
||||||
|
__attribute__ ((format (printf, 2, 3)))
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
|
void argv_printf_cat (struct argv *a, const char *format, ...)
|
||||||
|
#ifdef __GNUC__
|
||||||
|
__attribute__ ((format (printf, 2, 3)))
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
6
multi.c
6
multi.c
@ -103,7 +103,7 @@ learn_address_script (const struct multi_context *m,
|
|||||||
{
|
{
|
||||||
struct argv argv = argv_new ();
|
struct argv argv = argv_new ();
|
||||||
setenv_str (es, "script_type", "learn-address");
|
setenv_str (es, "script_type", "learn-address");
|
||||||
argv_printf (&argv, "%s %s %s",
|
argv_printf (&argv, "%sc %s %s",
|
||||||
m->top.options.learn_address_script,
|
m->top.options.learn_address_script,
|
||||||
op,
|
op,
|
||||||
mroute_addr_print (addr, &gc));
|
mroute_addr_print (addr, &gc));
|
||||||
@ -473,7 +473,7 @@ multi_client_disconnect_script (struct multi_context *m,
|
|||||||
{
|
{
|
||||||
struct argv argv = argv_new ();
|
struct argv argv = argv_new ();
|
||||||
setenv_str (mi->context.c2.es, "script_type", "client-disconnect");
|
setenv_str (mi->context.c2.es, "script_type", "client-disconnect");
|
||||||
argv_printf (&argv, "%s", mi->context.options.client_disconnect_script);
|
argv_printf (&argv, "%sc", mi->context.options.client_disconnect_script);
|
||||||
openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-disconnect command failed");
|
openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-disconnect command failed");
|
||||||
argv_reset (&argv);
|
argv_reset (&argv);
|
||||||
}
|
}
|
||||||
@ -1568,7 +1568,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
|
|||||||
|
|
||||||
delete_file (dc_file);
|
delete_file (dc_file);
|
||||||
|
|
||||||
argv_printf (&argv, "%s %s",
|
argv_printf (&argv, "%sc %s",
|
||||||
mi->context.options.client_connect_script,
|
mi->context.options.client_connect_script,
|
||||||
dc_file);
|
dc_file);
|
||||||
|
|
||||||
|
2
socket.c
2
socket.c
@ -1539,7 +1539,7 @@ ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socke
|
|||||||
const char *ip = print_sockaddr_ex (&info->lsa->actual.dest, NULL, 0, gc);
|
const char *ip = print_sockaddr_ex (&info->lsa->actual.dest, NULL, 0, gc);
|
||||||
const char *port = print_sockaddr_ex (&info->lsa->actual.dest, NULL, PS_DONT_SHOW_ADDR|PS_SHOW_PORT, gc);
|
const char *port = print_sockaddr_ex (&info->lsa->actual.dest, NULL, PS_DONT_SHOW_ADDR|PS_SHOW_PORT, gc);
|
||||||
if (include_cmd)
|
if (include_cmd)
|
||||||
argv_printf (argv, "%s %s %s",
|
argv_printf (argv, "%sc %s %s",
|
||||||
info->ipchange_command,
|
info->ipchange_command,
|
||||||
ip,
|
ip,
|
||||||
port);
|
port);
|
||||||
|
4
ssl.c
4
ssl.c
@ -718,7 +718,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
|
|||||||
|
|
||||||
setenv_str (opt->es, "script_type", "tls-verify");
|
setenv_str (opt->es, "script_type", "tls-verify");
|
||||||
|
|
||||||
argv_printf (&argv, "%s %d %s",
|
argv_printf (&argv, "%sc %d %s",
|
||||||
opt->verify_command,
|
opt->verify_command,
|
||||||
ctx->error_depth,
|
ctx->error_depth,
|
||||||
subject);
|
subject);
|
||||||
@ -2937,7 +2937,7 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
|
|||||||
setenv_untrusted (session);
|
setenv_untrusted (session);
|
||||||
|
|
||||||
/* format command line */
|
/* format command line */
|
||||||
argv_printf (&argv, "%s %s", session->opt->auth_user_pass_verify_script, tmp_file);
|
argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file);
|
||||||
|
|
||||||
/* call command */
|
/* call command */
|
||||||
retval = openvpn_execve (&argv, session->opt->es, S_SCRIPT);
|
retval = openvpn_execve (&argv, session->opt->es, S_SCRIPT);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user