summaryrefslogtreecommitdiff
path: root/threadproc
diff options
context:
space:
mode:
authorIvan Zhakov <ivan@apache.org>2019-10-15 10:59:58 +0000
committerIvan Zhakov <ivan@apache.org>2019-10-15 10:59:58 +0000
commit51b539596a9676ccc9b392b5b35c7a60174b1844 (patch)
tree0e941ca85ba6e9986fffdc8a51daec6d1e5e1eac /threadproc
parentcd40cc64f1d526f6c1659dd5777a36fd58031597 (diff)
downloadapr-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.c92
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