Line data Source code
1 : #include <stdarg.h>
2 : #include <stddef.h>
3 : #include <setjmp.h>
4 : #include <stdint.h>
5 : #include <cmocka.h>
6 : #include "lib/replace/replace.h"
7 :
8 : #include <errno.h>
9 : #include <unistd.h>
10 : #include <talloc.h>
11 : #include <ctype.h>
12 : #include <string.h>
13 : #include "lib/util/samba_util.h"
14 :
15 : /* These flags say what can be asserted about a relationship between a string
16 : and its supposedly escaped equivalent.
17 :
18 : The first part of the flag name indicates the direction of transformation;
19 : the second part is the expected result. For example, ESCAPE_EQ means the
20 : escape is expected to succeed and result is expected to be equal to the
21 : given answer. ESCAPE_EQ_CASECMP is only equal when compared
22 : case-insensitively. UNESCAPE_ERR means unescaping the escaped string should
23 : result in an error.
24 : */
25 : #define UNESCAPE_ERR 1
26 : #define ESCAPE_ERR 2
27 : #define ESCAPE_EQ 4
28 : #define UNESCAPE_EQ 8
29 : #define ESCAPE_NE 16
30 : #define UNESCAPE_NE 32
31 : #define ESCAPE_EQ_CASECMP 64
32 :
33 : struct rfc1738_test {
34 : const char *escaped; /* original for unescape; result for escape */
35 : const char *unescaped; /* result in unescape; original for escape */
36 : uint32_t flags; /* see above */
37 : int unesc_len; /* end - start will be this */
38 : int unesc_strlen; /* strlen() will say this */
39 : int esc_len; /* escaped string length */
40 : };
41 :
42 : /* unreserved = ALPHA DIGIT - . _ ~ */
43 :
44 : char spectrum[255 + 1];
45 : char spectrum_escaped[255 * 3 + 1];
46 :
47 : struct rfc1738_test examples[] = {
48 :
49 : #define SIMPLE1 "this_is_a_simple-string._With_no_escapes~" /* maps to self */
50 : {
51 : SIMPLE1,
52 : SIMPLE1,
53 : ESCAPE_EQ | UNESCAPE_EQ, /* round trip should work */
54 : sizeof(SIMPLE1) - 1,
55 : sizeof(SIMPLE1) - 1,
56 : sizeof(SIMPLE1) - 1,
57 : },
58 : #define SIMPLE2 "no escapes, but\n non-printables \xc5\x8d\x99"
59 : #define SIMPLE2_ESC "no%20escapes%2C%20but%0A%20non-printables%20%C5%8D%99"
60 : {
61 : SIMPLE2_ESC,
62 : SIMPLE2,
63 : ESCAPE_EQ | UNESCAPE_EQ,
64 : sizeof(SIMPLE2) - 1,
65 : sizeof(SIMPLE2) - 1,
66 : sizeof(SIMPLE2_ESC) - 1,
67 : },
68 : #define SIMPLE3 "this @#$^&*()_+{}:;"
69 : #define SIMPLE3_ESC "this%20%40%23%24%5E%26%2A%28%29_%2B%7B%7D%3A%3B"
70 : {
71 : SIMPLE3_ESC,
72 : SIMPLE3,
73 : ESCAPE_EQ | UNESCAPE_EQ,
74 : sizeof(SIMPLE3) - 1,
75 : sizeof(SIMPLE3) - 1,
76 : sizeof(SIMPLE3_ESC) - 1,
77 : },
78 :
79 : #define ESCAPE1 "%/\x06this string has expected escapes"
80 : #define ESCAPE1_ESC "%25%2F%06this%20string%20has%20expected%20escapes"
81 : #define ESCAPE1_ESC_ESC "%2525%252F%2506this%2520string%2520has%2520expected"\
82 : "%2520escapes"
83 : {
84 : ESCAPE1_ESC,
85 : ESCAPE1,
86 : ESCAPE_EQ | UNESCAPE_EQ,
87 : sizeof(ESCAPE1) - 1,
88 : sizeof(ESCAPE1) - 1,
89 : sizeof(ESCAPE1_ESC) - 1,
90 : },
91 : {
92 : ESCAPE1_ESC_ESC, /*re-escaping */
93 : ESCAPE1_ESC,
94 : ESCAPE_EQ | UNESCAPE_EQ,
95 : sizeof(ESCAPE1_ESC) - 1,
96 : sizeof(ESCAPE1_ESC) - 1,
97 : sizeof(ESCAPE1_ESC_ESC) - 1,
98 : },
99 : #define ESCAPE2 "%25%2f%06-this-string-has-expected-lowercase-escapes-%ab"
100 : #define ESCAPE2_UNESC "%/\x06-this-string-has-expected-lowercase-escapes-\xab"
101 : {
102 : ESCAPE2,
103 : ESCAPE2_UNESC,
104 : ESCAPE_EQ_CASECMP | UNESCAPE_EQ, /* escape won't match case */
105 : sizeof(ESCAPE2_UNESC) - 1,
106 : sizeof(ESCAPE2_UNESC) - 1,
107 : sizeof(ESCAPE2) - 1,
108 : },
109 : #define ESCAPE3 "%25%2f%06 %32 %44 %6a%AA THIS string h%61s random escapes %ab"
110 : #define ESCAPE3_UNESC "%/\x06 2 D j\xAA THIS string has random escapes \xab"
111 : {
112 : ESCAPE3,
113 : ESCAPE3_UNESC,
114 : ESCAPE_NE | UNESCAPE_EQ, /* escape will have escaped spaces */
115 : sizeof(ESCAPE3_UNESC) - 1,
116 : sizeof(ESCAPE3_UNESC) - 1,
117 : sizeof(ESCAPE3) - 1,
118 : },
119 : #define ESCAPE4 "%25%25%25" /* */
120 : #define ESCAPE4_UNESC "%%%" /* */
121 : #define ESCAPE4_ESC "%2525%2525%2525"
122 : {
123 : ESCAPE4,
124 : ESCAPE4_UNESC,
125 : ESCAPE_EQ | UNESCAPE_EQ,
126 : sizeof(ESCAPE4_UNESC) - 1,
127 : sizeof(ESCAPE4_UNESC) - 1,
128 : sizeof(ESCAPE4) - 1,
129 : },
130 : {
131 : ESCAPE4_ESC,
132 : ESCAPE4,
133 : ESCAPE_EQ | UNESCAPE_EQ,
134 : sizeof(ESCAPE4) - 1,
135 : sizeof(ESCAPE4) - 1,
136 : sizeof(ESCAPE4_ESC) - 1,
137 : },
138 : #define BAD1 "trailing percent is bad %"
139 : #define BAD1_ESC "trailing%20percent%20is%20bad%20%25"
140 : {
141 : BAD1_ESC,
142 : BAD1,
143 : UNESCAPE_EQ |ESCAPE_EQ,
144 : sizeof(BAD1) - 1,
145 : sizeof(BAD1) - 1,
146 : sizeof(BAD1_ESC) - 1,
147 : },
148 : {
149 : BAD1,
150 : NULL,
151 : UNESCAPE_ERR,
152 : 0,
153 : 0,
154 : sizeof(BAD1) - 1,
155 : },
156 : #define BAD2 "trailing percent is bad %1"
157 : #define BAD3 "bad characters %1 "
158 : {
159 : BAD2,
160 : NULL,
161 : UNESCAPE_ERR,
162 : 0,
163 : 0,
164 : sizeof(BAD2) - 1,
165 : },
166 : {
167 : BAD3,
168 : NULL,
169 : UNESCAPE_ERR,
170 : 0,
171 : 0,
172 : sizeof(BAD3) - 1,
173 : },
174 : #define BAD4 "bad characters %1 "
175 : {
176 : BAD4,
177 : NULL,
178 : UNESCAPE_ERR,
179 : 0,
180 : 0,
181 : sizeof(BAD4) - 1,
182 : },
183 : #define BAD5 "bad characters %1- "
184 : {
185 : BAD5,
186 : NULL,
187 : UNESCAPE_ERR,
188 : 0,
189 : 0,
190 : sizeof(BAD5) - 1,
191 : },
192 : #define BAD6 "bad characters %1G "
193 : {
194 : BAD6,
195 : NULL,
196 : UNESCAPE_ERR,
197 : 0,
198 : 0,
199 : sizeof(BAD6) - 1,
200 : },
201 : #define BAD7 "bad characters %%1 "
202 : {
203 : BAD7,
204 : NULL,
205 : UNESCAPE_ERR,
206 : 0,
207 : 0,
208 : sizeof(BAD7) - 1,
209 : },
210 : #define BAD8 "bad characters %sb "
211 : {
212 : BAD8,
213 : NULL,
214 : UNESCAPE_ERR,
215 : 0,
216 : 0,
217 : sizeof(BAD8) - 1,
218 : },
219 : #define BAD_SSCANF "sscanf would be happy with this\n"
220 : #define BAD_SSCANF_ESC "sscanf would be happy with this% a"
221 : {
222 : BAD_SSCANF_ESC,
223 : BAD_SSCANF,
224 : ESCAPE_NE | UNESCAPE_ERR,
225 : sizeof(BAD_SSCANF) - 1,
226 : sizeof(BAD_SSCANF) - 1,
227 : sizeof(BAD_SSCANF_ESC) - 1,
228 : },
229 : /* now try some with zeros in. escaping can't see past zeros, and the result is truncated */
230 : #define ZERO "%00"
231 : #define ZERO_UNESC "\0"
232 : {
233 : ESCAPE4 ZERO ESCAPE4,
234 : ESCAPE4_UNESC ZERO_UNESC ESCAPE4_UNESC,
235 : ESCAPE_NE | UNESCAPE_EQ,
236 : sizeof(ESCAPE4_UNESC ZERO_UNESC ESCAPE4_UNESC) - 1,
237 : sizeof(ESCAPE4_UNESC) - 1,
238 : sizeof(ESCAPE4 ZERO ESCAPE4) - 1,
239 : },
240 : {
241 : ZERO ESCAPE4,
242 : ZERO_UNESC ESCAPE4_UNESC,
243 : ESCAPE_NE | UNESCAPE_EQ,
244 : sizeof(ZERO_UNESC ESCAPE4_UNESC) - 1,
245 : 0,
246 : sizeof(ZERO ESCAPE4) - 1,
247 : },
248 : {
249 : ZERO,
250 : ZERO_UNESC,
251 : ESCAPE_NE | UNESCAPE_EQ,
252 : sizeof(ZERO_UNESC) - 1,
253 : 0,
254 : sizeof(ZERO) - 1,
255 : },
256 : {
257 : spectrum_escaped,
258 : spectrum,
259 : ESCAPE_EQ | UNESCAPE_EQ,
260 : 255,
261 : 255,
262 : 255 * 3,
263 : },
264 : };
265 :
266 38 : static struct rfc1738_test * dup_test(struct rfc1738_test *src)
267 : {
268 38 : struct rfc1738_test *dest = malloc(sizeof(*dest));
269 38 : char *esc = NULL, *unesc = NULL;
270 38 : if (dest == NULL) {
271 : return NULL;
272 : }
273 38 : *dest = *src;
274 38 : if (src->esc_len) {
275 38 : esc = malloc(src->esc_len + 1);
276 38 : if (esc == NULL) {
277 0 : free(dest);
278 0 : return NULL;
279 : }
280 38 : memcpy(esc, src->escaped, src->esc_len + 1);
281 38 : dest->escaped = esc;
282 : }
283 :
284 38 : if (src->unesc_len) {
285 30 : unesc = malloc(src->unesc_len + 1);
286 30 : if (unesc == NULL) {
287 0 : free(esc);
288 0 : free(dest);
289 0 : return NULL;
290 : }
291 30 : memcpy(unesc, src->unescaped, src->unesc_len + 1);
292 30 : dest->unescaped = unesc;
293 : }
294 :
295 : return dest;
296 : }
297 :
298 38 : static void free_test(struct rfc1738_test *t)
299 : {
300 38 : free(discard_const_p(char, t->escaped));
301 38 : free(discard_const_p(char, t->unescaped));
302 38 : free(t);
303 38 : }
304 :
305 :
306 1 : static void test_unescape(void **state)
307 : {
308 1 : uint i;
309 1 : char *s, *e;
310 1 : struct rfc1738_test *test, *orig;
311 24 : for (i = 0; i < ARRAY_SIZE(examples); i++) {
312 23 : orig = &examples[i];
313 23 : if ((orig->flags & (UNESCAPE_ERR |
314 : UNESCAPE_EQ |
315 : UNESCAPE_NE)) == 0) {
316 0 : continue;
317 : }
318 23 : test = dup_test(&examples[i]);
319 23 : s = discard_const_p(char, test->escaped);
320 23 : e = rfc1738_unescape(s);
321 23 : if (test->flags & UNESCAPE_ERR) {
322 9 : assert_null(e);
323 9 : free_test(test);
324 9 : continue;
325 : }
326 14 : assert_non_null(e);
327 14 : assert_int_equal(e - s, test->unesc_len);
328 :
329 14 : if (test->flags & UNESCAPE_EQ) {
330 14 : assert_memory_equal(s,
331 : orig->unescaped,
332 : orig->unesc_len);
333 14 : assert_int_equal(strlen(s),
334 : orig->unesc_strlen);
335 : } else {
336 0 : assert_memory_not_equal(s,
337 : orig->unescaped,
338 : orig->unesc_len);
339 0 : assert_int_equal(strlen(s),
340 : orig->unesc_strlen);
341 : }
342 14 : free_test(test);
343 : }
344 1 : }
345 :
346 1 : static void test_escape(void **state)
347 : {
348 1 : uint i;
349 1 : char *s, *e;
350 1 : struct rfc1738_test *test, *orig;
351 24 : for (i = 0; i < ARRAY_SIZE(examples); i++) {
352 23 : orig = &examples[i];
353 23 : if ((orig->flags & (ESCAPE_EQ |
354 : ESCAPE_EQ_CASECMP |
355 : ESCAPE_NE)) == 0) {
356 8 : continue;
357 : }
358 15 : test = dup_test(&examples[i]);
359 15 : s = discard_const_p(char, test->unescaped);
360 15 : e = rfc1738_escape_part(NULL, s);
361 15 : if (test->flags & ESCAPE_EQ) {
362 9 : assert_memory_equal(e, test->escaped,
363 : test->esc_len + 1);
364 6 : } else if (test->flags & ESCAPE_EQ_CASECMP) {
365 1 : int cmp = strcasecmp(e, test->escaped);
366 1 : assert_int_equal(cmp, 0);
367 1 : assert_string_not_equal(e, test->escaped);
368 : } else {
369 5 : assert_string_not_equal(e, test->escaped);
370 : }
371 15 : free_test(test);
372 : }
373 1 : }
374 :
375 :
376 1 : static void gen_spectrum(void)
377 : {
378 1 : int i, j = 0;
379 1 : const char *lut = "0123456789ABCDEF";
380 256 : for (i = 1; i < 256; i++) {
381 255 : spectrum[i - 1] = i;
382 255 : if (isalnum(i) ||
383 193 : i == '-' ||
384 : i == '.' ||
385 191 : i == '_' ||
386 190 : i == '-' ||
387 : i == '~') {
388 66 : spectrum_escaped[j] = i;
389 66 : j++;
390 : } else {
391 189 : spectrum_escaped[j] = '%';
392 189 : spectrum_escaped[j + 1] = lut[i >> 4];
393 189 : spectrum_escaped[j + 2] = lut[i & 15];
394 189 : j += 3;
395 : }
396 : }
397 1 : spectrum[i - 1] = '\0';
398 1 : spectrum_escaped[j] = '\0';
399 1 : }
400 :
401 1 : int main(int argc, const char **argv)
402 : {
403 1 : const struct CMUnitTest tests[] = {
404 : cmocka_unit_test(test_escape),
405 : cmocka_unit_test(test_unescape),
406 : };
407 :
408 1 : gen_spectrum();
409 1 : cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
410 1 : return cmocka_run_group_tests(tests, NULL, NULL);
411 : }
|