samba-3.0.24-CVE-2007-2447.patch [plain text]
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 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabdefghijklmnopqrstuvwxyz_/ \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));