Only in source-orig/: configure diff -u -r source-orig/lib/charcnv.c source/lib/charcnv.c --- source-orig/lib/charcnv.c 2006-04-19 19:29:23.000000000 -0700 +++ source/lib/charcnv.c 2007-05-10 09:59:49.023262000 -0700 @@ -1398,5 +1398,5 @@ /* We're hosed - we don't know how big this is... */ DEBUG(10,("next_mb_char_size: unknown size at string %s\n", s)); conv_silent = False; - return 1; + return (size_t)-1; } diff -u -r source-orig/lib/smbrun.c source/lib/smbrun.c --- source-orig/lib/smbrun.c 2006-04-19 19:29:23.000000000 -0700 +++ source/lib/smbrun.c 2007-05-10 09:57:03.305061000 -0700 @@ -55,7 +55,7 @@ outfd (or discard it if outfd is NULL). ****************************************************************************/ -int smbrun(const char *cmd, int *outfd) +static int smbrun_internal(const char *cmd, int *outfd, BOOL sanitize) { pid_t pid; uid_t uid = current_user.ut.uid; @@ -173,13 +173,36 @@ } #endif - execl("/bin/sh","sh","-c",cmd,NULL); + { + const char *newcmd = sanitize ? escape_shell_string(cmd) : cmd; + if (!newcmd) { + exit(82); + } + execl("/bin/sh","sh","-c",newcmd,NULL); + } /* not reached */ - exit(82); + exit(83); return 1; } +/**************************************************************************** + Use only in known safe shell calls (printing). +****************************************************************************/ + +int smbrun_no_sanitize(const char *cmd, int *outfd) +{ + return smbrun_internal(cmd, outfd, False); +} + +/**************************************************************************** + By default this now sanitizes shell expansion. +****************************************************************************/ + +int smbrun(const char *cmd, int *outfd) +{ + return smbrun_internal(cmd, outfd, True); +} /**************************************************************************** run a command being careful about uid/gid handling and putting the output in @@ -302,7 +325,7 @@ #endif execl("/bin/sh", "sh", "-c", cmd, NULL); - + /* not reached */ exit(82); return 1; diff -u -r source-orig/lib/util_str.c source/lib/util_str.c --- source-orig/lib/util_str.c 2007-02-04 10:59:17.000000000 -0800 +++ source/lib/util_str.c 2007-05-10 09:59:36.718762000 -0700 @@ -2426,3 +2426,165 @@ return True; } + +/******************************************************************* + Add a shell escape character '\' to any character not in a known list + of characters. UNIX charset format. +*******************************************************************/ + +#define INCLUDE_LIST "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_/ \t.," +#define INSIDE_DQUOTE_LIST "$`\n\"\\" + +char *escape_shell_string(const char *src) +{ + size_t srclen = strlen(src); + char *ret = SMB_MALLOC((srclen * 2) + 1); + char *dest = ret; + BOOL in_s_quote = False; + BOOL in_d_quote = False; + BOOL next_escaped = False; + + if (!ret) { + return NULL; + } + + while (*src) { + size_t c_size = next_mb_char_size(src); + + if (c_size == (size_t)-1) { + SAFE_FREE(ret); + return NULL; + } + + if (c_size > 1) { + memcpy(dest, src, c_size); + src += c_size; + dest += c_size; + next_escaped = False; + continue; + } + + /* + * Deal with backslash escaped state. + * This only lasts for one character. + */ + + if (next_escaped) { + *dest++ = *src++; + next_escaped = False; + continue; + } + + /* + * Deal with single quote state. The + * only thing we care about is exiting + * this state. + */ + + if (in_s_quote) { + if (*src == '\'') { + in_s_quote = False; + } + *dest++ = *src++; + continue; + } + + /* + * Deal with double quote state. The most + * complex state. We must cope with \, meaning + * possibly escape next char (depending what it + * is), ", meaning exit this state, and possibly + * add an \ escape to any unprotected character + * (listed in INSIDE_DQUOTE_LIST). + */ + + if (in_d_quote) { + if (*src == '\\') { + /* + * Next character might be escaped. + * We have to peek. Inside double + * quotes only INSIDE_DQUOTE_LIST + * characters are escaped by a \. + */ + + char nextchar; + + c_size = next_mb_char_size(&src[1]); + if (c_size == (size_t)-1) { + SAFE_FREE(ret); + return NULL; + } + if (c_size > 1) { + /* + * Don't escape the next char. + * Just copy the \. + */ + *dest++ = *src++; + continue; + } + + nextchar = src[1]; + + if (nextchar && strchr(INSIDE_DQUOTE_LIST, (int)nextchar)) { + next_escaped = True; + } + *dest++ = *src++; + continue; + } + + if (*src == '\"') { + /* Exit double quote state. */ + in_d_quote = False; + *dest++ = *src++; + continue; + } + + /* + * We know the character isn't \ or ", + * so escape it if it's any of the other + * possible unprotected characters. + */ + + if (strchr(INSIDE_DQUOTE_LIST, (int)*src)) { + *dest++ = '\\'; + } + *dest++ = *src++; + continue; + } + + /* + * From here to the end of the loop we're + * not in the single or double quote state. + */ + + if (*src == '\\') { + /* Next character must be escaped. */ + next_escaped = True; + *dest++ = *src++; + continue; + } + + if (*src == '\'') { + /* Go into single quote state. */ + in_s_quote = True; + *dest++ = *src++; + continue; + } + + if (*src == '\"') { + /* Go into double quote state. */ + in_d_quote = True; + *dest++ = *src++; + continue; + } + + /* Check if we need to escape the character. */ + + if (!strchr(INCLUDE_LIST, (int)*src)) { + *dest++ = '\\'; + } + *dest++ = *src++; + } + *dest++ = '\0'; + return ret; +} diff -u -r source-orig/printing/print_generic.c source/printing/print_generic.c --- source-orig/printing/print_generic.c 2007-02-04 10:59:13.000000000 -0800 +++ source/printing/print_generic.c 2007-05-10 09:57:03.292061000 -0700 @@ -58,7 +58,7 @@ if ( do_sub && snum != -1 ) standard_sub_snum(snum,syscmd,sizeof(syscmd)); - ret = smbrun(syscmd,outfd); + ret = smbrun_no_sanitize(syscmd,outfd); DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));