1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /* escape/unescape functions.
18 *
19 * These functions perform various escaping operations, and are provided in
20 * pairs, a function to query the length of and escape existing buffers, as
21 * well as companion functions to perform the same process to memory
22 * allocated from a pool.
23 *
24 * The API is designed to have the smallest possible RAM footprint, and so
25 * will only allocate the exact amount of RAM needed for each conversion.
26 */
27
28 #include "apr_escape.h"
29 #include "apr_escape_test_char.h"
30 #include "apr_encode_private.h"
31 #include "apr_lib.h"
32 #include "apr_strings.h"
33
34 /* we assume the folks using this ensure 0 <= c < 256... which means
35 * you need a cast to (unsigned char) first, you can't just plug a
36 * char in here and get it to work, because if char is signed then it
37 * will first be sign extended.
38 */
39 #define TEST_CHAR(c, f) (test_char_table[(unsigned)(c)] & (f))
40
apr_escape_shell(char * escaped,const char * str,apr_ssize_t slen,apr_size_t * len)41 APR_DECLARE(apr_status_t) apr_escape_shell(char *escaped, const char *str,
42 apr_ssize_t slen, apr_size_t *len)
43 {
44 unsigned char *d;
45 const unsigned char *s;
46 apr_size_t size = 1;
47 int found = 0;
48
49 d = (unsigned char *) escaped;
50 s = (const unsigned char *) str;
51
52 if (s) {
53 if (d) {
54 for (; *s && slen; ++s, slen--) {
55 #if defined(OS2) || defined(WIN32)
56 /*
57 * Newlines to Win32/OS2 CreateProcess() are ill advised.
58 * Convert them to spaces since they are effectively white
59 * space to most applications
60 */
61 if (*s == '\r' || *s == '\n') {
62 if (d) {
63 *d++ = ' ';
64 found = 1;
65 }
66 continue;
67 }
68 #endif
69 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
70 *d++ = '\\';
71 size++;
72 found = 1;
73 }
74 *d++ = *s;
75 size++;
76 }
77 *d = '\0';
78 }
79 else {
80 for (; *s && slen; ++s, slen--) {
81 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
82 size++;
83 found = 1;
84 }
85 size++;
86 }
87 }
88 }
89
90 if (len) {
91 *len = size;
92 }
93 if (!found) {
94 return APR_NOTFOUND;
95 }
96
97 return APR_SUCCESS;
98 }
99
apr_pescape_shell(apr_pool_t * p,const char * str)100 APR_DECLARE(const char *) apr_pescape_shell(apr_pool_t *p, const char *str)
101 {
102 apr_size_t len;
103
104 switch (apr_escape_shell(NULL, str, APR_ESCAPE_STRING, &len)) {
105 case APR_SUCCESS: {
106 char *cmd = apr_palloc(p, len);
107 apr_escape_shell(cmd, str, APR_ESCAPE_STRING, NULL);
108 return cmd;
109 }
110 case APR_NOTFOUND: {
111 break;
112 }
113 }
114
115 return str;
116 }
117
x2c(const char * what)118 static char x2c(const char *what)
119 {
120 register char digit;
121
122 #if !APR_CHARSET_EBCDIC
123 digit =
124 ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
125 digit *= 16;
126 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
127 #else /*APR_CHARSET_EBCDIC*/
128 char xstr[5];
129 xstr[0]='0';
130 xstr[1]='x';
131 xstr[2]=what[0];
132 xstr[3]=what[1];
133 xstr[4]='\0';
134 digit = ENCODE_TO_NATIVE[0xFF & strtol(xstr, NULL, 16)];
135 #endif /*APR_CHARSET_EBCDIC*/
136 return (digit);
137 }
138
apr_unescape_url(char * escaped,const char * url,apr_ssize_t slen,const char * forbid,const char * reserved,int plus,apr_size_t * len)139 APR_DECLARE(apr_status_t) apr_unescape_url(char *escaped, const char *url,
140 apr_ssize_t slen, const char *forbid, const char *reserved, int plus,
141 apr_size_t *len)
142 {
143 apr_size_t size = 1;
144 int found = 0;
145 const char *s = (const char *) url;
146 char *d = (char *) escaped;
147 register int badesc, badpath;
148
149 if (!url) {
150 return APR_NOTFOUND;
151 }
152
153 badesc = 0;
154 badpath = 0;
155 if (s) {
156 if (d) {
157 for (; *s && slen; ++s, d++, slen--) {
158 if (plus && *s == '+') {
159 *d = ' ';
160 found = 1;
161 }
162 else if (*s != '%') {
163 *d = *s;
164 }
165 else {
166 if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) {
167 badesc = 1;
168 *d = '%';
169 }
170 else {
171 char decoded;
172 decoded = x2c(s + 1);
173 if ((decoded == '\0')
174 || (forbid && strchr(forbid, decoded))) {
175 badpath = 1;
176 *d = decoded;
177 s += 2;
178 slen -= 2;
179 }
180 else if (reserved && strchr(reserved, decoded)) {
181 *d++ = *s++;
182 *d++ = *s++;
183 *d = *s;
184 size += 2;
185 }
186 else {
187 *d = decoded;
188 s += 2;
189 slen -= 2;
190 found = 1;
191 }
192 }
193 }
194 size++;
195 }
196 *d = '\0';
197 }
198 else {
199 for (; *s && slen; ++s, slen--) {
200 if (plus && *s == '+') {
201 found = 1;
202 }
203 else if (*s != '%') {
204 /* character unchanged */
205 }
206 else {
207 if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) {
208 badesc = 1;
209 }
210 else {
211 char decoded;
212 decoded = x2c(s + 1);
213 if ((decoded == '\0')
214 || (forbid && strchr(forbid, decoded))) {
215 badpath = 1;
216 s += 2;
217 slen -= 2;
218 }
219 else if (reserved && strchr(reserved, decoded)) {
220 s += 2;
221 slen -= 2;
222 size += 2;
223 }
224 else {
225 s += 2;
226 slen -= 2;
227 found = 1;
228 }
229 }
230 }
231 size++;
232 }
233 }
234 }
235
236 if (len) {
237 *len = size;
238 }
239 if (badesc) {
240 return APR_EINVAL;
241 }
242 else if (badpath) {
243 return APR_BADCH;
244 }
245 else if (!found) {
246 return APR_NOTFOUND;
247 }
248
249 return APR_SUCCESS;
250 }
251
apr_punescape_url(apr_pool_t * p,const char * url,const char * forbid,const char * reserved,int plus)252 APR_DECLARE(const char *) apr_punescape_url(apr_pool_t *p, const char *url,
253 const char *forbid, const char *reserved, int plus)
254 {
255 apr_size_t len;
256
257 switch (apr_unescape_url(NULL, url, APR_ESCAPE_STRING, forbid, reserved,
258 plus, &len)) {
259 case APR_SUCCESS: {
260 char *buf = apr_palloc(p, len);
261 apr_unescape_url(buf, url, APR_ESCAPE_STRING, forbid, reserved, plus,
262 NULL);
263 return buf;
264 }
265 case APR_EINVAL:
266 case APR_BADCH: {
267 return NULL;
268 }
269 case APR_NOTFOUND: {
270 break;
271 }
272 }
273
274 return url;
275 }
276
277 /* c2x takes an unsigned, and expects the caller has guaranteed that
278 * 0 <= what < 256... which usually means that you have to cast to
279 * unsigned char first, because (unsigned)(char)(x) first goes through
280 * signed extension to an int before the unsigned cast.
281 *
282 * The reason for this assumption is to assist gcc code generation --
283 * the unsigned char -> unsigned extension is already done earlier in
284 * both uses of this code, so there's no need to waste time doing it
285 * again.
286 */
287 static const char c2x_table[] = "0123456789abcdef";
288
c2x(unsigned what,unsigned char prefix,unsigned char * where)289 static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
290 unsigned char *where)
291 {
292 #if APR_CHARSET_EBCDIC
293 what = convert_e2a[(unsigned char)what];
294 #endif /*APR_CHARSET_EBCDIC*/
295 *where++ = prefix;
296 *where++ = c2x_table[what >> 4];
297 *where++ = c2x_table[what & 0xf];
298 return where;
299 }
300
apr_escape_path_segment(char * escaped,const char * str,apr_ssize_t slen,apr_size_t * len)301 APR_DECLARE(apr_status_t) apr_escape_path_segment(char *escaped,
302 const char *str, apr_ssize_t slen, apr_size_t *len)
303 {
304 apr_size_t size = 1;
305 int found = 0;
306 const unsigned char *s = (const unsigned char *) str;
307 unsigned char *d = (unsigned char *) escaped;
308 unsigned c;
309
310 if (s) {
311 if (d) {
312 while ((c = *s) && slen) {
313 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
314 d = c2x(c, '%', d);
315 size += 2;
316 found = 1;
317 }
318 else {
319 *d++ = c;
320 }
321 ++s;
322 size++;
323 slen--;
324 }
325 *d = '\0';
326 }
327 else {
328 while ((c = *s) && slen) {
329 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
330 size += 2;
331 found = 1;
332 }
333 ++s;
334 size++;
335 slen--;
336 }
337 }
338 }
339
340 if (len) {
341 *len = size;
342 }
343 if (!found) {
344 return APR_NOTFOUND;
345 }
346
347 return APR_SUCCESS;
348 }
349
apr_pescape_path_segment(apr_pool_t * p,const char * str)350 APR_DECLARE(const char *) apr_pescape_path_segment(apr_pool_t *p,
351 const char *str)
352 {
353 apr_size_t len;
354
355 switch (apr_escape_path_segment(NULL, str, APR_ESCAPE_STRING, &len)) {
356 case APR_SUCCESS: {
357 char *cmd = apr_palloc(p, len);
358 apr_escape_path_segment(cmd, str, APR_ESCAPE_STRING, NULL);
359 return cmd;
360 }
361 case APR_NOTFOUND: {
362 break;
363 }
364 }
365
366 return str;
367 }
368
apr_escape_path(char * escaped,const char * path,apr_ssize_t slen,int partial,apr_size_t * len)369 APR_DECLARE(apr_status_t) apr_escape_path(char *escaped, const char *path,
370 apr_ssize_t slen, int partial, apr_size_t *len)
371 {
372 apr_size_t size = 1;
373 int found = 0;
374 const unsigned char *s = (const unsigned char *) path;
375 unsigned char *d = (unsigned char *) escaped;
376 unsigned c;
377
378 if (!path) {
379 return APR_NOTFOUND;
380 }
381
382 if (!partial) {
383 const char *colon = strchr(path, ':');
384 const char *slash = strchr(path, '/');
385
386 if (colon && (!slash || colon < slash)) {
387 if (d) {
388 *d++ = '.';
389 *d++ = '/';
390 }
391 size += 2;
392 found = 1;
393 }
394 }
395 if (d) {
396 while ((c = *s) && slen) {
397 if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
398 d = c2x(c, '%', d);
399 size += 2;
400 found = 1;
401 }
402 else {
403 *d++ = c;
404 }
405 ++s;
406 size++;
407 slen--;
408 }
409 *d = '\0';
410 }
411 else {
412 while ((c = *s) && slen) {
413 if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
414 size += 2;
415 found = 1;
416 }
417 ++s;
418 size++;
419 slen--;
420 }
421 }
422
423 if (len) {
424 *len = size;
425 }
426 if (!found) {
427 return APR_NOTFOUND;
428 }
429
430 return APR_SUCCESS;
431 }
432
apr_pescape_path(apr_pool_t * p,const char * str,int partial)433 APR_DECLARE(const char *) apr_pescape_path(apr_pool_t *p, const char *str,
434 int partial)
435 {
436 apr_size_t len;
437
438 switch (apr_escape_path(NULL, str, APR_ESCAPE_STRING, partial, &len)) {
439 case APR_SUCCESS: {
440 char *path = apr_palloc(p, len);
441 apr_escape_path(path, str, APR_ESCAPE_STRING, partial, NULL);
442 return path;
443 }
444 case APR_NOTFOUND: {
445 break;
446 }
447 }
448
449 return str;
450 }
451
apr_escape_urlencoded(char * escaped,const char * str,apr_ssize_t slen,apr_size_t * len)452 APR_DECLARE(apr_status_t) apr_escape_urlencoded(char *escaped, const char *str,
453 apr_ssize_t slen, apr_size_t *len)
454 {
455 apr_size_t size = 1;
456 int found = 0;
457 const unsigned char *s = (const unsigned char *) str;
458 unsigned char *d = (unsigned char *) escaped;
459 unsigned c;
460
461 if (s) {
462 if (d) {
463 while ((c = *s) && slen) {
464 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
465 d = c2x(c, '%', d);
466 size += 2;
467 found = 1;
468 }
469 else if (c == ' ') {
470 *d++ = '+';
471 found = 1;
472 }
473 else {
474 *d++ = c;
475 }
476 ++s;
477 size++;
478 slen--;
479 }
480 *d = '\0';
481 }
482 else {
483 while ((c = *s) && slen) {
484 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
485 size += 2;
486 found = 1;
487 }
488 else if (c == ' ') {
489 found = 1;
490 }
491 ++s;
492 size++;
493 slen--;
494 }
495 }
496 }
497
498 if (len) {
499 *len = size;
500 }
501 if (!found) {
502 return APR_NOTFOUND;
503 }
504
505 return APR_SUCCESS;
506 }
507
apr_pescape_urlencoded(apr_pool_t * p,const char * str)508 APR_DECLARE(const char *) apr_pescape_urlencoded(apr_pool_t *p, const char *str)
509 {
510 apr_size_t len;
511
512 switch (apr_escape_urlencoded(NULL, str, APR_ESCAPE_STRING, &len)) {
513 case APR_SUCCESS: {
514 char *encoded = apr_palloc(p, len);
515 apr_escape_urlencoded(encoded, str, APR_ESCAPE_STRING, NULL);
516 return encoded;
517 }
518 case APR_NOTFOUND: {
519 break;
520 }
521 }
522
523 return str;
524 }
525
apr_escape_entity(char * escaped,const char * str,apr_ssize_t slen,int toasc,apr_size_t * len)526 APR_DECLARE(apr_status_t) apr_escape_entity(char *escaped, const char *str,
527 apr_ssize_t slen, int toasc, apr_size_t *len)
528 {
529 apr_size_t size = 1;
530 int found = 0;
531 const unsigned char *s = (const unsigned char *) str;
532 unsigned char *d = (unsigned char *) escaped;
533 unsigned c;
534
535 if (s) {
536 if (d) {
537 while ((c = *s) && slen) {
538 if (TEST_CHAR(c, T_ESCAPE_XML)) {
539 switch (c) {
540 case '>': {
541 memcpy(d, ">", 4);
542 size += 4;
543 d += 4;
544 break;
545 }
546 case '<': {
547 memcpy(d, "<", 4);
548 size += 4;
549 d += 4;
550 break;
551 }
552 case '&': {
553 memcpy(d, "&", 5);
554 size += 5;
555 d += 5;
556 break;
557 }
558 case '\"': {
559 memcpy(d, """, 6);
560 size += 6;
561 d += 6;
562 break;
563 }
564 case '\'': {
565 memcpy(d, "'", 6);
566 size += 6;
567 d += 6;
568 break;
569 }
570 }
571 found = 1;
572 }
573 else if (toasc && !apr_isascii(c)) {
574 int offset = apr_snprintf((char *) d, 6, "&#%3.3d;", c);
575 size += offset;
576 d += offset;
577 found = 1;
578 }
579 else {
580 *d++ = c;
581 size++;
582 }
583 ++s;
584 slen--;
585 }
586 *d = '\0';
587 }
588 else {
589 while ((c = *s) && slen) {
590 if (TEST_CHAR(c, T_ESCAPE_XML)) {
591 switch (c) {
592 case '>': {
593 size += 4;
594 break;
595 }
596 case '<': {
597 size += 4;
598 break;
599 }
600 case '&': {
601 size += 5;
602 break;
603 }
604 case '\"': {
605 size += 6;
606 break;
607 }
608 case '\'': {
609 size += 6;
610 break;
611 }
612 }
613 found = 1;
614 }
615 else if (toasc && !apr_isascii(c)) {
616 char buf[8];
617 size += apr_snprintf(buf, 6, "&#%3.3d;", c);
618 found = 1;
619 }
620 else {
621 size++;
622 }
623 ++s;
624 slen--;
625 }
626 }
627 }
628
629 if (len) {
630 *len = size;
631 }
632 if (!found) {
633 return APR_NOTFOUND;
634 }
635
636 return APR_SUCCESS;
637 }
638
apr_pescape_entity(apr_pool_t * p,const char * str,int toasc)639 APR_DECLARE(const char *) apr_pescape_entity(apr_pool_t *p, const char *str,
640 int toasc)
641 {
642 apr_size_t len;
643
644 switch (apr_escape_entity(NULL, str, APR_ESCAPE_STRING, toasc, &len)) {
645 case APR_SUCCESS: {
646 char *cmd = apr_palloc(p, len);
647 apr_escape_entity(cmd, str, APR_ESCAPE_STRING, toasc, NULL);
648 return cmd;
649 }
650 case APR_NOTFOUND: {
651 break;
652 }
653 }
654
655 return str;
656 }
657
658 /* maximum length of any ISO-LATIN-1 HTML entity name. */
659 #define MAXENTLEN (6)
660
apr_unescape_entity(char * unescaped,const char * str,apr_ssize_t slen,apr_size_t * len)661 APR_DECLARE(apr_status_t) apr_unescape_entity(char *unescaped, const char *str,
662 apr_ssize_t slen, apr_size_t *len)
663 {
664 int found = 0;
665 apr_size_t size = 1;
666 int val, i, j;
667 char *d = unescaped;
668 const char *s = str;
669 const char *ents;
670 static const char * const entlist[MAXENTLEN + 1] =
671 {
672 NULL, /* 0 */
673 NULL, /* 1 */
674 "lt\074gt\076", /* 2 */
675 "amp\046ETH\320eth\360", /* 3 */
676 "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml"
677 "\353iuml\357ouml\366uuml\374yuml\377", /* 4 */
678 "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc"
679 "\333THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352"
680 "icirc\356ocirc\364ucirc\373thorn\376", /* 5 */
681 "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311"
682 "Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde"
683 "\325Oslash\330Ugrave\331Uacute\332Yacute\335agrave\340"
684 "aacute\341atilde\343ccedil\347egrave\350eacute\351igrave"
685 "\354iacute\355ntilde\361ograve\362oacute\363otilde\365"
686 "oslash\370ugrave\371uacute\372yacute\375" /* 6 */
687 };
688
689 if (s) {
690 if (d) {
691 for (; *s != '\0' && slen; s++, d++, size++, slen--) {
692 if (*s != '&') {
693 *d = *s;
694 continue;
695 }
696 /* find end of entity */
697 for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0;
698 i++) {
699 continue;
700 }
701
702 if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */
703 *d = *s;
704 continue;
705 }
706
707 /* is it numeric ? */
708 if (s[1] == '#') {
709 for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) {
710 val = val * 10 + s[j] - '0';
711 }
712 s += i;
713 if (j < i || val <= 8 || (val >= 11 && val <= 31)
714 || (val >= 127 && val <= 160) || val >= 256) {
715 d--; /* no data to output */
716 size--;
717 }
718 else {
719 *d = ENCODE_TO_ASCII(val);
720 found = 1;
721 }
722 }
723 else {
724 j = i - 1;
725 if (j > MAXENTLEN || entlist[j] == NULL) {
726 /* wrong length */
727 *d = '&';
728 continue; /* skip it */
729 }
730 for (ents = entlist[j]; *ents != '\0'; ents += i) {
731 if (strncmp(s + 1, ents, j) == 0) {
732 break;
733 }
734 }
735
736 if (*ents == '\0') {
737 *d = '&'; /* unknown */
738 }
739 else {
740 *d = ENCODE_TO_ASCII(((const unsigned char *) ents)[j]);
741 s += i;
742 slen -= i;
743 found = 1;
744 }
745 }
746 }
747 *d = '\0';
748 }
749 else {
750 for (; *s != '\0' && slen; s++, size++, slen--) {
751 if (*s != '&') {
752 continue;
753 }
754 /* find end of entity */
755 for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0;
756 i++) {
757 continue;
758 }
759
760 if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */
761 continue;
762 }
763
764 /* is it numeric ? */
765 if (s[1] == '#') {
766 for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) {
767 val = val * 10 + s[j] - '0';
768 }
769 s += i;
770 if (j < i || val <= 8 || (val >= 11 && val <= 31)
771 || (val >= 127 && val <= 160) || val >= 256) {
772 /* no data to output */
773 size--;
774 }
775 else {
776 found = 1;
777 }
778 }
779 else {
780 j = i - 1;
781 if (j > MAXENTLEN || entlist[j] == NULL) {
782 /* wrong length */
783 continue; /* skip it */
784 }
785 for (ents = entlist[j]; *ents != '\0'; ents += i) {
786 if (strncmp(s + 1, ents, j) == 0) {
787 break;
788 }
789 }
790
791 if (*ents == '\0') {
792 /* unknown */
793 }
794 else {
795 s += i;
796 slen -= i;
797 found = 1;
798 }
799 }
800 }
801 }
802 }
803
804 if (len) {
805 *len = size;
806 }
807 if (!found) {
808 return APR_NOTFOUND;
809 }
810
811 return APR_SUCCESS;
812 }
813
apr_punescape_entity(apr_pool_t * p,const char * str)814 APR_DECLARE(const char *) apr_punescape_entity(apr_pool_t *p, const char *str)
815 {
816 apr_size_t len;
817
818 switch (apr_unescape_entity(NULL, str, APR_ESCAPE_STRING, &len)) {
819 case APR_SUCCESS: {
820 char *cmd = apr_palloc(p, len);
821 apr_unescape_entity(cmd, str, APR_ESCAPE_STRING, NULL);
822 return cmd;
823 }
824 case APR_NOTFOUND: {
825 break;
826 }
827 }
828
829 return str;
830 }
831
apr_escape_echo(char * escaped,const char * str,apr_ssize_t slen,int quote,apr_size_t * len)832 APR_DECLARE(apr_status_t) apr_escape_echo(char *escaped, const char *str,
833 apr_ssize_t slen, int quote, apr_size_t *len)
834 {
835 apr_size_t size = 1;
836 int found = 0;
837 const unsigned char *s = (const unsigned char *) str;
838 unsigned char *d = (unsigned char *) escaped;
839 unsigned c;
840
841 if (s) {
842 if (d) {
843 while ((c = *s) && slen) {
844 if (TEST_CHAR(c, T_ESCAPE_ECHO)) {
845 *d++ = '\\';
846 size++;
847 switch (c) {
848 case '\a':
849 *d++ = 'a';
850 size++;
851 found = 1;
852 break;
853 case '\b':
854 *d++ = 'b';
855 size++;
856 found = 1;
857 break;
858 case '\f':
859 *d++ = 'f';
860 size++;
861 found = 1;
862 break;
863 case '\n':
864 *d++ = 'n';
865 size++;
866 found = 1;
867 break;
868 case '\r':
869 *d++ = 'r';
870 size++;
871 found = 1;
872 break;
873 case '\t':
874 *d++ = 't';
875 size++;
876 found = 1;
877 break;
878 case '\v':
879 *d++ = 'v';
880 size++;
881 found = 1;
882 break;
883 case '\\':
884 *d++ = '\\';
885 size++;
886 found = 1;
887 break;
888 case '"':
889 if (quote) {
890 *d++ = c;
891 size++;
892 found = 1;
893 }
894 else {
895 d[-1] = c;
896 }
897 break;
898 default:
899 c2x(c, 'x', d);
900 d += 3;
901 size += 3;
902 found = 1;
903 break;
904 }
905 }
906 else {
907 *d++ = c;
908 size++;
909 }
910 ++s;
911 slen--;
912 }
913 *d = '\0';
914 }
915 else {
916 while ((c = *s) && slen) {
917 if (TEST_CHAR(c, T_ESCAPE_ECHO)) {
918 size++;
919 switch (c) {
920 case '\a':
921 case '\b':
922 case '\f':
923 case '\n':
924 case '\r':
925 case '\t':
926 case '\v':
927 case '\\':
928 size++;
929 found = 1;
930 break;
931 case '"':
932 if (quote) {
933 size++;
934 found = 1;
935 }
936 break;
937 default:
938 size += 3;
939 found = 1;
940 break;
941 }
942 }
943 else {
944 size++;
945 }
946 ++s;
947 slen--;
948 }
949 }
950 }
951
952 if (len) {
953 *len = size;
954 }
955 if (!found) {
956 return APR_NOTFOUND;
957 }
958
959 return APR_SUCCESS;
960 }
961
apr_pescape_echo(apr_pool_t * p,const char * str,int quote)962 APR_DECLARE(const char *) apr_pescape_echo(apr_pool_t *p, const char *str,
963 int quote)
964 {
965 apr_size_t len;
966
967 switch (apr_escape_echo(NULL, str, APR_ESCAPE_STRING, quote, &len)) {
968 case APR_SUCCESS: {
969 char *cmd = apr_palloc(p, len);
970 apr_escape_echo(cmd, str, APR_ESCAPE_STRING, quote, NULL);
971 return cmd;
972 }
973 case APR_NOTFOUND: {
974 break;
975 }
976 }
977
978 return str;
979 }
980
apr_escape_hex(char * dest,const void * src,apr_size_t srclen,int colon,apr_size_t * len)981 APR_DECLARE(apr_status_t) apr_escape_hex(char *dest, const void *src,
982 apr_size_t srclen, int colon, apr_size_t *len)
983 {
984 const unsigned char *in = src;
985 apr_size_t size;
986
987 if (!src) {
988 return APR_NOTFOUND;
989 }
990
991 if (dest) {
992 for (size = 0; size < srclen; size++) {
993 if (colon && size) {
994 *dest++ = ':';
995 }
996 *dest++ = c2x_table[in[size] >> 4];
997 *dest++ = c2x_table[in[size] & 0xf];
998 }
999 *dest = '\0';
1000 }
1001
1002 if (len) {
1003 if (colon && srclen) {
1004 *len = srclen * 3;
1005 }
1006 else {
1007 *len = srclen * 2 + 1;
1008 }
1009 }
1010
1011 return APR_SUCCESS;
1012 }
1013
apr_pescape_hex(apr_pool_t * p,const void * src,apr_size_t srclen,int colon)1014 APR_DECLARE(const char *) apr_pescape_hex(apr_pool_t *p, const void *src,
1015 apr_size_t srclen, int colon)
1016 {
1017 apr_size_t len;
1018
1019 switch (apr_escape_hex(NULL, src, srclen, colon, &len)) {
1020 case APR_SUCCESS: {
1021 char *cmd = apr_palloc(p, len);
1022 apr_escape_hex(cmd, src, srclen, colon, NULL);
1023 return cmd;
1024 }
1025 case APR_NOTFOUND: {
1026 break;
1027 }
1028 }
1029
1030 return src;
1031 }
1032
apr_unescape_hex(void * dest,const char * str,apr_ssize_t slen,int colon,apr_size_t * len)1033 APR_DECLARE(apr_status_t) apr_unescape_hex(void *dest, const char *str,
1034 apr_ssize_t slen, int colon, apr_size_t *len)
1035 {
1036 apr_size_t size = 0;
1037 int flip = 0;
1038 const unsigned char *s = (const unsigned char *) str;
1039 unsigned char *d = (unsigned char *) dest;
1040 unsigned c;
1041 unsigned char u = 0;
1042
1043 if (s) {
1044 if (d) {
1045 while ((c = *s) && slen) {
1046
1047 if (!flip) {
1048 u = 0;
1049 }
1050
1051 if (colon && c == ':' && !flip) {
1052 ++s;
1053 slen--;
1054 continue;
1055 }
1056 else if (apr_isdigit(c)) {
1057 u |= c - '0';
1058 }
1059 else if (apr_isupper(c) && c <= 'F') {
1060 u |= c - ('A' - 10);
1061 }
1062 else if (apr_islower(c) && c <= 'f') {
1063 u |= c - ('a' - 10);
1064 }
1065 else {
1066 return APR_BADCH;
1067 }
1068
1069 if (flip) {
1070 *d++ = u;
1071 size++;
1072 }
1073 else {
1074 u <<= 4;
1075 *d = u;
1076 }
1077 flip = !flip;
1078
1079 ++s;
1080 slen--;
1081 }
1082 }
1083 else {
1084 while ((c = *s) && slen) {
1085
1086 if (colon && c == ':' && !flip) {
1087 ++s;
1088 slen--;
1089 continue;
1090 }
1091 else if (apr_isdigit(c)) {
1092 /* valid */
1093 }
1094 else if (apr_isupper(c) && c <= 'F') {
1095 /* valid */
1096 }
1097 else if (apr_islower(c) && c <= 'f') {
1098 /* valid */
1099 }
1100 else {
1101 return APR_BADCH;
1102 }
1103
1104 if (flip) {
1105 size++;
1106 }
1107 flip = !flip;
1108
1109 ++s;
1110 slen--;
1111 }
1112 }
1113 }
1114
1115 if (len) {
1116 *len = size;
1117 }
1118 if (!s) {
1119 return APR_NOTFOUND;
1120 }
1121
1122 return APR_SUCCESS;
1123 }
1124
apr_punescape_hex(apr_pool_t * p,const char * str,int colon,apr_size_t * len)1125 APR_DECLARE(const void *) apr_punescape_hex(apr_pool_t *p, const char *str,
1126 int colon, apr_size_t *len)
1127 {
1128 apr_size_t size;
1129
1130 switch (apr_unescape_hex(NULL, str, APR_ESCAPE_STRING, colon, &size)) {
1131 case APR_SUCCESS: {
1132 void *cmd = apr_palloc(p, size);
1133 apr_unescape_hex(cmd, str, APR_ESCAPE_STRING, colon, len);
1134 return cmd;
1135 }
1136 case APR_BADCH:
1137 case APR_NOTFOUND: {
1138 break;
1139 }
1140 }
1141
1142 return NULL;
1143 }
1144
apr_escape_ldap(char * escaped,const void * str,apr_ssize_t slen,int flags,apr_size_t * len)1145 APR_DECLARE(apr_status_t) apr_escape_ldap(char *escaped, const void *str,
1146 apr_ssize_t slen, int flags, apr_size_t *len)
1147 {
1148 apr_size_t size = 1;
1149 int found = 0;
1150 const unsigned char *s = (const unsigned char *) str;
1151 unsigned char *d = (unsigned char *) escaped;
1152 unsigned c;
1153
1154 if (s) {
1155 if (d) {
1156 while (((c = *s) && slen) || (slen > 0)) {
1157 if (((flags & APR_ESCAPE_LDAP_DN) && TEST_CHAR(c, T_ESCAPE_LDAP_DN))
1158 || ((flags & APR_ESCAPE_LDAP_FILTER) && TEST_CHAR(c, T_ESCAPE_LDAP_FILTER))) {
1159 d = c2x(c, '\\', d);
1160 size += 2;
1161 found = 1;
1162 }
1163 else {
1164 *d++ = c;
1165 }
1166 ++s;
1167 size++;
1168 slen--;
1169 }
1170 *d = '\0';
1171 }
1172 else {
1173 while (((c = *s) && slen) || (slen > 0)) {
1174 if (((flags & APR_ESCAPE_LDAP_DN) && TEST_CHAR(c, T_ESCAPE_LDAP_DN))
1175 || ((flags & APR_ESCAPE_LDAP_FILTER) && TEST_CHAR(c, T_ESCAPE_LDAP_FILTER))) {
1176 size += 2;
1177 found = 1;
1178 }
1179 ++s;
1180 size++;
1181 slen--;
1182 }
1183 }
1184 }
1185
1186 if (len) {
1187 *len = size;
1188 }
1189 if (!found) {
1190 return APR_NOTFOUND;
1191 }
1192
1193 return APR_SUCCESS;
1194 }
1195
apr_pescape_ldap(apr_pool_t * p,const void * src,apr_ssize_t srclen,int flags)1196 APR_DECLARE(const char *) apr_pescape_ldap(apr_pool_t *p, const void *src,
1197 apr_ssize_t srclen, int flags)
1198 {
1199 apr_size_t len;
1200
1201 switch (apr_escape_ldap(NULL, src, srclen, flags, &len)) {
1202 case APR_SUCCESS: {
1203 char *encoded = apr_palloc(p, len);
1204 apr_escape_ldap(encoded, src, srclen, flags, NULL);
1205 return encoded;
1206 }
1207 case APR_NOTFOUND: {
1208 break;
1209 }
1210 }
1211
1212 return src;
1213 }
1214
1215