Annotation of /trunk/samba/patches/samba-3.0.24-shell_escape.patch
Parent Directory | Revision Log
Revision 201 -
(hide annotations)
(download)
Sat May 19 16:54:40 2007 UTC (17 years, 4 months ago) by niro
File size: 6234 byte(s)
Sat May 19 16:54:40 2007 UTC (17 years, 4 months ago) by niro
File size: 6234 byte(s)
-added security fixes (CVE-2007-2446 && CVE-2007-2447)
1 | niro | 201 | 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 |