Contents of /trunk/samba/patches/samba-3.0.24-shell_escape.patch
Parent Directory | Revision Log
Revision 201 -
(show annotations)
(download)
Sat May 19 16:54:40 2007 UTC (17 years, 5 months ago) by niro
File size: 6234 byte(s)
Sat May 19 16:54:40 2007 UTC (17 years, 5 months ago) by niro
File size: 6234 byte(s)
-added security fixes (CVE-2007-2446 && CVE-2007-2447)
1 | Only in source-orig/: configure |
2 | diff -u -r source-orig/lib/charcnv.c source/lib/charcnv.c |
3 | --- source-orig/lib/charcnv.c 2006-04-19 19:29:23.000000000 -0700 |
4 | +++ source/lib/charcnv.c 2007-05-10 09:59:49.023262000 -0700 |
5 | @@ -1398,5 +1398,5 @@ |
6 | /* We're hosed - we don't know how big this is... */ |
7 | DEBUG(10,("next_mb_char_size: unknown size at string %s\n", s)); |
8 | conv_silent = False; |
9 | - return 1; |
10 | + return (size_t)-1; |
11 | } |
12 | diff -u -r source-orig/lib/smbrun.c source/lib/smbrun.c |
13 | --- source-orig/lib/smbrun.c 2006-04-19 19:29:23.000000000 -0700 |
14 | +++ source/lib/smbrun.c 2007-05-10 09:57:03.305061000 -0700 |
15 | @@ -55,7 +55,7 @@ |
16 | outfd (or discard it if outfd is NULL). |
17 | ****************************************************************************/ |
18 | |
19 | -int smbrun(const char *cmd, int *outfd) |
20 | +static int smbrun_internal(const char *cmd, int *outfd, BOOL sanitize) |
21 | { |
22 | pid_t pid; |
23 | uid_t uid = current_user.ut.uid; |
24 | @@ -173,13 +173,36 @@ |
25 | } |
26 | #endif |
27 | |
28 | - execl("/bin/sh","sh","-c",cmd,NULL); |
29 | + { |
30 | + const char *newcmd = sanitize ? escape_shell_string(cmd) : cmd; |
31 | + if (!newcmd) { |
32 | + exit(82); |
33 | + } |
34 | + execl("/bin/sh","sh","-c",newcmd,NULL); |
35 | + } |
36 | |
37 | /* not reached */ |
38 | - exit(82); |
39 | + exit(83); |
40 | return 1; |
41 | } |
42 | |
43 | +/**************************************************************************** |
44 | + Use only in known safe shell calls (printing). |
45 | +****************************************************************************/ |
46 | + |
47 | +int smbrun_no_sanitize(const char *cmd, int *outfd) |
48 | +{ |
49 | + return smbrun_internal(cmd, outfd, False); |
50 | +} |
51 | + |
52 | +/**************************************************************************** |
53 | + By default this now sanitizes shell expansion. |
54 | +****************************************************************************/ |
55 | + |
56 | +int smbrun(const char *cmd, int *outfd) |
57 | +{ |
58 | + return smbrun_internal(cmd, outfd, True); |
59 | +} |
60 | |
61 | /**************************************************************************** |
62 | run a command being careful about uid/gid handling and putting the output in |
63 | @@ -302,7 +325,7 @@ |
64 | #endif |
65 | |
66 | execl("/bin/sh", "sh", "-c", cmd, NULL); |
67 | - |
68 | + |
69 | /* not reached */ |
70 | exit(82); |
71 | return 1; |
72 | diff -u -r source-orig/lib/util_str.c source/lib/util_str.c |
73 | --- source-orig/lib/util_str.c 2007-02-04 10:59:17.000000000 -0800 |
74 | +++ source/lib/util_str.c 2007-05-10 09:59:36.718762000 -0700 |
75 | @@ -2426,3 +2426,165 @@ |
76 | return True; |
77 | } |
78 | |
79 | + |
80 | +/******************************************************************* |
81 | + Add a shell escape character '\' to any character not in a known list |
82 | + of characters. UNIX charset format. |
83 | +*******************************************************************/ |
84 | + |
85 | +#define INCLUDE_LIST "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabdefghijklmnopqrstuvwxyz_/ \t.," |
86 | +#define INSIDE_DQUOTE_LIST "$`\n\"\\" |
87 | + |
88 | +char *escape_shell_string(const char *src) |
89 | +{ |
90 | + size_t srclen = strlen(src); |
91 | + char *ret = SMB_MALLOC((srclen * 2) + 1); |
92 | + char *dest = ret; |
93 | + BOOL in_s_quote = False; |
94 | + BOOL in_d_quote = False; |
95 | + BOOL next_escaped = False; |
96 | + |
97 | + if (!ret) { |
98 | + return NULL; |
99 | + } |
100 | + |
101 | + while (*src) { |
102 | + size_t c_size = next_mb_char_size(src); |
103 | + |
104 | + if (c_size == (size_t)-1) { |
105 | + SAFE_FREE(ret); |
106 | + return NULL; |
107 | + } |
108 | + |
109 | + if (c_size > 1) { |
110 | + memcpy(dest, src, c_size); |
111 | + src += c_size; |
112 | + dest += c_size; |
113 | + next_escaped = False; |
114 | + continue; |
115 | + } |
116 | + |
117 | + /* |
118 | + * Deal with backslash escaped state. |
119 | + * This only lasts for one character. |
120 | + */ |
121 | + |
122 | + if (next_escaped) { |
123 | + *dest++ = *src++; |
124 | + next_escaped = False; |
125 | + continue; |
126 | + } |
127 | + |
128 | + /* |
129 | + * Deal with single quote state. The |
130 | + * only thing we care about is exiting |
131 | + * this state. |
132 | + */ |
133 | + |
134 | + if (in_s_quote) { |
135 | + if (*src == '\'') { |
136 | + in_s_quote = False; |
137 | + } |
138 | + *dest++ = *src++; |
139 | + continue; |
140 | + } |
141 | + |
142 | + /* |
143 | + * Deal with double quote state. The most |
144 | + * complex state. We must cope with \, meaning |
145 | + * possibly escape next char (depending what it |
146 | + * is), ", meaning exit this state, and possibly |
147 | + * add an \ escape to any unprotected character |
148 | + * (listed in INSIDE_DQUOTE_LIST). |
149 | + */ |
150 | + |
151 | + if (in_d_quote) { |
152 | + if (*src == '\\') { |
153 | + /* |
154 | + * Next character might be escaped. |
155 | + * We have to peek. Inside double |
156 | + * quotes only INSIDE_DQUOTE_LIST |
157 | + * characters are escaped by a \. |
158 | + */ |
159 | + |
160 | + char nextchar; |
161 | + |
162 | + c_size = next_mb_char_size(&src[1]); |
163 | + if (c_size == (size_t)-1) { |
164 | + SAFE_FREE(ret); |
165 | + return NULL; |
166 | + } |
167 | + if (c_size > 1) { |
168 | + /* |
169 | + * Don't escape the next char. |
170 | + * Just copy the \. |
171 | + */ |
172 | + *dest++ = *src++; |
173 | + continue; |
174 | + } |
175 | + |
176 | + nextchar = src[1]; |
177 | + |
178 | + if (nextchar && strchr(INSIDE_DQUOTE_LIST, (int)nextchar)) { |
179 | + next_escaped = True; |
180 | + } |
181 | + *dest++ = *src++; |
182 | + continue; |
183 | + } |
184 | + |
185 | + if (*src == '\"') { |
186 | + /* Exit double quote state. */ |
187 | + in_d_quote = False; |
188 | + *dest++ = *src++; |
189 | + continue; |
190 | + } |
191 | + |
192 | + /* |
193 | + * We know the character isn't \ or ", |
194 | + * so escape it if it's any of the other |
195 | + * possible unprotected characters. |
196 | + */ |
197 | + |
198 | + if (strchr(INSIDE_DQUOTE_LIST, (int)*src)) { |
199 | + *dest++ = '\\'; |
200 | + } |
201 | + *dest++ = *src++; |
202 | + continue; |
203 | + } |
204 | + |
205 | + /* |
206 | + * From here to the end of the loop we're |
207 | + * not in the single or double quote state. |
208 | + */ |
209 | + |
210 | + if (*src == '\\') { |
211 | + /* Next character must be escaped. */ |
212 | + next_escaped = True; |
213 | + *dest++ = *src++; |
214 | + continue; |
215 | + } |
216 | + |
217 | + if (*src == '\'') { |
218 | + /* Go into single quote state. */ |
219 | + in_s_quote = True; |
220 | + *dest++ = *src++; |
221 | + continue; |
222 | + } |
223 | + |
224 | + if (*src == '\"') { |
225 | + /* Go into double quote state. */ |
226 | + in_d_quote = True; |
227 | + *dest++ = *src++; |
228 | + continue; |
229 | + } |
230 | + |
231 | + /* Check if we need to escape the character. */ |
232 | + |
233 | + if (!strchr(INCLUDE_LIST, (int)*src)) { |
234 | + *dest++ = '\\'; |
235 | + } |
236 | + *dest++ = *src++; |
237 | + } |
238 | + *dest++ = '\0'; |
239 | + return ret; |
240 | +} |
241 | diff -u -r source-orig/printing/print_generic.c source/printing/print_generic.c |
242 | --- source-orig/printing/print_generic.c 2007-02-04 10:59:13.000000000 -0800 |
243 | +++ source/printing/print_generic.c 2007-05-10 09:57:03.292061000 -0700 |
244 | @@ -58,7 +58,7 @@ |
245 | if ( do_sub && snum != -1 ) |
246 | standard_sub_snum(snum,syscmd,sizeof(syscmd)); |
247 | |
248 | - ret = smbrun(syscmd,outfd); |
249 | + ret = smbrun_no_sanitize(syscmd,outfd); |
250 | |
251 | DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret)); |
252 |