diff options
author | Ivan Zhakov <ivan@apache.org> | 2019-10-15 10:59:58 +0000 |
---|---|---|
committer | Ivan Zhakov <ivan@apache.org> | 2019-10-15 10:59:58 +0000 |
commit | 51b539596a9676ccc9b392b5b35c7a60174b1844 (patch) | |
tree | 0e941ca85ba6e9986fffdc8a51daec6d1e5e1eac /threadproc | |
parent | cd40cc64f1d526f6c1659dd5777a36fd58031597 (diff) | |
download | apr-51b539596a9676ccc9b392b5b35c7a60174b1844.tar.gz |
apr_proc_create(): Properly escape arguments containing whitespace characters
on Windows.
* CMakeLists.txt
(single_source_programs): Add test/echoargs.c.
* test/echoargs.c: New test app for test_proc_args test.
* test/testproc.c
(test_proc_args): New test.
(testproc): Add test_proc_args to test list.
* threadproc/win32/proc.c
(quote_arg): New. Helper for apr_proc_create().
(apr_proc_create): Use quote_arg() helper to escape arguments in command
line.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1868477 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'threadproc')
-rw-r--r-- | threadproc/win32/proc.c | 92 |
1 files changed, 86 insertions, 6 deletions
diff --git a/threadproc/win32/proc.c b/threadproc/win32/proc.c index 05953e347..5fee0c286 100644 --- a/threadproc/win32/proc.c +++ b/threadproc/win32/proc.c @@ -331,6 +331,91 @@ static const char* has_space(const char *str) return NULL; } +/* Quote one command line argument if needed. See documentation for + * CommandLineToArgV() for details: + * https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw + */ +static const char * quote_arg(const char *str, apr_pool_t *pool) +{ + const char *ch; + apr_size_t needed; + char *escaped; + char *dst; + + /* Perform quoting only if neccessary. */ + if (*str && !strpbrk(str, " \f\n\r\t\v\"")) { + return str; + } + + needed = 0; + /* One char for leading quote. */ + needed++; + for (ch = str; ; ch++) { + apr_size_t backslash_count = 0; + + while (*ch == '\\') { + backslash_count++; + ch++; + } + + if (*ch == 0) { + /* Escape backslashes. */ + needed += backslash_count * 2; + break; + } + else if (*ch == '"') { + /* Escape backslashes. */ + needed += backslash_count * 2 + 1; + /* Double quote char. */ + needed += 1; + } + else { + /* Unescaped backslashes. */ + needed += backslash_count; + /* Original character. */ + needed += 1; + } + } + + /* For trailing quote. */ + needed++; + /* Zero terminator. */ + needed++; + + escaped = apr_palloc(pool, needed); + + dst = escaped; + *dst++ = '"'; + for (ch = str; ; ch++) { + apr_size_t backslash_count = 0; + + while (*ch == '\\') { + backslash_count++; + ch++; + } + + if (*ch == 0) { + memset(dst, '\\', backslash_count * 2); + dst += backslash_count * 2; + break; + } + else if (*ch == '"') { + memset(dst, '\\', backslash_count * 2 + 1); + dst += backslash_count * 2 + 1; + *dst++ = *ch; + } + else { + memset(dst, '\\', backslash_count); + dst += backslash_count; + *dst++ = *ch; + } + } + *dst++ = '"'; + *dst = 0; + + return escaped; +} + static char *apr_caret_escape_args(apr_pool_t *p, const char *str) { char *cmd; @@ -583,12 +668,7 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, * Handle the args, seperate from argv0 */ cmdline = argv0; for (i = 1; args && args[i]; ++i) { - if (has_space(args[i]) || !args[i][0]) { - cmdline = apr_pstrcat(pool, cmdline, " \"", args[i], "\"", NULL); - } - else { - cmdline = apr_pstrcat(pool, cmdline, " ", args[i], NULL); - } + cmdline = apr_pstrcat(pool, cmdline, " ", quote_arg(args[i], pool), NULL); } /* Do not pass the first arg to CreateProc() for APR_PROGRAM_PATH |