Coverage Report

Created: 2023-03-26 06:28

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