Coverage Report

Created: 2026-10-19 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/httpd/server/util.c
Line
Count
Source
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
/*
18
 * util.c: string utility things
19
 *
20
 * 3/21/93 Rob McCool
21
 * 1995-96 Many changes by the Apache Software Foundation
22
 *
23
 */
24
25
/* Debugging aid:
26
 * #define DEBUG            to trace all cfg_open*()/cfg_closefile() calls
27
 * #define DEBUG_CFG_LINES  to trace every line read from the config files
28
 */
29
30
#include "apr.h"
31
#include "apr_strings.h"
32
#include "apr_lib.h"
33
#include "apr_md5.h"            /* for apr_password_validate */
34
35
#define APR_WANT_STDIO
36
#define APR_WANT_STRFUNC
37
#include "apr_want.h"
38
39
#if APR_HAVE_UNISTD_H
40
#include <unistd.h>
41
#endif
42
#if APR_HAVE_PROCESS_H
43
#include <process.h>            /* for getpid() on Win32 */
44
#endif
45
#if APR_HAVE_NETDB_H
46
#include <netdb.h>              /* for gethostbyname() */
47
#endif
48
49
#include "ap_config.h"
50
#include "apr_base64.h"
51
#include "apr_fnmatch.h"
52
#include "httpd.h"
53
#include "http_main.h"
54
#include "http_log.h"
55
#include "http_protocol.h"
56
#include "http_config.h"
57
#include "http_core.h"
58
#include "util_ebcdic.h"
59
#include "util_varbuf.h"
60
61
#ifdef HAVE_PWD_H
62
#include <pwd.h>
63
#endif
64
#ifdef HAVE_GRP_H
65
#include <grp.h>
66
#endif
67
#ifdef HAVE_SYS_LOADAVG_H
68
#include <sys/loadavg.h>
69
#endif
70
71
#include "ap_mpm.h"
72
#include "mpm_common.h"         /* for ap_max_mem_free */
73
74
/* A bunch of functions in util.c scan strings looking for certain characters.
75
 * To make that more efficient we encode a lookup table.  The test_char_table
76
 * is generated automatically by gen_test_char.c.
77
 */
78
#include "test_char.h"
79
80
/* we know core's module_index is 0 */
81
#undef APLOG_MODULE_INDEX
82
0
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
83
84
/* maximum nesting level for config directories */
85
#ifndef AP_MAX_FNMATCH_DIR_DEPTH
86
0
#define AP_MAX_FNMATCH_DIR_DEPTH (128)
87
#endif
88
89
/*
90
 * Examine a field value (such as a media-/content-type) string and return
91
 * it sans any parameters; e.g., strip off any ';charset=foo' and the like.
92
 */
93
AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype)
94
1.21k
{
95
1.21k
    const char *semi;
96
97
1.21k
    if (intype == NULL) return NULL;
98
99
1.21k
    semi = ap_strchr_c(intype, ';');
100
1.21k
    if (semi == NULL) {
101
1.11k
        return apr_pstrdup(p, intype);
102
1.11k
    }
103
100
    else {
104
230
        while ((semi > intype) && apr_isspace(semi[-1])) {
105
130
            semi--;
106
130
        }
107
100
        return apr_pstrmemdup(p, intype, semi - intype);
108
100
    }
109
1.21k
}
110
111
AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt,
112
                              int gmt)
113
0
{
114
0
    apr_size_t retcode;
115
0
    char ts[MAX_STRING_LEN];
116
0
    char tf[MAX_STRING_LEN];
117
0
    apr_time_exp_t xt;
118
119
0
    if (gmt) {
120
0
        const char *f;
121
0
        char *strp;
122
123
0
        apr_time_exp_gmt(&xt, t);
124
        /* Convert %Z to "GMT" and %z to "+0000";
125
         * on hosts that do not have a time zone string in struct tm,
126
         * strftime must assume its argument is local time.
127
         */
128
0
        for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f)
129
0
            ; f++, strp++) {
130
0
            if (*f != '%') continue;
131
0
            switch (f[1]) {
132
0
            case '%':
133
0
                *++strp = *++f;
134
0
                break;
135
0
            case 'Z':
136
0
                *strp++ = 'G';
137
0
                *strp++ = 'M';
138
0
                *strp = 'T';
139
0
                f++;
140
0
                break;
141
0
            case 'z': /* common extension */
142
0
                *strp++ = '+';
143
0
                *strp++ = '0';
144
0
                *strp++ = '0';
145
0
                *strp++ = '0';
146
0
                *strp = '0';
147
0
                f++;
148
0
                break;
149
0
            }
150
0
        }
151
0
        *strp = '\0';
152
0
        fmt = tf;
153
0
    }
154
0
    else {
155
0
        apr_time_exp_lt(&xt, t);
156
0
    }
157
158
    /* check return code? */
159
0
    apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt);
160
0
    ts[MAX_STRING_LEN - 1] = '\0';
161
0
    return apr_pstrdup(p, ts);
162
0
}
163
164
/* Roy owes Rob beer. */
165
/* Rob owes Roy dinner. */
166
167
/* These legacy comments would make a lot more sense if Roy hadn't
168
 * replaced the old later_than() routine with util_date.c.
169
 *
170
 * Well, okay, they still wouldn't make any sense.
171
 */
172
173
/* Match = 0, NoMatch = 1, Abort = -1
174
 * Based loosely on sections of wildmat.c by Rich Salz
175
 * Hmmm... shouldn't this really go component by component?
176
 */
177
AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
178
5.33k
{
179
5.33k
    apr_size_t x, y;
180
181
8.50k
    for (x = 0, y = 0; expected[y]; ++y, ++x) {
182
8.16k
        if (expected[y] == '*') {
183
863
            while (expected[++y] == '*');
184
617
            if (!expected[y])
185
5
                return 0;
186
4.17k
            while (str[x]) {
187
4.12k
                int ret;
188
4.12k
                if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1)
189
556
                    return ret;
190
4.12k
            }
191
56
            return -1;
192
612
        }
193
7.55k
        else if (!str[x])
194
18
            return -1;
195
7.53k
        else if ((expected[y] != '?') && (str[x] != expected[y]))
196
4.36k
            return 1;
197
8.16k
    }
198
334
    return (str[x] != '\0');
199
5.33k
}
200
201
AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
202
5.33k
{
203
5.33k
    apr_size_t x, y;
204
205
8.50k
    for (x = 0, y = 0; expected[y]; ++y, ++x) {
206
8.17k
        if (!str[x] && expected[y] != '*')
207
18
            return -1;
208
8.15k
        if (expected[y] == '*') {
209
863
            while (expected[++y] == '*');
210
617
            if (!expected[y])
211
5
                return 0;
212
4.17k
            while (str[x]) {
213
4.12k
                int ret;
214
4.12k
                if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1)
215
556
                    return ret;
216
4.12k
            }
217
56
            return -1;
218
612
        }
219
7.53k
        else if (expected[y] != '?'
220
6.19k
                 && apr_tolower(str[x]) != apr_tolower(expected[y]))
221
4.36k
            return 1;
222
8.15k
    }
223
334
    return (str[x] != '\0');
224
5.33k
}
225
226
/* We actually compare the canonical root to this root, (but we don't
227
 * waste time checking the case), since every use of this function in
228
 * httpd-2.1 tests if the path is 'proper', meaning we've already passed
229
 * it through apr_filepath_merge, or we haven't.
230
 */
231
AP_DECLARE(int) ap_os_is_path_absolute(apr_pool_t *p, const char *dir)
232
0
{
233
0
    const char *newpath;
234
0
    const char *ourdir = dir;
235
0
    if (apr_filepath_root(&newpath, &dir, 0, p) != APR_SUCCESS
236
0
            || strncmp(newpath, ourdir, strlen(newpath)) != 0) {
237
0
        return 0;
238
0
    }
239
0
    return 1;
240
0
}
241
242
AP_DECLARE(int) ap_is_matchexp(const char *str)
243
0
{
244
0
    for (; *str; str++)
245
0
        if ((*str == '*') || (*str == '?'))
246
0
            return 1;
247
0
    return 0;
248
0
}
249
250
/*
251
 * Here's a pool-based interface to the POSIX-esque ap_regcomp().
252
 * Note that we return ap_regex_t instead of being passed one.
253
 * The reason is that if you use an already-used ap_regex_t structure,
254
 * the memory that you've already allocated gets forgotten, and
255
 * regfree() doesn't clear it. So we don't allow it.
256
 */
257
258
static apr_status_t regex_cleanup(void *preg)
259
0
{
260
0
    ap_regfree((ap_regex_t *) preg);
261
0
    return APR_SUCCESS;
262
0
}
263
264
AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
265
                                     int cflags)
266
0
{
267
0
    ap_regex_t *preg = apr_palloc(p, sizeof *preg);
268
0
    int err = ap_regcomp(preg, pattern, cflags);
269
0
    if (err) {
270
0
        if (err == AP_REG_ESPACE)
271
0
            ap_abort_on_oom();
272
0
        return NULL;
273
0
    }
274
275
0
    apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
276
0
                              apr_pool_cleanup_null);
277
278
0
    return preg;
279
0
}
280
281
AP_DECLARE(void) ap_pregfree(apr_pool_t *p, ap_regex_t *reg)
282
0
{
283
0
    ap_regfree(reg);
284
0
    apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup);
285
0
}
286
287
/*
288
 * Similar to standard strstr() but we ignore case in this version.
289
 * Based on the strstr() implementation further below.
290
 */
291
AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2)
292
1.21k
{
293
1.21k
    char *p1, *p2;
294
1.21k
    if (*s2 == '\0') {
295
        /* an empty s2 */
296
169
        return((char *)s1);
297
169
    }
298
10.4k
    while(1) {
299
49.7k
        for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
300
10.4k
        if (*s1 == '\0') {
301
1.00k
            return(NULL);
302
1.00k
        }
303
        /* found first character of s2, see if the rest matches */
304
9.46k
        p1 = (char *)s1;
305
9.46k
        p2 = (char *)s2;
306
60.7k
        for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
307
51.2k
            if (*p1 == '\0') {
308
                /* both strings ended together */
309
8
                return((char *)s1);
310
8
            }
311
51.2k
        }
312
9.46k
        if (*p2 == '\0') {
313
            /* second string ended, a match */
314
32
            break;
315
32
        }
316
        /* didn't find a match here, try starting at next character in s1 */
317
9.42k
        s1++;
318
9.42k
    }
319
32
    return((char *)s1);
320
1.04k
}
321
322
/*
323
 * Returns an offsetted pointer in bigstring immediately after
324
 * prefix. Returns bigstring if bigstring doesn't start with
325
 * prefix or if prefix is longer than bigstring while still matching.
326
 * NOTE: pointer returned is relative to bigstring, so we
327
 * can use standard pointer comparisons in the calling function
328
 * (eg: test if ap_stripprefix(a,b) == a)
329
 */
330
AP_DECLARE(const char *) ap_stripprefix(const char *bigstring,
331
                                        const char *prefix)
332
0
{
333
0
    const char *p1;
334
335
0
    if (*prefix == '\0')
336
0
        return bigstring;
337
338
0
    p1 = bigstring;
339
0
    while (*p1 && *prefix) {
340
0
        if (*p1++ != *prefix++)
341
0
            return bigstring;
342
0
    }
343
0
    if (*prefix == '\0')
344
0
        return p1;
345
346
    /* hit the end of bigstring! */
347
0
    return bigstring;
348
0
}
349
350
/* This function substitutes for $0-$9, filling in regular expression
351
 * submatches. Pass it the same nmatch and pmatch arguments that you
352
 * passed ap_regexec(). pmatch should not be greater than the maximum number
353
 * of subexpressions - i.e. one more than the re_nsub member of ap_regex_t.
354
 *
355
 * nmatch must be <=AP_MAX_REG_MATCH (10).
356
 *
357
 * input should be the string with the $-expressions, source should be the
358
 * string that was matched against.
359
 *
360
 * It returns the substituted string, or NULL if a vbuf is used.
361
 * On errors, returns the orig string.
362
 *
363
 * Parts of this code are based on Henry Spencer's regsub(), from his
364
 * AT&T V8 regexp package.
365
 */
366
367
static apr_status_t regsub_core(apr_pool_t *p, char **result,
368
                                struct ap_varbuf *vb, const char *input,
369
                                const char *source, apr_size_t nmatch,
370
                                ap_regmatch_t pmatch[], apr_size_t maxlen)
371
0
{
372
0
    const char *src = input;
373
0
    char *dst;
374
0
    char c;
375
0
    apr_size_t no;
376
0
    apr_size_t len = 0;
377
378
0
    AP_DEBUG_ASSERT((result && p && !vb) || (vb && !p && !result));
379
0
    if (!source || nmatch>AP_MAX_REG_MATCH)
380
0
        return APR_EINVAL;
381
0
    if (!nmatch) {
382
0
        len = strlen(src);
383
0
        if (maxlen > 0 && len >= maxlen)
384
0
            return APR_ENOMEM;
385
0
        if (!vb) {
386
0
            *result = apr_pstrmemdup(p, src, len);
387
0
            return APR_SUCCESS;
388
0
        }
389
0
        else {
390
0
            ap_varbuf_strmemcat(vb, src, len);
391
0
            return APR_SUCCESS;
392
0
        }
393
0
    }
394
395
    /* First pass, find the size */
396
0
    while ((c = *src++) != '\0') {
397
0
        if (c == '$' && apr_isdigit(*src))
398
0
            no = *src++ - '0';
399
0
        else
400
0
            no = AP_MAX_REG_MATCH;
401
402
0
        if (no >= AP_MAX_REG_MATCH) {  /* Ordinary character. */
403
0
            if (c == '\\' && *src)
404
0
                src++;
405
0
            len++;
406
0
        }
407
0
        else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
408
0
            if (APR_SIZE_MAX - len <= pmatch[no].rm_eo - pmatch[no].rm_so)
409
0
                return APR_ENOMEM;
410
0
            len += pmatch[no].rm_eo - pmatch[no].rm_so;
411
0
        }
412
413
0
    }
414
415
0
    if (len >= maxlen && maxlen > 0)
416
0
        return APR_ENOMEM;
417
418
0
    if (!vb) {
419
0
        *result = dst = apr_palloc(p, len + 1);
420
0
    }
421
0
    else {
422
0
        if (vb->strlen == AP_VARBUF_UNKNOWN)
423
0
            vb->strlen = strlen(vb->buf);
424
0
        ap_varbuf_grow(vb, vb->strlen + len);
425
0
        dst = vb->buf + vb->strlen;
426
0
        vb->strlen += len;
427
0
    }
428
429
    /* Now actually fill in the string */
430
431
0
    src = input;
432
433
0
    while ((c = *src++) != '\0') {
434
0
        if (c == '$' && apr_isdigit(*src))
435
0
            no = *src++ - '0';
436
0
        else
437
0
            no = AP_MAX_REG_MATCH;
438
439
0
        if (no >= AP_MAX_REG_MATCH) {  /* Ordinary character. */
440
0
            if (c == '\\' && *src)
441
0
                c = *src++;
442
0
            *dst++ = c;
443
0
        }
444
0
        else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
445
0
            len = pmatch[no].rm_eo - pmatch[no].rm_so;
446
0
            memcpy(dst, source + pmatch[no].rm_so, len);
447
0
            dst += len;
448
0
        }
449
450
0
    }
451
0
    *dst = '\0';
452
453
0
    return APR_SUCCESS;
454
0
}
455
456
#ifndef AP_PREGSUB_MAXLEN
457
0
#define AP_PREGSUB_MAXLEN   (HUGE_STRING_LEN * 8)
458
#endif
459
AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
460
                              const char *source, apr_size_t nmatch,
461
                              ap_regmatch_t pmatch[])
462
0
{
463
0
    char *result;
464
0
    apr_status_t rc = regsub_core(p, &result, NULL, input, source, nmatch,
465
0
                                  pmatch, AP_PREGSUB_MAXLEN);
466
0
    if (rc != APR_SUCCESS)
467
0
        result = NULL;
468
0
    return result;
469
0
}
470
471
AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result,
472
                                       const char *input, const char *source,
473
                                       apr_size_t nmatch, ap_regmatch_t pmatch[],
474
                                       apr_size_t maxlen)
475
0
{
476
0
    apr_status_t rc = regsub_core(p, result, NULL, input, source, nmatch,
477
0
                                  pmatch, maxlen);
478
0
    if (rc != APR_SUCCESS)
479
0
        *result = NULL;
480
0
    return rc;
481
0
}
482
483
/* Forward declare */
484
static char x2c(const char *what);
485
486
973
#define IS_SLASH_OR_NUL(s) (s == '\0' || AP_IS_SLASH(s))
487
488
/*
489
 * Inspired by mod_jk's jk_servlet_normalize().
490
 */
491
AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags)
492
398
{
493
398
    int ret = 1;
494
398
    apr_size_t l = 1, w = 1, n;
495
398
    int decode_unreserved = (flags & AP_NORMALIZE_DECODE_UNRESERVED) != 0;
496
398
    int merge_slashes = (flags & AP_NORMALIZE_MERGE_SLASHES) != 0;
497
498
398
    if (!AP_IS_SLASH(path[0])) {
499
        /* Besides "OPTIONS *", a request-target should start with '/'
500
         * per RFC 7230 section 5.3, so anything else is invalid.
501
         */
502
380
        if (path[0] == '*' && path[1] == '\0') {
503
1
            return 1;
504
1
        }
505
        /* However, AP_NORMALIZE_ALLOW_RELATIVE can be used to bypass
506
         * this restriction (e.g. for subrequest file lookups).
507
         */
508
379
        if (!(flags & AP_NORMALIZE_ALLOW_RELATIVE) || path[0] == '\0') {
509
52
            return 0;
510
52
        }
511
512
327
        l = w = 0;
513
327
    }
514
515
15.9k
    while (path[l] != '\0') {
516
        /* RFC-3986 section 2.3:
517
         *  For consistency, percent-encoded octets in the ranges of
518
         *  ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D),
519
         *  period (%2E), underscore (%5F), or tilde (%7E) should [...]
520
         *  be decoded to their corresponding unreserved characters by
521
         *  URI normalizers.
522
         */
523
15.6k
        if (decode_unreserved && path[l] == '%') {
524
0
            if (apr_isxdigit(path[l + 1]) && apr_isxdigit(path[l + 2])) {
525
0
                const char c = x2c(&path[l + 1]);
526
0
                if (TEST_CHAR(c, T_URI_UNRESERVED)) {
527
                    /* Replace last char and fall through as the current
528
                     * read position */
529
0
                    l += 2;
530
0
                    path[l] = c;
531
0
                }
532
0
            }
533
0
            else {
534
                /* Invalid encoding */
535
0
                ret = 0;
536
0
            }
537
0
        }
538
539
15.6k
        if (w == 0 || AP_IS_SLASH(path[w - 1])) {
540
            /* Collapse ///// sequences to / */
541
1.35k
            if (merge_slashes && AP_IS_SLASH(path[l])) {
542
0
                do {
543
0
                    l++;
544
0
                } while (AP_IS_SLASH(path[l]));
545
0
                continue;
546
0
            }
547
548
1.35k
            if (path[l] == '.') {
549
                /* Remove /./ segments */
550
664
                if (IS_SLASH_OR_NUL(path[l + 1])) {
551
250
                    l++;
552
250
                    if (path[l]) {
553
247
                        l++;
554
247
                    }
555
250
                    continue;
556
250
                }
557
558
                /* Remove /xx/../ segments (or /xx/.%2e/ when
559
                 * AP_NORMALIZE_DECODE_UNRESERVED is set since we
560
                 * decoded only the first dot above).
561
                 */
562
414
                n = l + 1;
563
414
                if ((path[n] == '.' || (decode_unreserved
564
0
                                        && path[n] == '%'
565
0
                                        && path[++n] == '2'
566
0
                                        && (path[++n] == 'e'
567
0
                                            || path[n] == 'E')))
568
309
                        && IS_SLASH_OR_NUL(path[n + 1])) {
569
                    /* Wind w back to remove the previous segment */
570
227
                    if (w > 1) {
571
854
                        do {
572
854
                            w--;
573
854
                        } while (w && !AP_IS_SLASH(path[w - 1]));
574
134
                    }
575
93
                    else {
576
                        /* Already at root, ignore and return a failure
577
                         * if asked to.
578
                         */
579
93
                        if (flags & AP_NORMALIZE_NOT_ABOVE_ROOT) {
580
93
                            ret = 0;
581
93
                        }
582
93
                    }
583
584
                    /* Move l forward to the next segment */
585
227
                    l = n + 1;
586
227
                    if (path[l]) {
587
222
                        l++;
588
222
                    }
589
227
                    continue;
590
227
                }
591
414
            }
592
1.35k
        }
593
594
15.1k
        path[w++] = path[l++];
595
15.1k
    }
596
345
    path[w] = '\0';
597
598
345
    return ret;
599
398
}
600
601
/*
602
 * Parse .. so we don't compromise security
603
 */
604
AP_DECLARE(void) ap_getparents(char *name)
605
398
{
606
398
    if (!ap_normalize_path(name, AP_NORMALIZE_NOT_ABOVE_ROOT |
607
398
                                 AP_NORMALIZE_ALLOW_RELATIVE)) {
608
73
        name[0] = '\0';
609
73
    }
610
398
}
611
612
AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path)
613
323
{
614
615
323
    char *d, *s;
616
617
323
    if (!*name) {
618
53
        return;
619
53
    }
620
621
270
    s = d = name;
622
623
#ifdef HAVE_UNC_PATHS
624
    /* Check for UNC names.  Leave leading two slashes. */
625
    if (is_fs_path && s[0] == '/' && s[1] == '/')
626
        *d++ = *s++;
627
#endif
628
629
12.6k
    while (*s) {
630
12.4k
        if ((*d++ = *s) == '/') {
631
541
            do {
632
541
                ++s;
633
541
            } while (*s == '/');
634
322
        }
635
12.1k
        else {
636
12.1k
            ++s;
637
12.1k
        }
638
12.4k
    }
639
270
    *d = '\0';
640
270
}
641
642
AP_DECLARE(void) ap_no2slash(char *name)
643
323
{
644
323
    ap_no2slash_ex(name, 1);
645
323
}
646
647
/*
648
 * copy at most n leading directories of s into d
649
 * d should be at least as large as s plus 1 extra byte
650
 * assumes n > 0
651
 * the return value is the ever useful pointer to the trailing \0 of d
652
 *
653
 * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments,
654
 * so that if n == 0, "/" is returned in d with n == 1
655
 * and s == "e:/test.html", "e:/" is returned in d
656
 * *** See also ap_directory_walk in server/request.c
657
 *
658
 * examples:
659
 *    /a/b, 0  ==> /  (true for all platforms)
660
 *    /a/b, 1  ==> /
661
 *    /a/b, 2  ==> /a/
662
 *    /a/b, 3  ==> /a/b/
663
 *    /a/b, 4  ==> /a/b/
664
 *
665
 *    c:/a/b 0 ==> /
666
 *    c:/a/b 1 ==> c:/
667
 *    c:/a/b 2 ==> c:/a/
668
 *    c:/a/b 3 ==> c:/a/b
669
 *    c:/a/b 4 ==> c:/a/b
670
 */
671
AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
672
0
{
673
0
    if (n < 1) {
674
0
        *d = '/';
675
0
        *++d = '\0';
676
0
        return (d);
677
0
    }
678
679
0
    for (;;) {
680
0
        if (*s == '\0' || (*s == '/' && (--n) == 0)) {
681
0
            *d = '/';
682
0
            break;
683
0
        }
684
0
        *d++ = *s++;
685
0
    }
686
0
    *++d = 0;
687
0
    return (d);
688
0
}
689
690
691
/*
692
 * return the parent directory name including trailing / of the file s
693
 */
694
AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s)
695
212
{
696
212
    const char *last_slash = ap_strrchr_c(s, '/');
697
212
    char *d;
698
212
    int l;
699
700
212
    if (last_slash == NULL) {
701
188
        return apr_pstrdup(p, "");
702
188
    }
703
24
    l = (last_slash - s) + 1;
704
24
    d = apr_pstrmemdup(p, s, l);
705
706
24
    return (d);
707
212
}
708
709
710
AP_DECLARE(int) ap_count_dirs(const char *path)
711
0
{
712
0
    int x, n;
713
714
0
    for (x = 0, n = 0; path[x]; x++)
715
0
        if (path[x] == '/')
716
0
            n++;
717
0
    return n;
718
0
}
719
720
AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop)
721
0
{
722
0
    return ap_getword(atrans, (const char **) line, stop);
723
0
}
724
725
AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop)
726
1.21k
{
727
1.21k
    const char *pos = *line;
728
1.21k
    int len;
729
1.21k
    char *res;
730
731
57.2k
    while ((*pos != stop) && *pos) {
732
56.0k
        ++pos;
733
56.0k
    }
734
735
1.21k
    len = pos - *line;
736
1.21k
    res = apr_pstrmemdup(atrans, *line, len);
737
738
1.21k
    if (stop) {
739
0
        while (*pos == stop) {
740
0
            ++pos;
741
0
        }
742
0
    }
743
1.21k
    *line = pos;
744
745
1.21k
    return res;
746
1.21k
}
747
748
AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
749
168
{
750
168
    return ap_getword_white(atrans, (const char **) line);
751
168
}
752
753
AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
754
168
{
755
168
    const char *pos = *line;
756
168
    int len;
757
168
    char *res;
758
759
2.50k
    while (!apr_isspace(*pos) && *pos) {
760
2.33k
        ++pos;
761
2.33k
    }
762
763
168
    len = pos - *line;
764
168
    res = apr_pstrmemdup(atrans, *line, len);
765
766
458
    while (apr_isspace(*pos)) {
767
290
        ++pos;
768
290
    }
769
770
168
    *line = pos;
771
772
168
    return res;
773
168
}
774
775
AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line,
776
                                       char stop)
777
0
{
778
0
    return ap_getword_nulls(atrans, (const char **) line, stop);
779
0
}
780
781
AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line,
782
                                    char stop)
783
0
{
784
0
    const char *pos = ap_strchr_c(*line, stop);
785
0
    char *res;
786
787
0
    if (!pos) {
788
0
        apr_size_t len = strlen(*line);
789
0
        res = apr_pstrmemdup(atrans, *line, len);
790
0
        *line += len;
791
0
        return res;
792
0
    }
793
794
0
    res = apr_pstrmemdup(atrans, *line, pos - *line);
795
796
0
    ++pos;
797
798
0
    *line = pos;
799
800
0
    return res;
801
0
}
802
803
/* Get a word, (new) config-file style --- quoted strings and backslashes
804
 * all honored
805
 */
806
807
static char *substring_conf(apr_pool_t *p, const char *start, int len,
808
                            char quote)
809
1.19k
{
810
1.19k
    char *result = apr_palloc(p, len + 1);
811
1.19k
    char *resp = result;
812
1.19k
    int i;
813
814
32.9k
    for (i = 0; i < len; ++i) {
815
31.7k
        if (start[i] == '\\' && (start[i + 1] == '\\'
816
1.00k
                                 || (quote && start[i + 1] == quote)))
817
864
            *resp++ = start[++i];
818
30.8k
        else
819
30.8k
            *resp++ = start[i];
820
31.7k
    }
821
822
1.19k
    *resp++ = '\0';
823
#if RESOLVE_ENV_PER_TOKEN
824
    return (char *)ap_resolve_env(p,result);
825
#else
826
1.19k
    return result;
827
1.19k
#endif
828
1.19k
}
829
830
AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line)
831
0
{
832
0
    return ap_getword_conf(p, (const char **) line);
833
0
}
834
835
AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line)
836
81
{
837
81
    const char *str = *line, *strend;
838
81
    char *res;
839
81
    char quote;
840
841
290
    while (apr_isspace(*str))
842
209
        ++str;
843
844
81
    if (!*str) {
845
0
        *line = str;
846
0
        return "";
847
0
    }
848
849
81
    if ((quote = *str) == '"' || quote == '\'') {
850
81
        strend = str + 1;
851
2.28k
        while (*strend && *strend != quote) {
852
2.20k
            if (*strend == '\\' && strend[1] &&
853
494
                (strend[1] == quote || strend[1] == '\\')) {
854
253
                strend += 2;
855
253
            }
856
1.94k
            else {
857
1.94k
                ++strend;
858
1.94k
            }
859
2.20k
        }
860
81
        res = substring_conf(p, str + 1, strend - str - 1, quote);
861
862
81
        if (*strend == quote)
863
29
            ++strend;
864
81
    }
865
0
    else {
866
0
        strend = str;
867
0
        while (*strend && !apr_isspace(*strend))
868
0
            ++strend;
869
870
0
        res = substring_conf(p, str, strend - str, 0);
871
0
    }
872
873
239
    while (apr_isspace(*strend))
874
158
        ++strend;
875
81
    *line = strend;
876
81
    return res;
877
81
}
878
879
AP_DECLARE(char *) ap_getword_conf2_nc(apr_pool_t *p, char **line)
880
0
{
881
0
    return ap_getword_conf2(p, (const char **) line);
882
0
}
883
884
AP_DECLARE(char *) ap_getword_conf2(apr_pool_t *p, const char **line)
885
1.21k
{
886
1.21k
    const char *str = *line, *strend;
887
1.21k
    char *res;
888
1.21k
    char quote;
889
1.21k
    int count = 1;
890
891
2.75k
    while (apr_isspace(*str))
892
1.54k
        ++str;
893
894
1.21k
    if (!*str) {
895
18
        *line = str;
896
18
        return "";
897
18
    }
898
899
1.19k
    if ((quote = *str) == '"' || quote == '\'')
900
81
        return ap_getword_conf(p, line);
901
902
1.11k
    if (quote == '{') {
903
87
        strend = str + 1;
904
4.28k
        while (*strend) {
905
4.19k
            if (*strend == '}' && !--count)
906
2
                break;
907
4.19k
            if (*strend == '{')
908
359
                ++count;
909
4.19k
            if (*strend == '\\' && strend[1] == '\\') {
910
234
                ++strend;
911
234
            }
912
4.19k
            ++strend;
913
4.19k
        }
914
87
        res = substring_conf(p, str + 1, strend - str - 1, 0);
915
916
87
        if (*strend == '}')
917
2
            ++strend;
918
87
    }
919
1.02k
    else {
920
1.02k
        strend = str;
921
26.7k
        while (*strend && !apr_isspace(*strend))
922
25.7k
            ++strend;
923
924
1.02k
        res = substring_conf(p, str, strend - str, 0);
925
1.02k
    }
926
927
2.76k
    while (apr_isspace(*strend))
928
1.65k
        ++strend;
929
1.11k
    *line = strend;
930
1.11k
    return res;
931
1.19k
}
932
933
AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp)
934
0
{
935
#ifdef DEBUG
936
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00551)
937
        "Done with config file %s", cfp->name);
938
#endif
939
0
    return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
940
0
}
941
942
/* we can't use apr_file_* directly because of linking issues on Windows */
943
static apr_status_t cfg_close(void *param)
944
0
{
945
0
    return apr_file_close(param);
946
0
}
947
948
static apr_status_t cfg_getch(char *ch, void *param)
949
16.2k
{
950
16.2k
    return apr_file_getc(ch, param);
951
16.2k
}
952
953
static apr_status_t cfg_getstr(void *buf, apr_size_t bufsiz, void *param)
954
753k
{
955
753k
    return apr_file_gets(buf, bufsiz, param);
956
753k
}
957
958
/* Open a ap_configfile_t as FILE, return open ap_configfile_t struct pointer */
959
AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg,
960
                                          apr_pool_t *p, const char *name)
961
1.21k
{
962
1.21k
    ap_configfile_t *new_cfg;
963
1.21k
    apr_file_t *file = NULL;
964
1.21k
    apr_finfo_t finfo;
965
1.21k
    apr_status_t status;
966
#ifdef DEBUG
967
    char buf[120];
968
#endif
969
970
1.21k
    if (name == NULL) {
971
0
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00552)
972
0
               "Internal error: pcfg_openfile() called with NULL filename");
973
0
        return APR_EBADF;
974
0
    }
975
976
1.21k
    status = apr_file_open(&file, name, APR_READ | APR_BUFFERED,
977
1.21k
                           APR_OS_DEFAULT, p);
978
#ifdef DEBUG
979
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00553)
980
                "Opening config file %s (%s)",
981
                name, (status != APR_SUCCESS) ?
982
                apr_strerror(status, buf, sizeof(buf)) : "successful");
983
#endif
984
1.21k
    if (status != APR_SUCCESS)
985
0
        return status;
986
987
1.21k
    status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file);
988
1.21k
    if (status != APR_SUCCESS)
989
0
        return status;
990
991
1.21k
    if (finfo.filetype != APR_REG &&
992
#if defined(WIN32) || defined(OS2) || defined(NETWARE)
993
        ap_cstr_casecmp(apr_filepath_name_get(name), "nul") != 0) {
994
#else
995
0
        strcmp(name, "/dev/null") != 0) {
996
0
#endif /* WIN32 || OS2 */
997
0
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00554)
998
0
                     "Access to file %s denied by server: not a regular file",
999
0
                     name);
1000
0
        apr_file_close(file);
1001
0
        return APR_EBADF;
1002
0
    }
1003
1004
#ifdef WIN32
1005
    /* Some twisted character [no pun intended] at MS decided that a
1006
     * zero width joiner as the lead wide character would be ideal for
1007
     * describing Unicode text files.  This was further convoluted to
1008
     * another MSism that the same character mapped into utf-8, EF BB BF
1009
     * would signify utf-8 text files.
1010
     *
1011
     * Since MS configuration files are all protecting utf-8 encoded
1012
     * Unicode path, file and resource names, we already have the correct
1013
     * WinNT encoding.  But at least eat the stupid three bytes up front.
1014
     */
1015
    {
1016
        unsigned char buf[4];
1017
        apr_size_t len = 3;
1018
        status = apr_file_read(file, buf, &len);
1019
        if ((status != APR_SUCCESS) || (len < 3)
1020
              || memcmp(buf, "\xEF\xBB\xBF", 3) != 0) {
1021
            apr_off_t zero = 0;
1022
            apr_file_seek(file, APR_SET, &zero);
1023
        }
1024
    }
1025
#endif
1026
1027
1.21k
    new_cfg = apr_palloc(p, sizeof(*new_cfg));
1028
1.21k
    new_cfg->param = file;
1029
1.21k
    new_cfg->name = apr_pstrdup(p, name);
1030
1.21k
    new_cfg->getch = cfg_getch;
1031
1.21k
    new_cfg->getstr = cfg_getstr;
1032
1.21k
    new_cfg->close = cfg_close;
1033
1.21k
    new_cfg->line_number = 0;
1034
1.21k
    *ret_cfg = new_cfg;
1035
1.21k
    return APR_SUCCESS;
1036
1.21k
}
1037
1038
1039
/* Allocate a ap_configfile_t handle with user defined functions and params */
1040
AP_DECLARE(ap_configfile_t *) ap_pcfg_open_custom(
1041
            apr_pool_t *p, const char *descr, void *param,
1042
            apr_status_t (*getc_func) (char *ch, void *param),
1043
            apr_status_t (*gets_func) (void *buf, apr_size_t bufsize, void *param),
1044
            apr_status_t (*close_func) (void *param))
1045
0
{
1046
0
    ap_configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg));
1047
0
    new_cfg->param = param;
1048
0
    new_cfg->name = descr;
1049
0
    new_cfg->getch = getc_func;
1050
0
    new_cfg->getstr = gets_func;
1051
0
    new_cfg->close = close_func;
1052
0
    new_cfg->line_number = 0;
1053
0
    return new_cfg;
1054
0
}
1055
1056
/* Read one character from a configfile_t */
1057
AP_DECLARE(apr_status_t) ap_cfg_getc(char *ch, ap_configfile_t *cfp)
1058
0
{
1059
0
    apr_status_t rc = cfp->getch(ch, cfp->param);
1060
0
    if (rc == APR_SUCCESS && *ch == LF)
1061
0
        ++cfp->line_number;
1062
0
    return rc;
1063
0
}
1064
1065
AP_DECLARE(const char *) ap_pcfg_strerror(apr_pool_t *p, ap_configfile_t *cfp,
1066
                                          apr_status_t rc)
1067
0
{
1068
0
    if (rc == APR_SUCCESS)
1069
0
        return NULL;
1070
1071
0
    if (rc == APR_ENOSPC)
1072
0
        return apr_psprintf(p, "Error reading %s at line %d: Line too long",
1073
0
                            cfp->name, cfp->line_number);
1074
1075
0
    return apr_psprintf(p, "Error reading %s at line %d: %pm",
1076
0
                        cfp->name, cfp->line_number, &rc);
1077
0
}
1078
1079
/* Read one line from open ap_configfile_t, strip LF, increase line number */
1080
/* If custom handler does not define a getstr() function, read char by char */
1081
static apr_status_t ap_cfg_getline_core(char *buf, apr_size_t bufsize,
1082
                                        apr_size_t offset, ap_configfile_t *cfp)
1083
1.21k
{
1084
1.21k
    apr_status_t rc;
1085
    /* If a "get string" function is defined, use it */
1086
1.21k
    if (cfp->getstr != NULL) {
1087
1.10k
        char *cp;
1088
1.10k
        char *cbuf = buf + offset;
1089
1.10k
        apr_size_t cbufsize = bufsize - offset;
1090
1091
753k
        while (1) {
1092
753k
            ++cfp->line_number;
1093
753k
            rc = cfp->getstr(cbuf, cbufsize, cfp->param);
1094
753k
            if (rc == APR_EOF) {
1095
16
                if (cbuf != buf + offset) {
1096
12
                    *cbuf = '\0';
1097
12
                    break;
1098
12
                }
1099
4
                else {
1100
4
                    return APR_EOF;
1101
4
                }
1102
16
            }
1103
753k
            if (rc != APR_SUCCESS) {
1104
0
                return rc;
1105
0
            }
1106
1107
            /*
1108
             *  check for line continuation,
1109
             *  i.e. match [^\\]\\[\r]\n only
1110
             */
1111
753k
            cp = cbuf;
1112
753k
            cp += strlen(cp);
1113
753k
            if (cp > buf && cp[-1] == LF) {
1114
752k
                cp--;
1115
752k
                if (cp > buf && cp[-1] == CR)
1116
397
                    cp--;
1117
752k
                if (cp > buf && cp[-1] == '\\') {
1118
752k
                    cp--;
1119
                    /*
1120
                     * line continuation requested -
1121
                     * then remove backslash and continue
1122
                     */
1123
752k
                    cbufsize -= (cp-cbuf);
1124
752k
                    cbuf = cp;
1125
752k
                    continue;
1126
752k
                }
1127
752k
            }
1128
867
            else if (cp - buf >= bufsize - 1) {
1129
162
                return APR_ENOSPC;
1130
162
            }
1131
931
            break;
1132
753k
        }
1133
1.10k
    } else {
1134
        /* No "get string" function defined; read character by character */
1135
103
        apr_size_t i = offset;
1136
1137
103
        if (bufsize < 2) {
1138
            /* too small, assume caller is crazy */
1139
0
            return APR_EINVAL;
1140
0
        }
1141
103
        buf[offset] = '\0';
1142
1143
16.2k
        while (1) {
1144
16.2k
            char c;
1145
16.2k
            rc = cfp->getch(&c, cfp->param);
1146
16.2k
            if (rc == APR_EOF) {
1147
15
                if (i > offset)
1148
15
                    break;
1149
0
                else
1150
0
                    return APR_EOF;
1151
15
            }
1152
16.2k
            if (rc != APR_SUCCESS)
1153
0
                return rc;
1154
16.2k
            if (c == LF) {
1155
4.68k
                ++cfp->line_number;
1156
                /* check for line continuation */
1157
4.68k
                if (i > 0 && buf[i-1] == '\\') {
1158
4.64k
                    i--;
1159
4.64k
                    continue;
1160
4.64k
                }
1161
36
                else {
1162
36
                    break;
1163
36
                }
1164
4.68k
            }
1165
11.5k
            buf[i] = c;
1166
11.5k
            ++i;
1167
11.5k
            if (i >= bufsize - 1) {
1168
52
                return APR_ENOSPC;
1169
52
            }
1170
11.5k
        }
1171
51
        buf[i] = '\0';
1172
51
    }
1173
994
    return APR_SUCCESS;
1174
1.21k
}
1175
1176
static int cfg_trim_line(char *buf)
1177
994
{
1178
994
    char *start, *end;
1179
    /*
1180
     * Leading and trailing white space is eliminated completely
1181
     */
1182
994
    start = buf;
1183
2.15k
    while (apr_isspace(*start))
1184
1.16k
        ++start;
1185
    /* blast trailing whitespace */
1186
994
    end = ap_cstr_stripws(start);
1187
    /* Zap leading whitespace by shifting */
1188
994
    if (start != buf)
1189
265
        memmove(buf, start, end - start + 1);
1190
#ifdef DEBUG_CFG_LINES
1191
    ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, APLOGNO(00555) "Read config: '%s'", buf);
1192
#endif
1193
994
    return end - start;
1194
994
}
1195
1196
/* Read one line from open ap_configfile_t, strip LF, increase line number */
1197
/* If custom handler does not define a getstr() function, read char by char */
1198
AP_DECLARE(apr_status_t) ap_cfg_getline(char *buf, apr_size_t bufsize,
1199
                                        ap_configfile_t *cfp)
1200
1.21k
{
1201
1.21k
    apr_status_t rc = ap_cfg_getline_core(buf, bufsize, 0, cfp);
1202
1.21k
    if (rc == APR_SUCCESS)
1203
994
        cfg_trim_line(buf);
1204
1.21k
    return rc;
1205
1.21k
}
1206
1207
AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb,
1208
                                               ap_configfile_t *cfp,
1209
                                               apr_size_t max_len)
1210
0
{
1211
0
    apr_status_t rc;
1212
0
    apr_size_t new_len;
1213
0
    vb->strlen = 0;
1214
0
    *vb->buf = '\0';
1215
1216
0
    if (vb->strlen == AP_VARBUF_UNKNOWN)
1217
0
        vb->strlen = strlen(vb->buf);
1218
0
    if (vb->avail - vb->strlen < 3) {
1219
0
        new_len = vb->avail * 2;
1220
0
        if (new_len > max_len)
1221
0
            new_len = max_len;
1222
0
        else if (new_len < 3)
1223
0
            new_len = 3;
1224
0
        ap_varbuf_grow(vb, new_len);
1225
0
    }
1226
1227
0
    for (;;) {
1228
0
        rc = ap_cfg_getline_core(vb->buf, vb->avail, vb->strlen, cfp);
1229
0
        if (rc == APR_ENOSPC || rc == APR_SUCCESS)
1230
0
            vb->strlen += strlen(vb->buf + vb->strlen);
1231
0
        if (rc != APR_ENOSPC)
1232
0
            break;
1233
0
        if (vb->avail >= max_len)
1234
0
            return APR_ENOSPC;
1235
0
        new_len = vb->avail * 2;
1236
0
        if (new_len > max_len)
1237
0
            new_len = max_len;
1238
0
        ap_varbuf_grow(vb, new_len);
1239
0
        --cfp->line_number;
1240
0
    }
1241
0
    if (vb->strlen > max_len)
1242
0
        return APR_ENOSPC;
1243
0
    if (rc == APR_SUCCESS)
1244
0
        vb->strlen = cfg_trim_line(vb->buf);
1245
0
    return rc;
1246
0
}
1247
1248
/* Size an HTTP header field list item, as separated by a comma.
1249
 * The return value is a pointer to the beginning of the non-empty list item
1250
 * within the original string (or NULL if there is none) and the address
1251
 * of field is shifted to the next non-comma, non-whitespace character.
1252
 * len is the length of the item excluding any beginning whitespace.
1253
 */
1254
AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len)
1255
1.21k
{
1256
1.21k
    const unsigned char *ptr = (const unsigned char *)*field;
1257
1.21k
    const unsigned char *token;
1258
1.21k
    int in_qpair, in_qstr, in_com;
1259
1260
    /* Find first non-comma, non-whitespace byte */
1261
1262
2.94k
    while (*ptr == ',' || apr_isspace(*ptr))
1263
1.73k
        ++ptr;
1264
1265
1.21k
    token = ptr;
1266
1267
    /* Find the end of this item, skipping over dead bits */
1268
1269
1.21k
    for (in_qpair = in_qstr = in_com = 0;
1270
43.0k
         *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1271
41.8k
         ++ptr) {
1272
1273
41.8k
        if (in_qpair) {
1274
3.14k
            in_qpair = 0;
1275
3.14k
        }
1276
38.7k
        else {
1277
38.7k
            switch (*ptr) {
1278
3.17k
                case '\\': in_qpair = 1;      /* quoted-pair         */
1279
3.17k
                           break;
1280
956
                case '"' : if (!in_com)       /* quoted string delim */
1281
794
                               in_qstr = !in_qstr;
1282
956
                           break;
1283
1.23k
                case '(' : if (!in_qstr)      /* comment (may nest)  */
1284
1.07k
                               ++in_com;
1285
1.23k
                           break;
1286
529
                case ')' : if (in_com)        /* end comment         */
1287
201
                               --in_com;
1288
529
                           break;
1289
32.8k
                default  : break;
1290
38.7k
            }
1291
38.7k
        }
1292
41.8k
    }
1293
1294
1.21k
    if ((*len = (ptr - token)) == 0) {
1295
18
        *field = (const char *)ptr;
1296
18
        return NULL;
1297
18
    }
1298
1299
    /* Advance field pointer to the next non-comma, non-white byte */
1300
1301
2.13k
    while (*ptr == ',' || apr_isspace(*ptr))
1302
944
        ++ptr;
1303
1304
1.19k
    *field = (const char *)ptr;
1305
1.19k
    return (const char *)token;
1306
1.21k
}
1307
1308
/* Retrieve an HTTP header field list item, as separated by a comma,
1309
 * while stripping insignificant whitespace and lowercasing anything not in
1310
 * a quoted string or comment.  The return value is a new string containing
1311
 * the converted list item (or NULL if none) and the address pointed to by
1312
 * field is shifted to the next non-comma, non-whitespace.
1313
 */
1314
AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field)
1315
1.21k
{
1316
1.21k
    const char *tok_start;
1317
1.21k
    const unsigned char *ptr;
1318
1.21k
    unsigned char *pos;
1319
1.21k
    char *token;
1320
1.21k
    int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
1321
1322
    /* Find the beginning and maximum length of the list item so that
1323
     * we can allocate a buffer for the new string and reset the field.
1324
     */
1325
1.21k
    if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
1326
18
        return NULL;
1327
18
    }
1328
1.19k
    token = apr_palloc(p, tok_len + 1);
1329
1330
    /* Scan the token again, but this time copy only the good bytes.
1331
     * We skip extra whitespace and any whitespace around a '=', '/',
1332
     * or ';' and lowercase normal characters not within a comment,
1333
     * quoted-string or quoted-pair.
1334
     */
1335
1.19k
    for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
1336
43.0k
         *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1337
41.8k
         ++ptr) {
1338
1339
41.8k
        if (in_qpair) {
1340
3.14k
            in_qpair = 0;
1341
3.14k
            *pos++ = *ptr;
1342
3.14k
        }
1343
38.7k
        else {
1344
38.7k
            switch (*ptr) {
1345
3.17k
                case '\\': in_qpair = 1;
1346
3.17k
                           if (addspace == 1)
1347
88
                               *pos++ = ' ';
1348
3.17k
                           *pos++ = *ptr;
1349
3.17k
                           addspace = 0;
1350
3.17k
                           break;
1351
956
                case '"' : if (!in_com)
1352
794
                               in_qstr = !in_qstr;
1353
956
                           if (addspace == 1)
1354
90
                               *pos++ = ' ';
1355
956
                           *pos++ = *ptr;
1356
956
                           addspace = 0;
1357
956
                           break;
1358
1.23k
                case '(' : if (!in_qstr)
1359
1.07k
                               ++in_com;
1360
1.23k
                           if (addspace == 1)
1361
81
                               *pos++ = ' ';
1362
1.23k
                           *pos++ = *ptr;
1363
1.23k
                           addspace = 0;
1364
1.23k
                           break;
1365
529
                case ')' : if (in_com)
1366
201
                               --in_com;
1367
529
                           *pos++ = *ptr;
1368
529
                           addspace = 0;
1369
529
                           break;
1370
1.81k
                case ' ' :
1371
2.97k
                case '\t': if (addspace)
1372
1.43k
                               break;
1373
1.53k
                           if (in_com || in_qstr)
1374
740
                               *pos++ = *ptr;
1375
793
                           else
1376
793
                               addspace = 1;
1377
1.53k
                           break;
1378
417
                case '=' :
1379
1.02k
                case '/' :
1380
1.25k
                case ';' : if (!(in_com || in_qstr))
1381
778
                               addspace = -1;
1382
1.25k
                           *pos++ = *ptr;
1383
1.25k
                           break;
1384
28.6k
                default  : if (addspace == 1)
1385
449
                               *pos++ = ' ';
1386
28.6k
                           *pos++ = (in_com || in_qstr) ? *ptr
1387
28.6k
                                                        : apr_tolower(*ptr);
1388
28.6k
                           addspace = 0;
1389
28.6k
                           break;
1390
38.7k
            }
1391
38.7k
        }
1392
41.8k
    }
1393
1.19k
    *pos = '\0';
1394
1395
1.19k
    return token;
1396
1.19k
}
1397
1398
typedef enum ap_etag_e {
1399
    AP_ETAG_NONE,
1400
    AP_ETAG_WEAK,
1401
    AP_ETAG_STRONG
1402
} ap_etag_e;
1403
1404
/* Find an item in canonical form (lowercase, no extra spaces) within
1405
 * an HTTP field value list.  Returns 1 if found, 0 if not found.
1406
 * This would be much more efficient if we stored header fields as
1407
 * an array of list items as they are received instead of a plain string.
1408
 */
1409
static int find_list_item(apr_pool_t *p, const char *line,
1410
                                  const char *tok, ap_etag_e type)
1411
1.21k
{
1412
1.21k
    const unsigned char *pos;
1413
1.21k
    const unsigned char *ptr = (const unsigned char *)line;
1414
1.21k
    int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
1415
1416
1.21k
    if (!line || !tok) {
1417
0
        return 0;
1418
0
    }
1419
1.21k
    if (type == AP_ETAG_STRONG && *tok != '\"') {
1420
0
        return 0;
1421
0
    }
1422
1.21k
    if (type == AP_ETAG_WEAK) {
1423
0
        if (*tok == 'W' && (*(tok+1)) == '/' && (*(tok+2)) == '\"') {
1424
0
            tok += 2;
1425
0
        }
1426
0
        else if (*tok != '\"') {
1427
0
            return 0;
1428
0
        }
1429
0
    }
1430
1431
3.38k
    do {  /* loop for each item in line's list */
1432
1433
        /* Find first non-comma, non-whitespace byte */
1434
8.41k
        while (*ptr == ',' || apr_isspace(*ptr)) {
1435
5.03k
            ++ptr;
1436
5.03k
        }
1437
1438
        /* Account for strong or weak Etags, depending on our search */
1439
3.38k
        if (type == AP_ETAG_STRONG && *ptr != '\"') {
1440
0
            break;
1441
0
        }
1442
3.38k
        if (type == AP_ETAG_WEAK) {
1443
0
            if (*ptr == 'W' && (*(ptr+1)) == '/' && (*(ptr+2)) == '\"') {
1444
0
                ptr += 2;
1445
0
            }
1446
0
            else if (*ptr != '\"') {
1447
0
                break;
1448
0
            }
1449
0
        }
1450
1451
3.38k
        if (*ptr)
1452
3.32k
            good = 1;  /* until proven otherwise for this item */
1453
60
        else
1454
60
            break;     /* no items left and nothing good found */
1455
1456
        /* We skip extra whitespace and any whitespace around a '=', '/',
1457
         * or ';' and lowercase normal characters not within a comment,
1458
         * quoted-string or quoted-pair.
1459
         */
1460
3.32k
        for (pos = (const unsigned char *)tok;
1461
54.3k
             *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1462
50.9k
             ++ptr) {
1463
1464
50.9k
            if (in_qpair) {
1465
3.67k
                in_qpair = 0;
1466
3.67k
                if (good)
1467
0
                    good = (*pos++ == *ptr);
1468
3.67k
            }
1469
47.3k
            else {
1470
47.3k
                switch (*ptr) {
1471
3.71k
                    case '\\': in_qpair = 1;
1472
3.71k
                               if (addspace == 1)
1473
46
                                   good = good && (*pos++ == ' ');
1474
3.71k
                               good = good && (*pos++ == *ptr);
1475
3.71k
                               addspace = 0;
1476
3.71k
                               break;
1477
1.20k
                    case '"' : if (!in_com)
1478
1.03k
                                   in_qstr = !in_qstr;
1479
1.20k
                               if (addspace == 1)
1480
30
                                   good = good && (*pos++ == ' ');
1481
1.20k
                               good = good && (*pos++ == *ptr);
1482
1.20k
                               addspace = 0;
1483
1.20k
                               break;
1484
1.35k
                    case '(' : if (!in_qstr)
1485
1.18k
                                   ++in_com;
1486
1.35k
                               if (addspace == 1)
1487
25
                                   good = good && (*pos++ == ' ');
1488
1.35k
                               good = good && (*pos++ == *ptr);
1489
1.35k
                               addspace = 0;
1490
1.35k
                               break;
1491
779
                    case ')' : if (in_com)
1492
267
                                   --in_com;
1493
779
                               good = good && (*pos++ == *ptr);
1494
779
                               addspace = 0;
1495
779
                               break;
1496
2.21k
                    case ' ' :
1497
3.57k
                    case '\t': if (addspace || !good)
1498
3.38k
                                   break;
1499
192
                               if (in_com || in_qstr)
1500
0
                                   good = (*pos++ == *ptr);
1501
192
                               else
1502
192
                                   addspace = 1;
1503
192
                               break;
1504
510
                    case '=' :
1505
1.38k
                    case '/' :
1506
1.73k
                    case ';' : if (!(in_com || in_qstr))
1507
1.21k
                                   addspace = -1;
1508
1.73k
                               good = good && (*pos++ == *ptr);
1509
1.73k
                               break;
1510
34.9k
                    default  : if (!good)
1511
31.8k
                                   break;
1512
3.09k
                               if (addspace == 1)
1513
75
                                   good = (*pos++ == ' ');
1514
3.09k
                               if (in_com || in_qstr)
1515
0
                                   good = good && (*pos++ == *ptr);
1516
3.09k
                               else
1517
3.09k
                                   good = good
1518
3.02k
                                       && (apr_tolower(*pos++) == apr_tolower(*ptr));
1519
3.09k
                               addspace = 0;
1520
3.09k
                               break;
1521
47.3k
                }
1522
47.3k
            }
1523
50.9k
        }
1524
3.32k
        if (good && *pos)
1525
237
            good = 0;          /* not good if only a prefix was matched */
1526
1527
3.32k
    } while (*ptr && !good);
1528
1529
1.21k
    return good;
1530
1.21k
}
1531
1532
/* Find an item in canonical form (lowercase, no extra spaces) within
1533
 * an HTTP field value list.  Returns 1 if found, 0 if not found.
1534
 * This would be much more efficient if we stored header fields as
1535
 * an array of list items as they are received instead of a plain string.
1536
 */
1537
AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
1538
                                  const char *tok)
1539
1.21k
{
1540
1.21k
    return find_list_item(p, line, tok, AP_ETAG_NONE);
1541
1.21k
}
1542
1543
/* Find a strong Etag in canonical form (lowercase, no extra spaces) within
1544
 * an HTTP field value list.  Returns 1 if found, 0 if not found.
1545
 */
1546
AP_DECLARE(int) ap_find_etag_strong(apr_pool_t *p, const char *line,
1547
                                    const char *tok)
1548
0
{
1549
0
    return find_list_item(p, line, tok, AP_ETAG_STRONG);
1550
0
}
1551
1552
/* Find a weak ETag in canonical form (lowercase, no extra spaces) within
1553
 * an HTTP field value list.  Returns 1 if found, 0 if not found.
1554
 */
1555
AP_DECLARE(int) ap_find_etag_weak(apr_pool_t *p, const char *line,
1556
                                  const char *tok)
1557
0
{
1558
0
    return find_list_item(p, line, tok, AP_ETAG_WEAK);
1559
0
}
1560
1561
/* Grab a list of tokens of the format 1#token (from RFC7230) */
1562
AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p,
1563
                                                const char *str_in,
1564
                                                apr_array_header_t **tokens,
1565
                                                int skip_invalid)
1566
1.21k
{
1567
1.21k
    int in_leading_space = 1;
1568
1.21k
    int in_trailing_space = 0;
1569
1.21k
    int string_end = 0;
1570
1.21k
    const char *tok_begin;
1571
1.21k
    const char *cur;
1572
1573
1.21k
    if (!str_in) {
1574
0
        return NULL;
1575
0
    }
1576
1577
1.21k
    tok_begin = cur = str_in;
1578
1579
12.2k
    while (!string_end) {
1580
12.1k
        const unsigned char c = (unsigned char)*cur;
1581
1582
12.1k
        if (!TEST_CHAR(c, T_HTTP_TOKEN_STOP)) {
1583
            /* Non-separator character; we are finished with leading
1584
             * whitespace. We must never have encountered any trailing
1585
             * whitespace before the delimiter (comma) */
1586
8.27k
            in_leading_space = 0;
1587
8.27k
            if (in_trailing_space) {
1588
26
                return "Encountered illegal whitespace in token";
1589
26
            }
1590
8.27k
        }
1591
3.85k
        else if (c == ' ' || c == '\t') {
1592
            /* "Linear whitespace" only includes ASCII CRLF, space, and tab;
1593
             * we can't get a CRLF since headers are split on them already,
1594
             * so only look for a space or a tab */
1595
1.70k
            if (in_leading_space) {
1596
                /* We're still in leading whitespace */
1597
1.08k
                ++tok_begin;
1598
1.08k
            }
1599
618
            else {
1600
                /* We must be in trailing whitespace */
1601
618
                ++in_trailing_space;
1602
618
            }
1603
1.70k
        }
1604
2.15k
        else if (c == ',' || c == '\0') {
1605
1.12k
            if (!in_leading_space) {
1606
                /* If we're out of the leading space, we know we've read some
1607
                 * characters of a token */
1608
669
                if (*tokens == NULL) {
1609
201
                    *tokens = apr_array_make(p, 4, sizeof(char *));
1610
201
                }
1611
669
                APR_ARRAY_PUSH(*tokens, char *) =
1612
669
                    apr_pstrmemdup((*tokens)->pool, tok_begin,
1613
669
                                   (cur - tok_begin) - in_trailing_space);
1614
669
            }
1615
            /* We're allowed to have null elements, just don't add them to the
1616
             * array */
1617
1618
1.12k
            tok_begin = cur + 1;
1619
1.12k
            in_leading_space = 1;
1620
1.12k
            in_trailing_space = 0;
1621
1.12k
            string_end = (c == '\0');
1622
1.12k
        }
1623
1.03k
        else {
1624
            /* Encountered illegal separator char */
1625
1.03k
            if (skip_invalid) {
1626
                /* Skip to the next separator */
1627
0
                const char *temp;
1628
0
                temp = ap_strchr_c(cur, ',');
1629
0
                if(!temp) {
1630
0
                    temp = ap_strchr_c(cur, '\0');
1631
0
                }
1632
1633
                /* Act like we haven't seen a token so we reset */
1634
0
                cur = temp - 1;
1635
0
                in_leading_space = 1;
1636
0
                in_trailing_space = 0;
1637
0
            }
1638
1.03k
            else {
1639
1.03k
                return apr_psprintf(p, "Encountered illegal separator "
1640
1.03k
                                    "'\\x%.2x'", (unsigned int)c);
1641
1.03k
            }
1642
1.03k
        }
1643
1644
11.0k
        ++cur;
1645
11.0k
    }
1646
1647
149
    return NULL;
1648
1.21k
}
1649
1650
/* Scan a string for HTTP VCHAR/obs-text characters including HT and SP
1651
 * (as used in header values, for example, in RFC 7230 section 3.2)
1652
 * returning the pointer to the first non-HT ASCII ctrl character.
1653
 */
1654
AP_DECLARE(const char *) ap_scan_http_field_content(const char *ptr)
1655
0
{
1656
0
    for ( ; !TEST_CHAR(*ptr, T_HTTP_CTRLS); ++ptr) ;
1657
1658
0
    return ptr;
1659
0
}
1660
1661
/* Scan a string for HTTP token characters, returning the pointer to
1662
 * the first non-token character.
1663
 */
1664
AP_DECLARE(const char *) ap_scan_http_token(const char *ptr)
1665
489
{
1666
3.67k
    for ( ; !TEST_CHAR(*ptr, T_HTTP_TOKEN_STOP); ++ptr) ;
1667
1668
489
    return ptr;
1669
489
}
1670
1671
/* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+)
1672
 * and return a pointer to the first ctrl/space character encountered.
1673
 */
1674
AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr)
1675
903
{
1676
17.0k
    for ( ; TEST_CHAR(*ptr, T_VCHAR_OBSTEXT); ++ptr) ;
1677
1678
903
    return ptr;
1679
903
}
1680
1681
/* Retrieve a token, spacing over it and returning a pointer to
1682
 * the first non-white byte afterwards.  Note that these tokens
1683
 * are delimited by semis and commas; and can also be delimited
1684
 * by whitespace at the caller's option.
1685
 */
1686
1687
AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line,
1688
                                int accept_white)
1689
1.21k
{
1690
1.21k
    const char *ptr = *accept_line;
1691
1.21k
    const char *tok_start;
1692
1.21k
    char *token;
1693
1694
    /* Find first non-white byte */
1695
1696
2.75k
    while (apr_isspace(*ptr))
1697
1.54k
        ++ptr;
1698
1699
1.21k
    tok_start = ptr;
1700
1701
    /* find token end, skipping over quoted strings.
1702
     * (comments are already gone).
1703
     */
1704
1705
35.5k
    while (*ptr && (accept_white || !apr_isspace(*ptr))
1706
34.6k
           && *ptr != ';' && *ptr != ',') {
1707
34.2k
        if (*ptr++ == '"')
1708
5.29k
            while (*ptr)
1709
5.15k
                if (*ptr++ == '"')
1710
451
                    break;
1711
34.2k
    }
1712
1713
1.21k
    token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
1714
1715
    /* Advance accept_line pointer to the next non-white byte */
1716
1717
1.21k
    while (apr_isspace(*ptr))
1718
0
        ++ptr;
1719
1720
1.21k
    *accept_line = ptr;
1721
1.21k
    return token;
1722
1.21k
}
1723
1724
1725
/* find http tokens, see the definition of token from RFC2068 */
1726
AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1727
1.21k
{
1728
1.21k
    const unsigned char *start_token;
1729
1.21k
    const unsigned char *s;
1730
1731
1.21k
    if (!line)
1732
0
        return 0;
1733
1734
1.21k
    s = (const unsigned char *)line;
1735
5.19k
    for (;;) {
1736
        /* find start of token, skip all stop characters */
1737
38.5k
        while (*s && TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1738
33.3k
            ++s;
1739
33.3k
        }
1740
5.19k
        if (!*s) {
1741
721
            return 0;
1742
721
        }
1743
4.47k
        start_token = s;
1744
        /* find end of the token */
1745
22.7k
        while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1746
18.2k
            ++s;
1747
18.2k
        }
1748
4.47k
        if (!ap_cstr_casecmpn((const char *)start_token, (const char *)tok,
1749
4.47k
                         s - start_token)) {
1750
114
            return 1;
1751
114
        }
1752
4.35k
        if (!*s) {
1753
377
            return 0;
1754
377
        }
1755
4.35k
    }
1756
1.21k
}
1757
1758
static const char *find_last_token(apr_pool_t *p, const char *line,
1759
                            const char *tok)
1760
2.41k
{
1761
2.41k
    int llen, tlen, lidx;
1762
1763
2.41k
    if (!line)
1764
0
        return NULL;
1765
1766
2.41k
    llen = strlen(line);
1767
2.41k
    tlen = strlen(tok);
1768
2.41k
    lidx = llen - tlen;
1769
1770
2.41k
    if (lidx < 0 ||
1771
2.25k
        (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1772
1.95k
        return NULL;
1773
1774
456
    if (ap_cstr_casecmpn(&line[lidx], tok, tlen) == 0) { 
1775
23
        return &line[lidx];
1776
23
    }
1777
433
   return NULL;
1778
456
}
1779
1780
AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
1781
                                   const char *tok)
1782
1.21k
{
1783
1.21k
    return find_last_token(p, line, tok) != NULL;
1784
1.21k
}
1785
1786
AP_DECLARE(int) ap_is_chunked(apr_pool_t *p, const char *line)
1787
1.21k
{
1788
1.21k
    const char *s;
1789
1790
1.21k
    if (!line) 
1791
0
        return 0;
1792
1.21k
    if (!ap_cstr_casecmp(line, "chunked")) { 
1793
10
        return 1;
1794
10
    }
1795
1796
1.20k
    s = find_last_token(p, line, "chunked");
1797
1798
1.20k
    if (!s) return 0;
1799
 
1800
    /* eat spaces right-to-left to see what precedes "chunked" */
1801
258
    while (--s > line) { 
1802
257
        if (*s != ' ') break;
1803
257
    }
1804
1805
    /* found delim, or leading ws (input wasn't parsed by httpd as a header) */
1806
22
    if (*s == ',' || *s == ' ') { 
1807
2
        return 1;
1808
2
    }
1809
20
    return 0;
1810
22
}
1811
1812
AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1813
1.21k
{
1814
1.21k
    char *cmd;
1815
1.21k
    unsigned char *d;
1816
1.21k
    const unsigned char *s;
1817
1.21k
    apr_size_t len = strlen(str);
1818
1819
1.21k
    ap_assert(len <= (APR_SIZE_MAX - 1) / 2);
1820
1.21k
    cmd = apr_palloc(p, 2 * len + 1);
1821
1.21k
    d = (unsigned char *)cmd;
1822
1.21k
    s = (const unsigned char *)str;
1823
57.2k
    for (; *s; ++s) {
1824
1825
#if defined(OS2) || defined(WIN32)
1826
        /*
1827
         * Newlines to Win32/OS2 CreateProcess() are ill advised.
1828
         * Convert them to spaces since they are effectively white
1829
         * space to most applications
1830
         */
1831
        if (*s == '\r' || *s == '\n') {
1832
             *d++ = ' ';
1833
             continue;
1834
         }
1835
#endif
1836
1837
56.0k
        if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1838
16.3k
            *d++ = '\\';
1839
16.3k
        }
1840
56.0k
        *d++ = *s;
1841
56.0k
    }
1842
1.21k
    *d = '\0';
1843
1844
1.21k
    return cmd;
1845
1.21k
}
1846
1847
static char x2c(const char *what)
1848
476
{
1849
476
    char digit;
1850
1851
476
#if !APR_CHARSET_EBCDIC
1852
476
    digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
1853
476
             : (what[0] - '0'));
1854
476
    digit *= 16;
1855
476
    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
1856
476
              : (what[1] - '0'));
1857
#else /*APR_CHARSET_EBCDIC*/
1858
    char xstr[5];
1859
    xstr[0]='0';
1860
    xstr[1]='x';
1861
    xstr[2]=what[0];
1862
    xstr[3]=what[1];
1863
    xstr[4]='\0';
1864
    digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
1865
                                0xFF & strtol(xstr, NULL, 16));
1866
#endif /*APR_CHARSET_EBCDIC*/
1867
476
    return (digit);
1868
476
}
1869
1870
/*
1871
 * Unescapes a URL, leaving reserved characters intact.
1872
 * Returns 0 on success, non-zero on error
1873
 * Failure is due to
1874
 *   bad % escape       returns HTTP_BAD_REQUEST
1875
 *
1876
 *   decoding %00 or a forbidden character returns HTTP_NOT_FOUND
1877
 */
1878
1879
static int unescape_url(char *url, const char *forbid, const char *reserved,
1880
                        unsigned int flags)
1881
561
{
1882
561
    const int keep_slashes = (flags & AP_UNESCAPE_URL_KEEP_SLASHES) != 0,
1883
561
              forbid_slashes = (flags & AP_UNESCAPE_URL_FORBID_SLASHES) != 0,
1884
561
              keep_unreserved = (flags & AP_UNESCAPE_URL_KEEP_UNRESERVED) != 0;
1885
561
    int badesc, badpath;
1886
561
    char *x, *y;
1887
1888
561
    badesc = 0;
1889
561
    badpath = 0;
1890
1891
561
    if (url == NULL) {
1892
0
        return OK;
1893
0
    }
1894
    /* Initial scan for first '%'. Don't bother writing values before
1895
     * seeing a '%' */
1896
561
    y = strchr(url, '%');
1897
561
    if (y == NULL) {
1898
442
        return OK;
1899
442
    }
1900
4.56k
    for (x = y; *y; ++x, ++y) {
1901
4.44k
        if (*y != '%') {
1902
3.06k
            *x = *y;
1903
3.06k
        }
1904
1.38k
        else {
1905
1.38k
            if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1906
905
                badesc = 1;
1907
905
                *x = '%';
1908
905
            }
1909
476
            else {
1910
476
                char decoded;
1911
476
                decoded = x2c(y + 1);
1912
476
                if ((decoded == '\0')
1913
372
                    || (forbid_slashes && AP_IS_SLASH(decoded))
1914
372
                    || (forbid && ap_strchr_c(forbid, decoded))) {
1915
186
                    badpath = 1;
1916
186
                    *x = decoded;
1917
186
                    y += 2;
1918
186
                }
1919
290
                else if ((keep_unreserved && TEST_CHAR(decoded,
1920
290
                                                       T_URI_UNRESERVED))
1921
290
                         || (keep_slashes && AP_IS_SLASH(decoded))
1922
290
                         || (reserved && ap_strchr_c(reserved, decoded))) {
1923
0
                    *x++ = *y++;
1924
0
                    *x++ = *y++;
1925
0
                    *x = *y;
1926
0
                }
1927
290
                else {
1928
290
                    *x = decoded;
1929
290
                    y += 2;
1930
290
                }
1931
476
            }
1932
1.38k
        }
1933
4.44k
    }
1934
119
    *x = '\0';
1935
119
    if (badesc) {
1936
103
        return HTTP_BAD_REQUEST;
1937
103
    }
1938
16
    else if (badpath) {
1939
6
        return HTTP_NOT_FOUND;
1940
6
    }
1941
10
    else {
1942
10
        return OK;
1943
10
    }
1944
119
}
1945
AP_DECLARE(int) ap_unescape_url(char *url)
1946
301
{
1947
    /* Traditional */
1948
301
    return unescape_url(url, AP_SLASHES, NULL, 0);
1949
301
}
1950
AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
1951
0
{
1952
    /* AllowEncodedSlashes (corrected) */
1953
0
    if (decode_slashes) {
1954
        /* no chars reserved */
1955
0
        return unescape_url(url, NULL, NULL, 0);
1956
0
    } else {
1957
        /* reserve (do not decode) encoded slashes */
1958
0
        return unescape_url(url, NULL, AP_SLASHES, 0);
1959
0
    }
1960
0
}
1961
AP_DECLARE(int) ap_unescape_url_ex(char *url, unsigned int flags)
1962
0
{
1963
0
    return unescape_url(url, NULL, NULL, flags);
1964
0
}
1965
1966
#ifdef NEW_APIS
1967
/* IFDEF these out until they've been thought through.
1968
 * Just a germ of an API extension for now
1969
 */
1970
AP_DECLARE(int) ap_unescape_url_proxy(char *url)
1971
{
1972
    /* leave RFC1738 reserved characters intact, * so proxied URLs
1973
     * don't get mangled.  Where does that leave encoded '&' ?
1974
     */
1975
    return unescape_url(url, NULL, "/;?", 0);
1976
}
1977
AP_DECLARE(int) ap_unescape_url_reserved(char *url, const char *reserved)
1978
{
1979
    return unescape_url(url, NULL, reserved);
1980
}
1981
#endif
1982
1983
AP_DECLARE(int) ap_unescape_urlencoded(char *query)
1984
260
{
1985
260
    char *slider;
1986
1987
    /* replace plus with a space */
1988
260
    if (query) {
1989
10.9k
        for (slider = query; *slider; slider++) {
1990
10.7k
            if (*slider == '+') {
1991
138
                *slider = ' ';
1992
138
            }
1993
10.7k
        }
1994
260
    }
1995
1996
    /* unescape everything else */
1997
260
    return unescape_url(query, NULL, NULL, 0);
1998
260
}
1999
2000
AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
2001
                                       apr_port_t port, const request_rec *r)
2002
0
{
2003
0
    if (ap_is_default_port(port, r)) {
2004
0
        return apr_pstrdup(p, hostname);
2005
0
    }
2006
0
    else {
2007
0
        return apr_psprintf(p, "%s:%u", hostname, port);
2008
0
    }
2009
0
}
2010
2011
AP_DECLARE(int) ap_unescape_all(char *url)
2012
0
{
2013
0
    return unescape_url(url, NULL, NULL, 0);
2014
0
}
2015
2016
/* c2x takes an unsigned, and expects the caller has guaranteed that
2017
 * 0 <= what < 256... which usually means that you have to cast to
2018
 * unsigned char first, because (unsigned)(char)(x) first goes through
2019
 * signed extension to an int before the unsigned cast.
2020
 *
2021
 * The reason for this assumption is to assist gcc code generation --
2022
 * the unsigned char -> unsigned extension is already done earlier in
2023
 * both uses of this code, so there's no need to waste time doing it
2024
 * again.
2025
 */
2026
static const char c2x_table[] = "0123456789abcdef";
2027
2028
static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
2029
                                     unsigned char *where)
2030
118k
{
2031
#if APR_CHARSET_EBCDIC
2032
    what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
2033
#endif /*APR_CHARSET_EBCDIC*/
2034
118k
    *where++ = prefix;
2035
118k
    *where++ = c2x_table[what >> 4];
2036
118k
    *where++ = c2x_table[what & 0xf];
2037
118k
    return where;
2038
118k
}
2039
2040
/*
2041
 * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
2042
 * routine is (should be) OS independent.
2043
 *
2044
 * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
2045
 * cases if a ':' occurs before the first '/' in the URL, the URL should be
2046
 * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
2047
 * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
2048
 * efficiency reasons, we don't use escape_path_segment(), which is provided for
2049
 * reference. Again, RFC 1808 is where this stuff is defined.
2050
 *
2051
 * If partial is set, os_escape_path() assumes that the path will be appended to
2052
 * something with a '/' in it (and thus does not prefix "./").
2053
 */
2054
2055
AP_DECLARE(char *) ap_escape_path_segment_buffer(char *copy, const char *segment)
2056
1.21k
{
2057
1.21k
    const unsigned char *s = (const unsigned char *)segment;
2058
1.21k
    unsigned char *d = (unsigned char *)copy;
2059
1.21k
    unsigned c;
2060
2061
57.2k
    while ((c = *s)) {
2062
56.0k
        if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
2063
30.6k
            d = c2x(c, '%', d);
2064
30.6k
        }
2065
25.3k
        else {
2066
25.3k
            *d++ = c;
2067
25.3k
        }
2068
56.0k
        ++s;
2069
56.0k
    }
2070
1.21k
    *d = '\0';
2071
1.21k
    return copy;
2072
1.21k
}
2073
2074
AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
2075
0
{
2076
0
    apr_size_t len = strlen(segment);
2077
0
    ap_assert(len <= (APR_SIZE_MAX - 1) / 3);
2078
0
    return ap_escape_path_segment_buffer(apr_palloc(p, 3 * len + 1), segment);
2079
0
}
2080
2081
AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
2082
1.21k
{
2083
    /* Allocate +3 for potential "./" and trailing NULL.
2084
     * Allocate another +1 to allow the caller to add a trailing '/' (see
2085
     * comment in 'ap_sub_req_lookup_dirent')
2086
     */
2087
1.21k
    apr_size_t len = strlen(path);
2088
1.21k
    char *copy;
2089
1.21k
    const unsigned char *s;
2090
1.21k
    unsigned char *d;
2091
1.21k
    unsigned c;
2092
2093
1.21k
    ap_assert(len <= (APR_SIZE_MAX - 4) / 3);
2094
1.21k
    copy = apr_palloc(p, 3 * len + 3 + 1);
2095
1.21k
    s = (const unsigned char *)path;
2096
1.21k
    d = (unsigned char *)copy;
2097
2098
1.21k
    if (!partial) {
2099
1.21k
        const char *colon = ap_strchr_c(path, ':');
2100
1.21k
        const char *slash = ap_strchr_c(path, '/');
2101
2102
1.21k
        if (colon && (!slash || colon < slash)) {
2103
53
            *d++ = '.';
2104
53
            *d++ = '/';
2105
53
        }
2106
1.21k
    }
2107
57.2k
    while ((c = *s)) {
2108
56.0k
        if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
2109
29.4k
            d = c2x(c, '%', d);
2110
29.4k
        }
2111
26.5k
        else {
2112
26.5k
            *d++ = c;
2113
26.5k
        }
2114
56.0k
        ++s;
2115
56.0k
    }
2116
1.21k
    *d = '\0';
2117
1.21k
    return copy;
2118
1.21k
}
2119
2120
AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer)
2121
1.21k
{
2122
1.21k
    const unsigned char *s = (const unsigned char *)buffer;
2123
1.21k
    unsigned char *d = (unsigned char *)copy;
2124
1.21k
    unsigned c;
2125
2126
57.2k
    while ((c = *s)) {
2127
56.0k
        if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
2128
35.0k
            d = c2x(c, '%', d);
2129
35.0k
        }
2130
21.0k
        else if (c == ' ') {
2131
2.93k
            *d++ = '+';
2132
2.93k
        }
2133
18.0k
        else {
2134
18.0k
            *d++ = c;
2135
18.0k
        }
2136
56.0k
        ++s;
2137
56.0k
    }
2138
1.21k
    *d = '\0';
2139
1.21k
    return copy;
2140
1.21k
}
2141
2142
AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
2143
1.21k
{
2144
1.21k
    apr_size_t len = strlen(buffer);
2145
1.21k
    ap_assert(len <= (APR_SIZE_MAX - 1) / 3);
2146
1.21k
    return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * len + 1), buffer);
2147
1.21k
}
2148
2149
/* ap_escape_uri is now a macro for os_escape_path */
2150
2151
AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
2152
1.21k
{
2153
1.21k
    apr_size_t i, j;
2154
1.21k
    char *x;
2155
2156
    /* first, count the number of extra characters */
2157
57.2k
    for (i = 0, j = 0; s[i] != '\0'; i++) {
2158
56.0k
        if (i + j > APR_SIZE_MAX - 6) {
2159
0
            abort();
2160
0
        }
2161
56.0k
        if (s[i] == '<' || s[i] == '>')
2162
536
            j += 3;
2163
55.4k
        else if (s[i] == '&')
2164
226
            j += 4;
2165
55.2k
        else if (s[i] == '"')
2166
1.48k
            j += 5;
2167
53.7k
        else if (toasc && !apr_isascii(s[i]))
2168
0
            j += 5;
2169
56.0k
    }
2170
2171
1.21k
    if (j == 0)
2172
835
        return apr_pstrmemdup(p, s, i);
2173
2174
377
    x = apr_palloc(p, i + j + 1);
2175
22.0k
    for (i = 0, j = 0; s[i] != '\0'; i++, j++)
2176
21.6k
        if (s[i] == '<') {
2177
248
            memcpy(&x[j], "&lt;", 4);
2178
248
            j += 3;
2179
248
        }
2180
21.3k
        else if (s[i] == '>') {
2181
288
            memcpy(&x[j], "&gt;", 4);
2182
288
            j += 3;
2183
288
        }
2184
21.1k
        else if (s[i] == '&') {
2185
226
            memcpy(&x[j], "&amp;", 5);
2186
226
            j += 4;
2187
226
        }
2188
20.8k
        else if (s[i] == '"') {
2189
1.48k
            memcpy(&x[j], "&quot;", 6);
2190
1.48k
            j += 5;
2191
1.48k
        }
2192
19.3k
        else if (toasc && !apr_isascii(s[i])) {
2193
0
            char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]);
2194
0
            memcpy(&x[j], esc, 6);
2195
0
            j += 5;
2196
0
        }
2197
19.3k
        else
2198
19.3k
            x[j] = s[i];
2199
2200
377
    x[j] = '\0';
2201
377
    return x;
2202
1.21k
}
2203
AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
2204
1.21k
{
2205
1.21k
    char *ret;
2206
1.21k
    unsigned char *d;
2207
1.21k
    const unsigned char *s;
2208
1.21k
    apr_size_t length, escapes = 0;
2209
2210
1.21k
    if (!str) {
2211
0
        return NULL;
2212
0
    }
2213
2214
    /* Compute how many characters need to be escaped */
2215
1.21k
    s = (const unsigned char *)str;
2216
57.2k
    for (; *s; ++s) {
2217
56.0k
        if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2218
24.5k
            escapes++;
2219
24.5k
        }
2220
56.0k
    }
2221
    
2222
    /* Compute the length of the input string, including NULL */
2223
1.21k
    length = s - (const unsigned char *)str + 1;
2224
    
2225
    /* Fast path: nothing to escape */
2226
1.21k
    if (escapes == 0) {
2227
165
        return apr_pmemdup(p, str, length);
2228
165
    }
2229
    
2230
    /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
2231
1.04k
    ret = apr_palloc(p, length + 3 * escapes);
2232
1.04k
    d = (unsigned char *)ret;
2233
1.04k
    s = (const unsigned char *)str;
2234
53.3k
    for (; *s; ++s) {
2235
52.3k
        if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2236
24.5k
            *d++ = '\\';
2237
24.5k
            switch(*s) {
2238
209
            case '\b':
2239
209
                *d++ = 'b';
2240
209
                break;
2241
2.93k
            case '\n':
2242
2.93k
                *d++ = 'n';
2243
2.93k
                break;
2244
603
            case '\r':
2245
603
                *d++ = 'r';
2246
603
                break;
2247
2.11k
            case '\t':
2248
2.11k
                *d++ = 't';
2249
2.11k
                break;
2250
415
            case '\v':
2251
415
                *d++ = 'v';
2252
415
                break;
2253
5.31k
            case '\\':
2254
6.79k
            case '"':
2255
6.79k
                *d++ = *s;
2256
6.79k
                break;
2257
11.4k
            default:
2258
11.4k
                c2x(*s, 'x', d);
2259
11.4k
                d += 3;
2260
24.5k
            }
2261
24.5k
        }
2262
27.7k
        else {
2263
27.7k
            *d++ = *s;
2264
27.7k
        }
2265
52.3k
    }
2266
1.04k
    *d = '\0';
2267
2268
1.04k
    return ret;
2269
1.04k
}
2270
2271
AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
2272
                                               apr_size_t buflen)
2273
1.21k
{
2274
1.21k
    unsigned char *d, *ep;
2275
1.21k
    const unsigned char *s;
2276
2277
1.21k
    if (!source || !buflen) { /* be safe */
2278
0
        return 0;
2279
0
    }
2280
2281
1.21k
    d = (unsigned char *)dest;
2282
1.21k
    s = (const unsigned char *)source;
2283
1.21k
    ep = d + buflen - 1;
2284
2285
57.2k
    for (; d < ep && *s; ++s) {
2286
2287
56.0k
        if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2288
24.5k
            *d++ = '\\';
2289
24.5k
            if (d >= ep) {
2290
0
                --d;
2291
0
                break;
2292
0
            }
2293
2294
24.5k
            switch(*s) {
2295
209
            case '\b':
2296
209
                *d++ = 'b';
2297
209
                break;
2298
2.93k
            case '\n':
2299
2.93k
                *d++ = 'n';
2300
2.93k
                break;
2301
603
            case '\r':
2302
603
                *d++ = 'r';
2303
603
                break;
2304
2.11k
            case '\t':
2305
2.11k
                *d++ = 't';
2306
2.11k
                break;
2307
415
            case '\v':
2308
415
                *d++ = 'v';
2309
415
                break;
2310
5.31k
            case '\\':
2311
5.31k
                *d++ = *s;
2312
5.31k
                break;
2313
1.48k
            case '"': /* no need for this in error log */
2314
1.48k
                d[-1] = *s;
2315
1.48k
                break;
2316
11.4k
            default:
2317
11.4k
                if (d >= ep - 2) {
2318
0
                    ep = --d; /* break the for loop as well */
2319
0
                    break;
2320
0
                }
2321
11.4k
                c2x(*s, 'x', d);
2322
11.4k
                d += 3;
2323
24.5k
            }
2324
24.5k
        }
2325
31.4k
        else {
2326
31.4k
            *d++ = *s;
2327
31.4k
        }
2328
56.0k
    }
2329
1.21k
    *d = '\0';
2330
2331
1.21k
    return (d - (unsigned char *)dest);
2332
1.21k
}
2333
2334
AP_DECLARE(void) ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
2335
0
{
2336
0
    const unsigned char *in = src;
2337
0
    apr_size_t i;
2338
2339
0
    for (i = 0; i < srclen; i++) {
2340
0
        *dest++ = c2x_table[in[i] >> 4];
2341
0
        *dest++ = c2x_table[in[i] & 0xf];
2342
0
    }
2343
0
    *dest = '\0';
2344
0
}
2345
2346
AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
2347
0
{
2348
0
    apr_finfo_t finfo;
2349
2350
0
    if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS)
2351
0
        return 0;                /* in error condition, just return no */
2352
2353
0
    return (finfo.filetype == APR_DIR);
2354
0
}
2355
2356
AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path)
2357
0
{
2358
0
    apr_finfo_t finfo;
2359
2360
0
    if (apr_stat(&finfo, path, APR_FINFO_LINK | APR_FINFO_TYPE, p) != APR_SUCCESS)
2361
0
        return 0;                /* in error condition, just return no */
2362
2363
0
    return (finfo.filetype == APR_DIR);
2364
0
}
2365
2366
AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
2367
                                  const char *src2)
2368
0
{
2369
0
    apr_size_t len1, len2;
2370
0
    char *path;
2371
2372
0
    len1 = strlen(src1);
2373
0
    len2 = strlen(src2);
2374
     /* allocate +3 for '/' delimiter, trailing NULL and overallocate
2375
      * one extra byte to allow the caller to add a trailing '/'
2376
      */
2377
0
    path = (char *)apr_palloc(a, len1 + len2 + 3);
2378
0
    if (len1 == 0) {
2379
0
        *path = '/';
2380
0
        memcpy(path + 1, src2, len2 + 1);
2381
0
    }
2382
0
    else {
2383
0
        char *next;
2384
0
        memcpy(path, src1, len1);
2385
0
        next = path + len1;
2386
0
        if (next[-1] != '/') {
2387
0
            *next++ = '/';
2388
0
        }
2389
0
        memcpy(next, src2, len2 + 1);
2390
0
    }
2391
0
    return path;
2392
0
}
2393
2394
/*
2395
 * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
2396
 */
2397
AP_DECLARE(int) ap_is_url(const char *u)
2398
0
{
2399
0
    int x;
2400
2401
0
    for (x = 0; u[x] != ':'; x++) {
2402
0
        if ((!u[x]) ||
2403
0
            ((!apr_isalnum(u[x])) &&
2404
0
             (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
2405
0
            return 0;
2406
0
        }
2407
0
    }
2408
2409
0
    return (x ? 1 : 0);                /* If the first character is ':', it's broken, too */
2410
0
}
2411
2412
AP_DECLARE(int) ap_ind(const char *s, char c)
2413
0
{
2414
0
    const char *p = ap_strchr_c(s, c);
2415
2416
0
    if (p == NULL)
2417
0
        return -1;
2418
0
    return p - s;
2419
0
}
2420
2421
AP_DECLARE(int) ap_rind(const char *s, char c)
2422
0
{
2423
0
    const char *p = ap_strrchr_c(s, c);
2424
2425
0
    if (p == NULL)
2426
0
        return -1;
2427
0
    return p - s;
2428
0
}
2429
2430
AP_DECLARE(void) ap_str_tolower(char *str)
2431
225
{
2432
8.57k
    while (*str) {
2433
8.34k
        *str = apr_tolower(*str);
2434
8.34k
        ++str;
2435
8.34k
    }
2436
225
}
2437
2438
AP_DECLARE(void) ap_str_toupper(char *str)
2439
0
{
2440
0
    while (*str) {
2441
0
        *str = apr_toupper(*str);
2442
0
        ++str;
2443
0
    }
2444
0
}
2445
2446
/*
2447
 * We must return a FQDN
2448
 */
2449
char *ap_get_local_host(apr_pool_t *a)
2450
0
{
2451
0
#ifndef MAXHOSTNAMELEN
2452
0
#define MAXHOSTNAMELEN 256
2453
0
#endif
2454
0
    char str[MAXHOSTNAMELEN + 1];
2455
0
    char *server_hostname = NULL;
2456
0
    apr_sockaddr_t *sockaddr;
2457
0
    char *hostname;
2458
2459
0
    if (apr_gethostname(str, sizeof(str) - 1, a) != APR_SUCCESS) {
2460
0
        ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00556)
2461
0
                     "%s: apr_gethostname() failed to determine ServerName",
2462
0
                     ap_server_argv0);
2463
0
    } else {
2464
0
        str[sizeof(str) - 1] = '\0';
2465
0
        if (apr_sockaddr_info_get(&sockaddr, str, APR_UNSPEC, 0, 0, a) == APR_SUCCESS) {
2466
0
            if ( (apr_getnameinfo(&hostname, sockaddr, 0) == APR_SUCCESS) &&
2467
0
                (ap_strchr_c(hostname, '.')) ) {
2468
0
                server_hostname = apr_pstrdup(a, hostname);
2469
0
                return server_hostname;
2470
0
            } else if (ap_strchr_c(str, '.')) {
2471
0
                server_hostname = apr_pstrdup(a, str);
2472
0
            } else {
2473
0
                apr_sockaddr_ip_get(&hostname, sockaddr);
2474
0
                server_hostname = apr_pstrdup(a, hostname);
2475
0
            }
2476
0
        } else {
2477
0
            ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00557)
2478
0
                         "%s: apr_sockaddr_info_get() failed for %s",
2479
0
                         ap_server_argv0, str);
2480
0
        }
2481
0
    }
2482
2483
0
    if (!server_hostname)
2484
0
        server_hostname = apr_pstrdup(a, "127.0.0.1");
2485
2486
0
    ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, a, APLOGNO(00558)
2487
0
                 "%s: Could not reliably determine the server's fully qualified "
2488
0
                 "domain name, using %s. Set the 'ServerName' directive globally "
2489
0
                 "to suppress this message",
2490
0
                 ap_server_argv0, server_hostname);
2491
2492
0
    return server_hostname;
2493
0
}
2494
2495
/* simple 'pool' alloc()ing glue to apr_base64.c
2496
 */
2497
AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
2498
1.21k
{
2499
1.21k
    char *decoded;
2500
2501
1.21k
    decoded = (char *) apr_palloc(p, apr_base64_decode_len(bufcoded));
2502
1.21k
    apr_base64_decode(decoded, bufcoded);
2503
2504
1.21k
    return decoded;
2505
1.21k
}
2506
2507
/* a stringent version of ap_pbase64decode() */
2508
AP_DECLARE(apr_status_t) ap_pbase64decode_strict(apr_pool_t *p,
2509
                                                 const char *encoded,
2510
                                                 char **decoded,
2511
                                                 apr_size_t *len)
2512
207
{
2513
207
    apr_size_t end_index;
2514
207
    int last_group_len;
2515
207
    const char *end;
2516
2517
    /* Sanity check.
2518
     * TODO: this would be a lot more efficient if we had access to the lookup
2519
     * table used by APR. If that gets pulled in at any point, make use of it.
2520
     */
2521
207
    end_index = strspn(encoded, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2522
207
                                "abcdefghijklmnopqrstuvwxyz"
2523
207
                                "0123456789+/");
2524
2525
207
    last_group_len = end_index % 4;
2526
207
    end = encoded + end_index;
2527
2528
    /* The only non-alphabet character allowed is the padding character '=' at
2529
     * the end of the string. There are two allowable padding cases for the last
2530
     * group of four: "xY==" or "xyZ=". We require the final (non-padding)
2531
     * character to have been zero-padded during encoding, which limits the
2532
     * character choices.
2533
     */
2534
207
    if (last_group_len == 1) {
2535
        /* This isn't ever valid. */
2536
9
        return APR_EINVAL;
2537
9
    }
2538
198
    else if (last_group_len == 2) {
2539
        /* ...xY== */
2540
26
        if (*end != '=' || end[1] != '=') {
2541
24
            return APR_EINVAL;
2542
24
        }
2543
2
        else if (!ap_strchr("AQgw", end[-1])) {
2544
            /* Correctly zero-padded input data will result in a final character
2545
             * that is one of the four above. */
2546
1
            return APR_EINVAL;
2547
1
        }
2548
2549
1
        end += 2;
2550
1
    }
2551
172
    else if (last_group_len == 3) {
2552
        /* ...xyZ= */
2553
24
        if (*end != '=') {
2554
22
            return APR_EINVAL;
2555
22
        }
2556
2
        else if (!ap_strchr("AEIMQUYcgkosw048", end[-1])) {
2557
            /* Correctly zero-padded input data will result in a final character
2558
             * that is one of the sixteen above. */
2559
1
            return APR_EINVAL;
2560
1
        }
2561
2562
1
        end++;
2563
1
    }
2564
2565
    /* At this point, if the encoded buffer is correct, we should be at the end
2566
     * of the string. */
2567
150
    if (*end) {
2568
115
        return APR_EINVAL;
2569
115
    }
2570
2571
35
    *decoded = apr_palloc(p, apr_base64_decode_len(encoded));
2572
35
    *len = apr_base64_decode(*decoded, encoded);
2573
2574
35
    return APR_SUCCESS;
2575
150
}
2576
2577
AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
2578
1.21k
{
2579
1.21k
    char *encoded;
2580
1.21k
    int l = strlen(string);
2581
2582
1.21k
    encoded = (char *) apr_palloc(p, apr_base64_encode_len(l));
2583
1.21k
    apr_base64_encode(encoded, string, l);
2584
2585
1.21k
    return encoded;
2586
1.21k
}
2587
2588
/* we want to downcase the type/subtype for comparison purposes
2589
 * but nothing else because ;parameter=foo values are case sensitive.
2590
 * XXX: in truth we want to downcase parameter names... but really,
2591
 * apache has never handled parameters and such correctly.  You
2592
 * also need to compress spaces and such to be able to compare
2593
 * properly. -djg
2594
 */
2595
AP_DECLARE(void) ap_content_type_tolower(char *str)
2596
225
{
2597
225
    char *semi;
2598
2599
225
    semi = strchr(str, ';');
2600
225
    if (semi) {
2601
9
        *semi = '\0';
2602
9
    }
2603
2604
225
    ap_str_tolower(str);
2605
2606
225
    if (semi) {
2607
9
        *semi = ';';
2608
9
    }
2609
225
}
2610
2611
/*
2612
 * Given a string, replace any bare " with \" .
2613
 */
2614
AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
2615
1.21k
{
2616
1.21k
    apr_size_t size, extra = 0;
2617
1.21k
    const char *inchr = instring;
2618
1.21k
    char *outchr, *outstring;
2619
2620
    /*
2621
     * Look through the input string, jogging the length of the output
2622
     * string up by an extra byte each time we find an unescaped ".
2623
     */
2624
53.5k
    while (*inchr != '\0') {
2625
52.3k
        if (*inchr == '"') {
2626
1.20k
            extra++;
2627
1.20k
        }
2628
        /*
2629
         * If we find a slosh, and it's not the last byte in the string,
2630
         * it's escaping something - advance past both bytes.
2631
         */
2632
51.1k
        else if ((*inchr == '\\') && (inchr[1] != '\0')) {
2633
3.67k
            inchr++;
2634
3.67k
        }
2635
52.3k
        inchr++;
2636
52.3k
    }
2637
2638
1.21k
    if (!extra) {
2639
936
        return apr_pstrdup(p, instring);
2640
936
    }
2641
2642
    /* How large will the string become, once we escaped all the quotes?
2643
     * The tricky cases are
2644
     * - an `instring` that is already longer than `ptrdiff_t`
2645
     *   can hold (which is an undefined case in C, as C defines ptrdiff_t as
2646
     *   a signed difference between pointers into the same array and one index
2647
     *   beyond).
2648
     * - an `instring` that, including the `extra` chars we want to add, becomes
2649
     *   even larger than apr_size_t can handle.
2650
     * Since this function was not designed to ever return NULL for failure, we
2651
     * can only trigger a hard assertion failure. It seems more a programming
2652
     * mistake (or failure to verify the input causing this) that leads to this
2653
     * situation.
2654
     */
2655
276
    ap_assert(inchr - instring > 0);
2656
276
    size = ((apr_size_t)(inchr - instring)) + 1;
2657
276
    ap_assert(size + extra > size);
2658
2659
276
    outstring = apr_palloc(p, size + extra);
2660
276
    inchr = instring;
2661
276
    outchr = outstring;
2662
    /*
2663
     * Now copy the input string to the output string, inserting a slosh
2664
     * in front of every " that doesn't already have one.
2665
     */
2666
14.9k
    while (*inchr != '\0') {
2667
14.6k
        if (*inchr == '"') {
2668
1.20k
            *outchr++ = '\\';
2669
1.20k
        }
2670
13.4k
        else if ((*inchr == '\\') && (inchr[1] != '\0')) {
2671
914
            *outchr++ = *inchr++;
2672
914
        }
2673
14.6k
        *outchr++ = *inchr++;
2674
14.6k
    }
2675
276
    *outchr = '\0';
2676
276
    return outstring;
2677
276
}
2678
2679
/*
2680
 * Given a string, append the PID deliminated by delim.
2681
 * Usually used to create a pid-appended filepath name
2682
 * (eg: /a/b/foo -> /a/b/foo.6726). A function, and not
2683
 * a macro, to avoid unistd.h dependency
2684
 */
2685
AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
2686
                                    const char *delim)
2687
0
{
2688
0
    return apr_psprintf(p, "%s%s%" APR_PID_T_FMT, string,
2689
0
                        delim, getpid());
2690
2691
0
}
2692
2693
/**
2694
 * Parse a given timeout parameter string into an apr_interval_time_t value.
2695
 * The unit of the time interval is given as postfix string to the numeric
2696
 * string. Currently the following units are understood (case insensitive):
2697
 *
2698
 * ms    : milliseconds
2699
 * s     : seconds
2700
 * mi[n] : minutes
2701
 * h     : hours
2702
 *
2703
 * If no unit is contained in the given timeout parameter the default_time_unit
2704
 * will be used instead.
2705
 * @param timeout_parameter The string containing the timeout parameter.
2706
 * @param timeout The timeout value to be returned.
2707
 * @param default_time_unit The default time unit to use if none is specified
2708
 * in timeout_parameter.
2709
 * @return Status value indicating whether the parsing was successful or not.
2710
 */
2711
384
#define CHECK_OVERFLOW(a, b) if (a > b) return APR_EGENERAL
2712
AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
2713
                                               const char *timeout_parameter,
2714
                                               apr_interval_time_t *timeout,
2715
                                               const char *default_time_unit)
2716
1.21k
{
2717
1.21k
    char *endp;
2718
1.21k
    const char *time_str;
2719
1.21k
    apr_int64_t tout;
2720
1.21k
    apr_uint64_t check;
2721
2722
1.21k
    tout = apr_strtoi64(timeout_parameter, &endp, 10);
2723
1.21k
    if (errno) {
2724
4
        return errno;
2725
4
    }
2726
1.20k
    if (!endp || !*endp) {
2727
111
        time_str = default_time_unit;
2728
111
    }
2729
1.09k
    else {
2730
1.09k
        time_str = endp;
2731
1.09k
    }
2732
2733
1.20k
    if (tout < 0) { 
2734
93
        return APR_EGENERAL;
2735
93
    }
2736
2737
1.11k
    switch (*time_str) {
2738
        /* Time is in seconds */
2739
63
    case 's':
2740
101
    case 'S':
2741
101
        CHECK_OVERFLOW(tout, apr_time_sec(APR_INT64_MAX));
2742
62
        check = apr_time_from_sec(tout);
2743
62
        break;
2744
        /* Time is in hours */
2745
43
    case 'h':
2746
83
    case 'H':
2747
83
        CHECK_OVERFLOW(tout, apr_time_sec(APR_INT64_MAX / 3600));
2748
32
        check = apr_time_from_sec(tout * 3600);
2749
32
        break;
2750
149
    case 'm':
2751
203
    case 'M':
2752
203
        switch (*(++time_str)) {
2753
        /* Time is in milliseconds */
2754
107
        case 's':
2755
111
        case 'S':
2756
111
            CHECK_OVERFLOW(tout, apr_time_as_msec(APR_INT64_MAX));
2757
79
            check = apr_time_from_msec(tout);
2758
79
            break;
2759
        /* Time is in minutes */
2760
47
        case 'i':
2761
89
        case 'I':
2762
89
            CHECK_OVERFLOW(tout, apr_time_sec(APR_INT64_MAX / 60));
2763
43
            check = apr_time_from_sec(tout * 60);
2764
43
            break;
2765
3
        default:
2766
3
            return APR_EGENERAL;
2767
203
        }
2768
122
        break;
2769
728
    default:
2770
728
        return APR_EGENERAL;
2771
1.11k
    }
2772
2773
216
    *timeout = (apr_interval_time_t)check;
2774
216
    return APR_SUCCESS;
2775
1.11k
}
2776
2777
AP_DECLARE(apr_status_t) ap_size_parameter_parse(const char *parameter,
2778
                                                 apr_off_t *value)
2779
0
{
2780
0
    apr_off_t parsed;
2781
0
    apr_status_t rv;
2782
0
    char *end;
2783
2784
    /* Check for no conversion before the status: some libc implementations
2785
     * set EINVAL when no digits are present. */
2786
0
    rv = apr_strtoff(&parsed, parameter, &end, 10);
2787
0
    if (end == parameter) {
2788
0
        return APR_EINVAL;
2789
0
    }
2790
0
    if (rv != APR_SUCCESS) {
2791
0
        return APR_ERANGE;
2792
0
    }
2793
0
    if (*end != '\0') {
2794
0
        return APR_EINVAL;
2795
0
    }
2796
2797
0
    *value = parsed;
2798
0
    return APR_SUCCESS;
2799
0
}
2800
#undef CHECK_OVERFLOW
2801
2802
AP_DECLARE(int) ap_parse_strict_length(apr_off_t *len, const char *str)
2803
0
{
2804
0
    char *end;
2805
2806
0
    return (apr_isdigit(*str)
2807
0
            && apr_strtoff(len, str, &end, 10) == APR_SUCCESS
2808
0
            && *end == '\0');
2809
0
}
2810
2811
/**
2812
 * Determine if a request has a request body or not.
2813
 *
2814
 * @param r the request_rec of the request
2815
 * @return truth value
2816
 */
2817
AP_DECLARE(int) ap_request_has_body(request_rec *r)
2818
0
{
2819
0
    apr_off_t cl;
2820
0
    const char *cls;
2821
2822
0
    return (!r->header_only
2823
0
            && (r->kept_body
2824
0
                || apr_table_get(r->headers_in, "Transfer-Encoding")
2825
0
                || ((cls = apr_table_get(r->headers_in, "Content-Length"))
2826
0
                    && ap_parse_strict_length(&cl, cls) && cl > 0)));
2827
0
}
2828
2829
/**
2830
 * Check whether a request is tainted by exposure to something
2831
 * potentially untrusted.  
2832
 *
2833
 */
2834
AP_DECLARE(int) ap_request_tainted(request_rec *r, int flags)
2835
0
{
2836
    /** Potential future: a hook or callback here could serve modules
2837
     *  like mod_security and ironbee with more complex needs.
2838
     */
2839
0
    return r && ((r->taint&flags)
2840
0
                 || ap_request_tainted(r->main, flags)
2841
0
                 || ap_request_tainted(r->prev, flags));
2842
0
}
2843
2844
AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
2845
0
{
2846
0
    void **ptr = (void **)data_;
2847
0
    *ptr = NULL;
2848
0
    return APR_SUCCESS;
2849
0
}
2850
2851
1.21k
AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
2852
2853
57.2k
    for ( ; *src; src++, dest++)
2854
56.0k
    {
2855
56.0k
        if (!apr_isprint(*src))
2856
17.7k
            *dest = 'x';
2857
38.2k
        else if (!apr_isalnum(*src))
2858
22.8k
            *dest = '_';
2859
15.4k
        else
2860
15.4k
            *dest = (char)*src;
2861
56.0k
    }
2862
1.21k
    *dest = '\0';
2863
1.21k
    return APR_SUCCESS;
2864
2865
1.21k
}
2866
2867
AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
2868
                                        const char **dest)
2869
1.21k
{
2870
1.21k
    char *new = apr_palloc(p, strlen(src)+1);
2871
1.21k
    if (!new)
2872
0
        return APR_ENOMEM;
2873
1.21k
    *dest = new;
2874
1.21k
    return ap_str2_alnum(src, new);
2875
1.21k
}
2876
2877
/**
2878
 * Read the body and parse any form found, which must be of the
2879
 * type application/x-www-form-urlencoded.
2880
 *
2881
 * Name/value pairs are returned in an array, with the names as
2882
 * strings with a maximum length of HUGE_STRING_LEN, and the
2883
 * values as bucket brigades. This allows values to be arbitrarily
2884
 * large.
2885
 *
2886
 * All url-encoding is removed from both the names and the values
2887
 * on the fly. The names are interpreted as strings, while the
2888
 * values are interpreted as blocks of binary data, that may
2889
 * contain the 0 character.
2890
 *
2891
 * In order to ensure that resource limits are not exceeded, a
2892
 * maximum size must be provided. If the sum of the lengths of
2893
 * the names and the values exceed this size, this function
2894
 * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
2895
 *
2896
 * An optional number of parameters can be provided, if the number
2897
 * of parameters provided exceeds this amount, this function will
2898
 * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
2899
 * no limit is imposed, and the number of parameters is in turn
2900
 * constrained by the size parameter above.
2901
 *
2902
 * This function honours any kept_body configuration, and the
2903
 * original raw request body will be saved to the kept_body brigade
2904
 * if so configured, just as ap_discard_request_body does.
2905
 *
2906
 * NOTE: File upload is not yet supported, but can be without change
2907
 * to the function call.
2908
 */
2909
2910
/* form parsing stuff */
2911
typedef enum {
2912
    FORM_NORMAL,
2913
    FORM_AMP,
2914
    FORM_NAME,
2915
    FORM_VALUE,
2916
    FORM_PERCENTA,
2917
    FORM_PERCENTB,
2918
    FORM_ABORT
2919
} ap_form_type_t;
2920
2921
AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
2922
                                   apr_array_header_t **ptr,
2923
                                   apr_size_t num, apr_size_t usize)
2924
0
{
2925
0
    apr_bucket_brigade *bb = NULL;
2926
0
    int seen_eos = 0;
2927
0
    char buffer[HUGE_STRING_LEN + 1];
2928
0
    const char *ct;
2929
0
    apr_size_t offset = 0;
2930
0
    apr_ssize_t size;
2931
0
    ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
2932
0
    ap_form_pair_t *pair = NULL;
2933
0
    apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
2934
0
    char escaped_char[2] = { 0 };
2935
2936
0
    *ptr = pairs;
2937
2938
    /* sanity check - we only support forms for now */
2939
0
    ct = apr_table_get(r->headers_in, "Content-Type");
2940
0
    if (!ct || ap_cstr_casecmpn("application/x-www-form-urlencoded", ct, 33)) {
2941
0
        return ap_discard_request_body(r);
2942
0
    }
2943
2944
0
    if (usize > APR_SIZE_MAX >> 1)
2945
0
        size = APR_SIZE_MAX >> 1;
2946
0
    else
2947
0
        size = usize;
2948
2949
0
    if (!f) {
2950
0
        f = r->input_filters;
2951
0
    }
2952
2953
0
    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2954
0
    do {
2955
0
        apr_bucket *bucket = NULL, *last = NULL;
2956
2957
0
        int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
2958
0
                                APR_BLOCK_READ, HUGE_STRING_LEN);
2959
0
        if (rv != APR_SUCCESS) {
2960
0
            apr_brigade_destroy(bb);
2961
0
            return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
2962
0
        }
2963
2964
0
        for (bucket = APR_BRIGADE_FIRST(bb);
2965
0
             bucket != APR_BRIGADE_SENTINEL(bb);
2966
0
             last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
2967
0
            const char *data;
2968
0
            apr_size_t len, slide;
2969
2970
0
            if (last) {
2971
0
                apr_bucket_delete(last);
2972
0
            }
2973
0
            if (APR_BUCKET_IS_EOS(bucket)) {
2974
0
                seen_eos = 1;
2975
0
                break;
2976
0
            }
2977
0
            if (bucket->length == 0) {
2978
0
                continue;
2979
0
            }
2980
2981
0
            rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
2982
0
            if (rv != APR_SUCCESS) {
2983
0
                apr_brigade_destroy(bb);
2984
0
                return HTTP_BAD_REQUEST;
2985
0
            }
2986
2987
0
            slide = len;
2988
0
            while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
2989
0
                char c = *data++;
2990
0
                if ('+' == c) {
2991
0
                    c = ' ';
2992
0
                }
2993
0
                else if ('&' == c) {
2994
0
                    state = FORM_AMP;
2995
0
                }
2996
0
                if ('%' == c) {
2997
0
                    percent = FORM_PERCENTA;
2998
0
                    continue;
2999
0
                }
3000
0
                if (FORM_PERCENTA == percent) {
3001
0
                    escaped_char[0] = c;
3002
0
                    percent = FORM_PERCENTB;
3003
0
                    continue;
3004
0
                }
3005
0
                if (FORM_PERCENTB == percent) {
3006
0
                    escaped_char[1] = c;
3007
0
                    c = x2c(escaped_char);
3008
0
                    percent = FORM_NORMAL;
3009
0
                }
3010
0
                switch (state) {
3011
0
                    case FORM_AMP:
3012
0
                        if (pair) {
3013
0
                            const char *tmp = apr_pmemdup(r->pool, buffer, offset);
3014
0
                            apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
3015
0
                            APR_BRIGADE_INSERT_TAIL(pair->value, b);
3016
0
                        }
3017
0
                        state = FORM_NAME;
3018
0
                        pair = NULL;
3019
0
                        offset = 0;
3020
0
                        num--;
3021
0
                        break;
3022
0
                    case FORM_NAME:
3023
0
                        if (offset < HUGE_STRING_LEN) {
3024
0
                            if ('=' == c) {
3025
0
                                pair = (ap_form_pair_t *) apr_array_push(pairs);
3026
0
                                pair->name = apr_pstrmemdup(r->pool, buffer, offset);
3027
0
                                pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
3028
0
                                state = FORM_VALUE;
3029
0
                                offset = 0;
3030
0
                            }
3031
0
                            else {
3032
0
                                buffer[offset++] = c;
3033
0
                                size--;
3034
0
                            }
3035
0
                        }
3036
0
                        else {
3037
0
                            state = FORM_ABORT;
3038
0
                        }
3039
0
                        break;
3040
0
                    case FORM_VALUE:
3041
0
                        if (offset >= HUGE_STRING_LEN) {
3042
0
                            const char *tmp = apr_pmemdup(r->pool, buffer, offset);
3043
0
                            apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
3044
0
                            APR_BRIGADE_INSERT_TAIL(pair->value, b);
3045
0
                            offset = 0;
3046
0
                        }
3047
0
                        buffer[offset++] = c;
3048
0
                        size--;
3049
0
                        break;
3050
0
                    default:
3051
0
                        break;
3052
0
                }
3053
0
            }
3054
3055
0
        }
3056
3057
0
        apr_brigade_cleanup(bb);
3058
0
    } while (!seen_eos);
3059
3060
0
    if (FORM_ABORT == state || size < 0 || num == 0) {
3061
0
        return HTTP_REQUEST_ENTITY_TOO_LARGE;
3062
0
    }
3063
0
    else if (FORM_VALUE == state && pair && offset > 0) {
3064
0
        const char *tmp = apr_pmemdup(r->pool, buffer, offset);
3065
0
        apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
3066
0
        APR_BRIGADE_INSERT_TAIL(pair->value, b);
3067
0
    }
3068
3069
0
    return OK;
3070
3071
0
}
3072
3073
0
#define VARBUF_SMALL_SIZE 2048
3074
0
#define VARBUF_MAX_SIZE   (APR_SIZE_MAX - 1 -                                \
3075
0
                           APR_ALIGN_DEFAULT(sizeof(struct ap_varbuf_info)))
3076
3077
struct ap_varbuf_info {
3078
    struct apr_memnode_t *node;
3079
    apr_allocator_t *allocator;
3080
};
3081
3082
static apr_status_t varbuf_cleanup(void *info_)
3083
0
{
3084
0
    struct ap_varbuf_info *info = info_;
3085
0
    info->node->next = NULL;
3086
0
    apr_allocator_free(info->allocator, info->node);
3087
0
    return APR_SUCCESS;
3088
0
}
3089
3090
static const char nul = '\0';
3091
static char * const varbuf_empty = (char *)&nul;
3092
3093
AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
3094
                                apr_size_t init_size)
3095
0
{
3096
0
    vb->buf = varbuf_empty;
3097
0
    vb->avail = 0;
3098
0
    vb->strlen = AP_VARBUF_UNKNOWN;
3099
0
    vb->pool = p;
3100
0
    vb->info = NULL;
3101
3102
0
    ap_varbuf_grow(vb, init_size);
3103
0
}
3104
3105
AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
3106
0
{
3107
0
    apr_memnode_t *new_node = NULL;
3108
0
    apr_allocator_t *allocator;
3109
0
    struct ap_varbuf_info *new_info;
3110
0
    char *new;
3111
3112
0
    AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen);
3113
3114
0
    if (new_len <= vb->avail)
3115
0
        return;
3116
3117
0
    if (new_len < 2 * vb->avail && vb->avail < VARBUF_MAX_SIZE/2) {
3118
        /* at least double the size, to avoid repeated reallocations */
3119
0
        new_len = 2 * vb->avail;
3120
0
    }
3121
0
    else if (new_len > VARBUF_MAX_SIZE) {
3122
0
        apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
3123
0
        ap_assert(abort_fn != NULL);
3124
0
        abort_fn(APR_ENOMEM);
3125
0
        return;
3126
0
    }
3127
3128
0
    new_len++;  /* add space for trailing \0 */
3129
0
    if (new_len <= VARBUF_SMALL_SIZE) {
3130
0
        new_len = APR_ALIGN_DEFAULT(new_len);
3131
0
        new = apr_palloc(vb->pool, new_len);
3132
0
        if (vb->avail && vb->strlen != 0) {
3133
0
            AP_DEBUG_ASSERT(vb->buf != NULL);
3134
0
            AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
3135
0
            if (new == vb->buf + vb->avail + 1) {
3136
                /* We are lucky: the new memory lies directly after our old
3137
                 * buffer, we can now use both.
3138
                 */
3139
0
                vb->avail += new_len;
3140
0
                return;
3141
0
            }
3142
0
            else {
3143
                /* copy up to vb->strlen + 1 bytes */
3144
0
                memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
3145
0
                                     vb->avail + 1 : vb->strlen + 1);
3146
0
            }
3147
0
        }
3148
0
        else {
3149
0
            *new = '\0';
3150
0
        }
3151
0
        vb->avail = new_len - 1;
3152
0
        vb->buf = new;
3153
0
        return;
3154
0
    }
3155
3156
    /* The required block is rather larger. Use allocator directly so that
3157
     * the memory can be freed independently from the pool. */
3158
0
    allocator = apr_pool_allocator_get(vb->pool);
3159
    /* Happens if APR was compiled with APR_POOL_DEBUG */
3160
0
    if (allocator == NULL) {
3161
0
        apr_allocator_create(&allocator);
3162
0
        ap_assert(allocator != NULL);
3163
0
    }
3164
0
    if (new_len <= VARBUF_MAX_SIZE)
3165
0
        new_node = apr_allocator_alloc(allocator,
3166
0
                                       new_len + APR_ALIGN_DEFAULT(sizeof(*new_info)));
3167
0
    if (!new_node) {
3168
0
        apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
3169
0
        ap_assert(abort_fn != NULL);
3170
0
        abort_fn(APR_ENOMEM);
3171
0
        return;
3172
0
    }
3173
0
    new_info = (struct ap_varbuf_info *)new_node->first_avail;
3174
0
    new_node->first_avail += APR_ALIGN_DEFAULT(sizeof(*new_info));
3175
0
    new_info->node = new_node;
3176
0
    new_info->allocator = allocator;
3177
0
    new = new_node->first_avail;
3178
0
    AP_DEBUG_ASSERT(new_node->endp - new_node->first_avail >= new_len);
3179
0
    new_len = new_node->endp - new_node->first_avail;
3180
3181
0
    if (vb->avail && vb->strlen != 0)
3182
0
        memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
3183
0
                             vb->avail + 1 : vb->strlen + 1);
3184
0
    else
3185
0
        *new = '\0';
3186
0
    if (vb->info)
3187
0
        apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
3188
0
    apr_pool_cleanup_register(vb->pool, new_info, varbuf_cleanup,
3189
0
                              apr_pool_cleanup_null);
3190
0
    vb->info = new_info;
3191
0
    vb->buf = new;
3192
0
    vb->avail = new_len - 1;
3193
0
}
3194
3195
AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
3196
                                     int len)
3197
0
{
3198
0
    if (len == 0)
3199
0
        return;
3200
0
    if (!vb->avail) {
3201
0
        ap_varbuf_grow(vb, len);
3202
0
        memcpy(vb->buf, str, len);
3203
0
        vb->buf[len] = '\0';
3204
0
        vb->strlen = len;
3205
0
        return;
3206
0
    }
3207
0
    if (vb->strlen == AP_VARBUF_UNKNOWN)
3208
0
        vb->strlen = strlen(vb->buf);
3209
0
    ap_varbuf_grow(vb, vb->strlen + len);
3210
0
    memcpy(vb->buf + vb->strlen, str, len);
3211
0
    vb->strlen += len;
3212
0
    vb->buf[vb->strlen] = '\0';
3213
0
}
3214
3215
AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
3216
0
{
3217
0
    if (vb->info) {
3218
0
        apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
3219
0
        vb->info = NULL;
3220
0
    }
3221
0
    vb->buf = NULL;
3222
0
}
3223
3224
AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf,
3225
                                  const char *prepend, apr_size_t prepend_len,
3226
                                  const char *append, apr_size_t append_len,
3227
                                  apr_size_t *new_len)
3228
0
{
3229
0
    apr_size_t i = 0;
3230
0
    struct iovec vec[3];
3231
3232
0
    if (prepend) {
3233
0
        vec[i].iov_base = (void *)prepend;
3234
0
        vec[i].iov_len = prepend_len;
3235
0
        i++;
3236
0
    }
3237
0
    if (buf->avail && buf->strlen) {
3238
0
        if (buf->strlen == AP_VARBUF_UNKNOWN)
3239
0
            buf->strlen = strlen(buf->buf);
3240
0
        vec[i].iov_base = (void *)buf->buf;
3241
0
        vec[i].iov_len = buf->strlen;
3242
0
        i++;
3243
0
    }
3244
0
    if (append) {
3245
0
        vec[i].iov_base = (void *)append;
3246
0
        vec[i].iov_len = append_len;
3247
0
        i++;
3248
0
    }
3249
0
    if (i)
3250
0
        return apr_pstrcatv(p, vec, i, new_len);
3251
3252
0
    if (new_len)
3253
0
        *new_len = 0;
3254
0
    return "";
3255
0
}
3256
3257
AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
3258
                                          const char *input,
3259
                                          const char *source,
3260
                                          apr_size_t nmatch,
3261
                                          ap_regmatch_t pmatch[],
3262
                                          apr_size_t maxlen)
3263
0
{
3264
0
    return regsub_core(NULL, NULL, vb, input, source, nmatch, pmatch, maxlen);
3265
0
}
3266
3267
static const char * const oom_message = "[crit] Memory allocation failed, "
3268
                                        "aborting process." APR_EOL_STR;
3269
3270
AP_DECLARE(void) ap_abort_on_oom(void)
3271
0
{
3272
0
    int written, count = strlen(oom_message);
3273
0
    const char *buf = oom_message;
3274
0
    do {
3275
0
        written = write(STDERR_FILENO, buf, count);
3276
0
        if (written == count)
3277
0
            break;
3278
0
        if (written > 0) {
3279
0
            buf += written;
3280
0
            count -= written;
3281
0
        }
3282
0
    } while (written >= 0 || errno == EINTR);
3283
0
    abort();
3284
0
}
3285
3286
AP_DECLARE(void *) ap_malloc(size_t size)
3287
0
{
3288
0
    void *p = malloc(size);
3289
0
    if (p == NULL && size != 0)
3290
0
        ap_abort_on_oom();
3291
0
    return p;
3292
0
}
3293
3294
AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size)
3295
0
{
3296
0
    void *p = calloc(nelem, size);
3297
0
    if (p == NULL && nelem != 0 && size != 0)
3298
0
        ap_abort_on_oom();
3299
0
    return p;
3300
0
}
3301
3302
AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
3303
0
{
3304
0
    void *p = realloc(ptr, size);
3305
0
    if (p == NULL && size != 0)
3306
0
        ap_abort_on_oom();
3307
0
    return p;
3308
0
}
3309
3310
#if APR_HAS_THREADS
3311
3312
#if AP_HAS_THREAD_LOCAL && !APR_VERSION_AT_LEAST(1,8,0)
3313
static AP_THREAD_LOCAL apr_thread_t *current_thread = NULL;
3314
#endif
3315
3316
struct thread_ctx {
3317
    apr_thread_start_t func;
3318
    void *data;
3319
};
3320
3321
static void *APR_THREAD_FUNC thread_start(apr_thread_t *thread, void *data)
3322
0
{
3323
0
    struct thread_ctx *ctx = data;
3324
3325
    /* Don't let the thread's pool allocator with no limits, though there
3326
     * is possibly no allocator with APR <= 1.7 and APR_POOL_DEBUG.
3327
     */
3328
0
    {
3329
0
        apr_pool_t *tp = apr_thread_pool_get(thread);
3330
0
        apr_allocator_t *ta = apr_pool_allocator_get(tp);
3331
0
        if (ta) {
3332
0
            apr_allocator_max_free_set(ta, ap_max_mem_free);
3333
0
        }
3334
0
    }
3335
3336
#if AP_HAS_THREAD_LOCAL && !APR_VERSION_AT_LEAST(1,8,0)
3337
    current_thread = thread;
3338
#endif
3339
0
    return ctx->func(thread, ctx->data);
3340
0
}
3341
3342
AP_DECLARE(apr_status_t) ap_thread_create(apr_thread_t **thread, 
3343
                                          apr_threadattr_t *attr, 
3344
                                          apr_thread_start_t func, 
3345
                                          void *data, apr_pool_t *pool)
3346
0
{
3347
0
    struct thread_ctx *ctx = apr_palloc(pool, sizeof(*ctx));
3348
3349
0
    ctx->func = func;
3350
0
    ctx->data = data;
3351
0
    return apr_thread_create(thread, attr, thread_start, ctx, pool);
3352
0
}
3353
3354
static apr_status_t main_thread_cleanup(void *arg)
3355
0
{
3356
0
    apr_thread_t *thd = arg;
3357
0
    apr_pool_destroy(apr_thread_pool_get(thd));
3358
0
    return APR_SUCCESS;
3359
0
}
3360
3361
AP_DECLARE(apr_status_t) ap_thread_main_create(apr_thread_t **thread,
3362
                                               apr_pool_t *pool)
3363
0
{
3364
0
    apr_status_t rv;
3365
0
    apr_threadattr_t *attr = NULL;
3366
3367
    /* Create an apr_thread_t for the main child thread to set up its Thread
3368
     * Local Storage. Since it's detached and won't apr_thread_exit(), destroy
3369
     * its pool before exiting via a cleanup of the given pool.
3370
     */
3371
0
    if ((rv = apr_threadattr_create(&attr, pool))
3372
0
            || (rv = apr_threadattr_detach_set(attr, 1))
3373
0
#if APR_VERSION_AT_LEAST(1,8,0)
3374
0
            || (rv = apr_threadattr_max_free_set(attr, ap_max_mem_free))
3375
0
#endif
3376
0
            || (rv = ap_thread_current_create(thread, attr, pool))) {
3377
0
        *thread = NULL;
3378
0
        return rv;
3379
0
    }
3380
3381
0
    apr_pool_cleanup_register(pool, *thread, main_thread_cleanup,
3382
0
                              apr_pool_cleanup_null);
3383
0
    return APR_SUCCESS;
3384
0
}
3385
3386
#if !APR_VERSION_AT_LEAST(1,8,0)
3387
3388
AP_DECLARE(apr_status_t) ap_thread_current_create(apr_thread_t **current,
3389
                                                  apr_threadattr_t *attr,
3390
                                                  apr_pool_t *pool)
3391
{
3392
#if AP_HAS_THREAD_LOCAL
3393
    apr_status_t rv;
3394
    apr_allocator_t *ta;
3395
    apr_abortfunc_t abort_fn;
3396
    apr_os_thread_t osthd;
3397
    apr_pool_t *p;
3398
3399
    *current = ap_thread_current();
3400
    if (*current) {
3401
        return APR_EEXIST;
3402
    }
3403
3404
    abort_fn = (pool) ? apr_pool_abort_get(pool) : NULL;
3405
    rv = apr_allocator_create(&ta);
3406
    if (rv != APR_SUCCESS) {
3407
        if (abort_fn)
3408
            abort_fn(rv);
3409
        return rv;
3410
    }
3411
    /* Don't let the thread's pool allocator with no limits */
3412
    apr_allocator_max_free_set(ta, ap_max_mem_free);
3413
    rv = apr_pool_create_unmanaged_ex(&p, abort_fn, ta);
3414
    if (rv != APR_SUCCESS) {
3415
        return rv;
3416
    }
3417
    apr_allocator_owner_set(ta, p);
3418
3419
    osthd = apr_os_thread_current();
3420
    rv = apr_os_thread_put(current, &osthd, p);
3421
    if (rv != APR_SUCCESS) {
3422
        apr_pool_destroy(p);
3423
        return rv;
3424
    }
3425
3426
    current_thread = *current;
3427
    return APR_SUCCESS;
3428
#else
3429
    return APR_ENOTIMPL;
3430
#endif
3431
}
3432
3433
AP_DECLARE(void) ap_thread_current_after_fork(void)
3434
{
3435
#if AP_HAS_THREAD_LOCAL
3436
    current_thread = NULL;
3437
#endif
3438
}
3439
3440
AP_DECLARE(apr_thread_t *) ap_thread_current(void)
3441
{
3442
#if AP_HAS_THREAD_LOCAL
3443
    return current_thread;
3444
#else
3445
    return NULL;
3446
#endif
3447
}
3448
3449
#endif /* !APR_VERSION_AT_LEAST(1,8,0) */
3450
3451
#endif /* APR_HAS_THREADS */
3452
3453
AP_DECLARE(void) ap_get_sload(ap_sload_t *ld)
3454
0
{
3455
0
    int i, j, server_limit, thread_limit;
3456
0
    int ready = 0;
3457
0
    int busy = 0;
3458
0
    int total;
3459
0
    ap_generation_t mpm_generation;
3460
3461
    /* preload errored fields, we overwrite */
3462
0
    ld->idle = -1;
3463
0
    ld->busy = -1;
3464
0
    ld->bytes_served = 0;
3465
0
    ld->access_count = 0;
3466
3467
0
    ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
3468
0
    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
3469
0
    ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
3470
3471
0
    for (i = 0; i < server_limit; i++) {
3472
0
        process_score *ps;
3473
0
        ps = ap_get_scoreboard_process(i);
3474
3475
0
        for (j = 0; j < thread_limit; j++) {
3476
0
            int res;
3477
0
            worker_score *ws = NULL;
3478
0
            ws = &ap_scoreboard_image->servers[i][j];
3479
0
            res = ws->status;
3480
3481
0
            if (!ps->quiescing && ps->pid) {
3482
0
                if (res == SERVER_READY && ps->generation == mpm_generation) {
3483
0
                    ready++;
3484
0
                }
3485
0
                else if (res != SERVER_DEAD &&
3486
0
                         res != SERVER_STARTING && res != SERVER_IDLE_KILL &&
3487
0
                         ps->generation == mpm_generation) {
3488
0
                    busy++;
3489
0
                }   
3490
0
            }
3491
3492
0
            if (ap_extended_status && !ps->quiescing && ps->pid) {
3493
0
                if (ws->access_count != 0 
3494
0
                    || (res != SERVER_READY && res != SERVER_DEAD)) {
3495
0
                    ld->access_count += ws->access_count;
3496
0
                    ld->bytes_served += ws->bytes_served;
3497
0
                }
3498
0
            }
3499
0
        }
3500
0
    }
3501
0
    total = busy + ready;
3502
0
    if (total) {
3503
0
        ld->idle = ready * 100 / total;
3504
0
        ld->busy = busy * 100 / total;
3505
0
    }
3506
0
}
3507
3508
AP_DECLARE(void) ap_get_loadavg(ap_loadavg_t *ld)
3509
0
{
3510
    /* preload errored fields, we overwrite */
3511
0
    ld->loadavg = -1.0;
3512
0
    ld->loadavg5 = -1.0;
3513
0
    ld->loadavg15 = -1.0;
3514
3515
0
#if HAVE_GETLOADAVG
3516
0
    {
3517
0
        double la[3];
3518
0
        int num;
3519
3520
0
        num = getloadavg(la, 3);
3521
0
        if (num > 0) {
3522
0
            ld->loadavg = (float)la[0];
3523
0
        }
3524
0
        if (num > 1) {
3525
0
            ld->loadavg5 = (float)la[1];
3526
0
        }
3527
0
        if (num > 2) {
3528
0
            ld->loadavg15 = (float)la[2];
3529
0
        }
3530
0
    }
3531
0
#endif
3532
0
}
3533
3534
static const char * const pw_cache_note_name = "conn_cache_note";
3535
struct pw_cache {
3536
    /* varbuf contains concatenated password and hash */
3537
    struct ap_varbuf vb;
3538
    apr_size_t pwlen;
3539
    apr_status_t result;
3540
};
3541
3542
AP_DECLARE(apr_status_t) ap_password_validate(request_rec *r,
3543
                                              const char *username,
3544
                                              const char *passwd,
3545
                                              const char *hash)
3546
0
{
3547
0
    struct pw_cache *cache;
3548
0
    apr_size_t hashlen;
3549
3550
0
    cache = (struct pw_cache *)apr_table_get(r->connection->notes, pw_cache_note_name);
3551
0
    if (cache != NULL) {
3552
0
        if (strncmp(passwd, cache->vb.buf, cache->pwlen) == 0
3553
0
            && strcmp(hash, cache->vb.buf + cache->pwlen) == 0) {
3554
0
            return cache->result;
3555
0
        }
3556
        /* make ap_varbuf_grow below not copy the old data */
3557
0
        cache->vb.strlen = 0;
3558
0
    }
3559
0
    else {
3560
0
        cache = apr_palloc(r->connection->pool, sizeof(struct pw_cache));
3561
0
        ap_varbuf_init(r->connection->pool, &cache->vb, 0);
3562
0
        apr_table_setn(r->connection->notes, pw_cache_note_name, (void *)cache);
3563
0
    }
3564
0
    cache->pwlen = strlen(passwd);
3565
0
    hashlen = strlen(hash);
3566
0
    ap_varbuf_grow(&cache->vb, cache->pwlen + hashlen + 1);
3567
0
    memcpy(cache->vb.buf, passwd, cache->pwlen);
3568
0
    memcpy(cache->vb.buf + cache->pwlen, hash, hashlen + 1);
3569
0
    cache->result = apr_password_validate(passwd, hash);
3570
0
    return cache->result;
3571
0
}
3572
3573
AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p,
3574
                                    const char *cmd,
3575
                                    const char * const * argv)
3576
0
{
3577
0
    char buf[MAX_STRING_LEN];
3578
0
    apr_procattr_t *procattr;
3579
0
    apr_proc_t *proc;
3580
0
    apr_file_t *fp;
3581
0
    apr_size_t nbytes = 1;
3582
0
    char c;
3583
0
    int k;
3584
3585
0
    if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
3586
0
        return NULL;
3587
0
    if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
3588
0
                            APR_FULL_BLOCK) != APR_SUCCESS)
3589
0
        return NULL;
3590
0
    if (apr_procattr_dir_set(procattr,
3591
0
                             ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
3592
0
        return NULL;
3593
0
    if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
3594
0
        return NULL;
3595
0
    proc = apr_pcalloc(p, sizeof(apr_proc_t));
3596
0
    if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
3597
0
        return NULL;
3598
0
    fp = proc->out;
3599
3600
0
    if (fp == NULL)
3601
0
        return NULL;
3602
    /* XXX: we are reading 1 byte at a time here */
3603
0
    for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
3604
0
                && nbytes == 1 && (k < MAX_STRING_LEN-1)     ; ) {
3605
0
        if (c == '\n' || c == '\r')
3606
0
            break;
3607
0
        buf[k++] = c;
3608
0
    }
3609
0
    buf[k] = '\0'; 
3610
0
    apr_file_close(fp);
3611
3612
0
    return apr_pstrndup(p, buf, k);
3613
0
}
3614
3615
AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array, 
3616
                                   const char *s,
3617
                                   int start)
3618
0
{
3619
0
    if (start >= 0) {
3620
0
        int i;
3621
        
3622
0
        for (i = start; i < array->nelts; i++) {
3623
0
            const char *p = APR_ARRAY_IDX(array, i, const char *);
3624
0
            if (!strcmp(p, s)) {
3625
0
                return i;
3626
0
            }
3627
0
        }
3628
0
    }
3629
    
3630
0
    return -1;
3631
0
}
3632
3633
AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array, 
3634
                                      const char *s)
3635
0
{
3636
0
    return (ap_array_str_index(array, s, 0) >= 0);
3637
0
}
3638
3639
#if !APR_CHARSET_EBCDIC
3640
/*
3641
 * Our own known-fast translation table for casecmp by character.
3642
 * Only ASCII alpha characters 41-5A are folded to 61-7A, other
3643
 * octets (such as extended latin alphabetics) are never case-folded.
3644
 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3645
 */
3646
static const unsigned char ucharmap[256] = {
3647
    0x0,  0x1,  0x2,  0x3,  0x4,  0x5,  0x6,  0x7,
3648
    0x8,  0x9,  0xa,  0xb,  0xc,  0xd,  0xe,  0xf,
3649
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3650
    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3651
    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3652
    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3653
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3654
    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3655
    0x40,  'a',  'b',  'c',  'd',  'e',  'f',  'g',
3656
     'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
3657
     'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
3658
     'x',  'y',  'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3659
    0x60,  'a',  'b',  'c',  'd',  'e',  'f',  'g',
3660
     'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
3661
     'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
3662
     'x',  'y',  'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3663
    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3664
    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3665
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3666
    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3667
    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3668
    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3669
    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3670
    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3671
    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3672
    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3673
    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3674
    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3675
    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3676
    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3677
    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3678
    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3679
};
3680
#else /* APR_CHARSET_EBCDIC */
3681
/*
3682
 * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison,
3683
 * provides unique identity of every char value (strict ISO-646
3684
 * conformance, arbitrary election of an ISO-8859-1 ordering, and
3685
 * very arbitrary control code assignments into C1 to achieve
3686
 * identity and a reversible mapping of code points),
3687
 * then folding the equivalences of ASCII 41-5A into 61-7A, 
3688
 * presenting comparison results in a somewhat ISO/IEC 10646
3689
 * (ASCII-like) order, depending on the EBCDIC code page in use.
3690
 *
3691
 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3692
 */
3693
static const unsigned char ucharmap[256] = {
3694
    0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
3695
    0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
3696
    0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
3697
    0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
3698
    0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
3699
    0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
3700
    0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
3701
    0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
3702
    0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,
3703
    0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
3704
    0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,
3705
    0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
3706
    0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,
3707
    0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
3708
    0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,
3709
    0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
3710
    0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3711
    0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
3712
    0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3713
    0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
3714
    0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3715
    0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,
3716
    0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,
3717
    0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,
3718
    0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3719
    0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
3720
    0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3721
    0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
3722
    0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3723
    0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
3724
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3725
    0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F
3726
};
3727
#endif
3728
3729
AP_DECLARE(char *) ap_cstr_stripws(char *str)
3730
994
{
3731
994
    char *end = str + strlen(str);
3732
3733
1.41k
    while (end > str && apr_isspace(end[-1])) {
3734
417
        --end;
3735
417
    }
3736
994
    *end = '\0';
3737
3738
994
    return end;
3739
994
}
3740
3741
AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2)
3742
2.61k
{
3743
2.61k
    const unsigned char *u1 = (const unsigned char *)s1;
3744
2.61k
    const unsigned char *u2 = (const unsigned char *)s2;
3745
3.30k
    for (;;) {
3746
3.30k
        const int c2 = ucharmap[*u2++];
3747
3.30k
        const int cmp = (int)ucharmap[*u1++] - c2;
3748
        /* Not necessary to test for !c1, this is caught by cmp */
3749
3.30k
        if (cmp || !c2)
3750
2.61k
            return cmp;
3751
3.30k
    }
3752
2.61k
}
3753
3754
AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
3755
6.09k
{
3756
6.09k
    const unsigned char *u1 = (const unsigned char *)s1;
3757
6.09k
    const unsigned char *u2 = (const unsigned char *)s2;
3758
8.51k
    while (n--) {
3759
8.37k
        const int c2 = ucharmap[*u2++];
3760
8.37k
        const int cmp = (int)ucharmap[*u1++] - c2;
3761
        /* Not necessary to test for !c1, this is caught by cmp */
3762
8.37k
        if (cmp || !c2)
3763
5.95k
            return cmp;
3764
8.37k
    }
3765
142
    return 0;
3766
6.09k
}
3767
3768
typedef struct {
3769
    const char *fname;
3770
} fnames;
3771
3772
static int fname_alphasort(const void *fn1, const void *fn2)
3773
0
{
3774
0
    const fnames *f1 = fn1;
3775
0
    const fnames *f2 = fn2;
3776
3777
0
    return strcmp(f1->fname, f2->fname);
3778
0
}
3779
3780
AP_DECLARE(ap_dir_match_t *)ap_dir_cfgmatch(cmd_parms *cmd, int flags,
3781
        const char *(*cb)(ap_dir_match_t *w, const char *fname), void *ctx)
3782
0
{
3783
0
    ap_dir_match_t *w = apr_palloc(cmd->temp_pool, sizeof(*w));
3784
3785
0
    w->prefix = apr_pstrcat(cmd->pool, cmd->cmd->name, ": ", NULL);
3786
0
    w->p = cmd->pool;
3787
0
    w->ptemp = cmd->temp_pool;
3788
0
    w->flags = flags;
3789
0
    w->cb = cb;
3790
0
    w->ctx = ctx;
3791
0
    w->depth = 0;
3792
3793
0
    return w;
3794
0
}
3795
3796
AP_DECLARE(const char *)ap_dir_nofnmatch(ap_dir_match_t *w, const char *fname)
3797
0
{
3798
0
    const char *error;
3799
0
    apr_status_t rv;
3800
3801
0
    if ((w->flags & AP_DIR_FLAG_RECURSIVE) && ap_is_directory(w->ptemp, fname)) {
3802
0
        apr_dir_t *dirp;
3803
0
        apr_finfo_t dirent;
3804
0
        int current;
3805
0
        apr_array_header_t *candidates = NULL;
3806
0
        fnames *fnew;
3807
0
        char *path = apr_pstrdup(w->ptemp, fname);
3808
3809
0
        if (++w->depth > AP_MAX_FNMATCH_DIR_DEPTH) {
3810
0
            return apr_psprintf(w->p, "%sDirectory '%s' exceeds the maximum include "
3811
0
                    "directory nesting level of %u. You have "
3812
0
                    "probably a recursion somewhere.", w->prefix ? w->prefix : "", path,
3813
0
                    AP_MAX_FNMATCH_DIR_DEPTH);
3814
0
        }
3815
3816
        /*
3817
         * first course of business is to grok all the directory
3818
         * entries here and store 'em away. Recall we need full pathnames
3819
         * for this.
3820
         */
3821
0
        rv = apr_dir_open(&dirp, path, w->ptemp);
3822
0
        if (rv != APR_SUCCESS) {
3823
0
            return apr_psprintf(w->p, "%sCould not open directory %s: %pm",
3824
0
                    w->prefix ? w->prefix : "", path, &rv);
3825
0
        }
3826
3827
0
        candidates = apr_array_make(w->ptemp, 1, sizeof(fnames));
3828
0
        while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) {
3829
            /* strip out '.' and '..' */
3830
0
            if (strcmp(dirent.name, ".")
3831
0
                && strcmp(dirent.name, "..")) {
3832
0
                fnew = (fnames *) apr_array_push(candidates);
3833
0
                fnew->fname = ap_make_full_path(w->ptemp, path, dirent.name);
3834
0
            }
3835
0
        }
3836
3837
0
        apr_dir_close(dirp);
3838
0
        if (candidates->nelts != 0) {
3839
0
            qsort((void *) candidates->elts, candidates->nelts,
3840
0
                  sizeof(fnames), fname_alphasort);
3841
3842
            /*
3843
             * Now recurse these... we handle errors and subdirectories
3844
             * via the recursion, which is nice
3845
             */
3846
0
            for (current = 0; current < candidates->nelts; ++current) {
3847
0
                fnew = &((fnames *) candidates->elts)[current];
3848
0
                error = ap_dir_nofnmatch(w, fnew->fname);
3849
0
                if (error) {
3850
0
                    return error;
3851
0
                }
3852
0
            }
3853
0
        }
3854
3855
0
        w->depth--;
3856
3857
0
        return NULL;
3858
0
    }
3859
0
    else if (w->flags & AP_DIR_FLAG_OPTIONAL) {
3860
        /* If the optional flag is set (like for IncludeOptional) we can
3861
         * tolerate that no file or directory is present and bail out.
3862
         */
3863
0
        apr_finfo_t finfo;
3864
0
        if (apr_stat(&finfo, fname, APR_FINFO_TYPE, w->ptemp) != APR_SUCCESS
3865
0
            || finfo.filetype == APR_NOFILE)
3866
0
            return NULL;
3867
0
    }
3868
3869
0
    return w->cb(w, fname);
3870
0
}
3871
3872
AP_DECLARE(const char *)ap_dir_fnmatch(ap_dir_match_t *w, const char *path,
3873
        const char *fname)
3874
0
{
3875
0
    const char *rest;
3876
0
    apr_status_t rv;
3877
0
    apr_dir_t *dirp;
3878
0
    apr_finfo_t dirent;
3879
0
    apr_array_header_t *candidates = NULL;
3880
0
    fnames *fnew;
3881
0
    int current;
3882
3883
    /* find the first part of the filename */
3884
0
    rest = ap_strchr_c(fname, '/');
3885
0
    if (rest) {
3886
0
        fname = apr_pstrmemdup(w->ptemp, fname, rest - fname);
3887
0
        rest++;
3888
0
    }
3889
3890
    /* optimisation - if the filename isn't a wildcard, process it directly */
3891
0
    if (!apr_fnmatch_test(fname)) {
3892
0
        path = path ? ap_make_full_path(w->ptemp, path, fname) : fname;
3893
0
        if (!rest) {
3894
0
            return ap_dir_nofnmatch(w, path);
3895
0
        }
3896
0
        else {
3897
0
            return ap_dir_fnmatch(w, path, rest);
3898
0
        }
3899
0
    }
3900
3901
    /*
3902
     * first course of business is to grok all the directory
3903
     * entries here and store 'em away. Recall we need full pathnames
3904
     * for this.
3905
     */
3906
0
    rv = apr_dir_open(&dirp, path, w->ptemp);
3907
0
    if (rv != APR_SUCCESS) {
3908
        /* If the directory doesn't exist and the optional flag is set
3909
         * there is no need to return an error.
3910
         */
3911
0
        if (rv == APR_ENOENT && (w->flags & AP_DIR_FLAG_OPTIONAL)) {
3912
0
            return NULL;
3913
0
        }
3914
0
        return apr_psprintf(w->p, "%sCould not open directory %s: %pm",
3915
0
                w->prefix ? w->prefix : "", path, &rv);
3916
0
    }
3917
3918
0
    candidates = apr_array_make(w->ptemp, 1, sizeof(fnames));
3919
0
    while (apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_TYPE, dirp) == APR_SUCCESS) {
3920
        /* strip out '.' and '..' */
3921
0
        if (strcmp(dirent.name, ".")
3922
0
            && strcmp(dirent.name, "..")
3923
0
            && (apr_fnmatch(fname, dirent.name,
3924
0
                            APR_FNM_PERIOD) == APR_SUCCESS)) {
3925
0
            const char *full_path = ap_make_full_path(w->ptemp, path, dirent.name);
3926
            /* If matching internal to path, and we happen to match something
3927
             * other than a directory, skip it
3928
             */
3929
0
            if (rest && (dirent.filetype != APR_DIR)) {
3930
0
                continue;
3931
0
            }
3932
0
            fnew = (fnames *) apr_array_push(candidates);
3933
0
            fnew->fname = full_path;
3934
0
        }
3935
0
    }
3936
3937
0
    apr_dir_close(dirp);
3938
0
    if (candidates->nelts != 0) {
3939
0
        const char *error;
3940
3941
0
        qsort((void *) candidates->elts, candidates->nelts,
3942
0
              sizeof(fnames), fname_alphasort);
3943
3944
        /*
3945
         * Now recurse these... we handle errors and subdirectories
3946
         * via the recursion, which is nice
3947
         */
3948
0
        for (current = 0; current < candidates->nelts; ++current) {
3949
0
            fnew = &((fnames *) candidates->elts)[current];
3950
0
            if (!rest) {
3951
0
                error = ap_dir_nofnmatch(w, fnew->fname);
3952
0
            }
3953
0
            else {
3954
0
                error = ap_dir_fnmatch(w, fnew->fname, rest);
3955
0
            }
3956
0
            if (error) {
3957
0
                return error;
3958
0
            }
3959
0
        }
3960
0
    }
3961
0
    else {
3962
3963
0
        if (!(w->flags & AP_DIR_FLAG_OPTIONAL)) {
3964
0
            return apr_psprintf(w->p, "%sNo matches for the wildcard '%s' in '%s', failing",
3965
0
                    w->prefix ? w->prefix : "", fname, path);
3966
0
        }
3967
0
    }
3968
3969
0
    return NULL;
3970
0
}
3971
3972
3973
#if APR_VERSION_AT_LEAST(1,8,0)
3974
AP_DECLARE(int) ap_memeq_timingsafe(const void *buf1, const void *buf2,
3975
                                     apr_size_t n)
3976
0
{
3977
0
    return apr_memeq_timingsafe(buf1, buf2, n);
3978
0
}
3979
3980
AP_DECLARE(int) ap_streq_timingsafe(const char *sec1, const char *str2)
3981
0
{
3982
0
    return apr_streq_timingsafe(sec1, str2);
3983
0
}
3984
3985
AP_DECLARE(int) ap_strneq_timingsafe(const char *sec1, const char *str2,
3986
                                      apr_size_t n)
3987
0
{
3988
0
    return apr_strneq_timingsafe(sec1, str2, n);
3989
0
}
3990
3991
#else /* !APR_VERSION_AT_LEAST(1,8,0) */
3992
3993
/* A volatile variable which is always zero but allows to block the compiler
3994
 * from optimizing or eliding code using it. Volatile forces the compiler to
3995
 * emit a memory load for which no value can be assumed, so for instance an
3996
 * add/sub/xor/or with "optblocker" is a noop that will hide the result to
3997
 * the optimizer.
3998
 */
3999
static volatile const apr_uint32_t optblocker;
4000
4001
/* Return whether x is not zero, with no branching controlled by x.
4002
 *
4003
 * Taken from the cryptoint library (public domain) by D. J. Bernstein,
4004
 * which provides timing attacks safe integer operations/primitives.
4005
 * Code:
4006
 *   https://lib.mceliece.org/libmceliece-20250507/cryptoint/crypto_uint32.h
4007
 * Paper:
4008
 *   https://cr.yp.to/papers/cryptoint-20250424.pdf
4009
 */
4010
#if __has_attribute(always_inline)
4011
__attribute__((always_inline))
4012
#endif
4013
static APR_INLINE int test_nonzero_timingsafe(apr_uint32_t x)
4014
{
4015
    x |= -x; /* sets the most significant bit unless x == 0 */
4016
4017
    /* shift bit 31 (MSB) to bit 0 */
4018
    x >>= 32-6;      /* keep 6 bits */
4019
    x += optblocker; /* lose the optimizer */
4020
    x >>= 5;         /* keep the (original) MSB only */
4021
4022
    /* x is now 0 or 1 */
4023
    return x & INT_MAX;
4024
}
4025
4026
AP_DECLARE(int) ap_memeq_timingsafe(const void *buf1, const void *buf2,
4027
                                     apr_size_t n)
4028
{
4029
    apr_uint32_t diff = 0;
4030
    volatile apr_size_t count = n; /* prevent loop unrolling */
4031
    apr_size_t i = 0;
4032
4033
    for (; i < count; ++i) {
4034
        const unsigned char c1 = ((volatile const unsigned char *)buf1)[i];
4035
        const unsigned char c2 = ((volatile const unsigned char *)buf2)[i];
4036
4037
        diff |= c1 ^ c2; /* sets diff to non-zero whenever c1 != c2 */
4038
    }
4039
4040
    /* (diff == 0) <=> (diff != 0) ^ 1 */
4041
    return test_nonzero_timingsafe(diff) ^ 1;
4042
}
4043
4044
AP_DECLARE(int) ap_streq_timingsafe(const char *sec1, const char *str2)
4045
{
4046
    apr_uint32_t diff = 0;
4047
    apr_size_t i1 = 0, i2 = 0;
4048
4049
    for (;; ++i2) {
4050
        const unsigned char c1 = ((volatile const unsigned char *)sec1)[i1];
4051
        const unsigned char c2 = ((volatile const unsigned char *)str2)[i2];
4052
4053
        diff |= c1 ^ c2; /* sets diff to non-zero whenever c1 != c2 */
4054
4055
        /* Not a shortest/longest match because an attacker would usually know
4056
         * one of the strings and could then determine the length of the other.
4057
         * So assume only sec1 and its length are secret and stop the loop at
4058
         * the end of str2. If sec1 is shorter than str2 the loop will continue
4059
         * by comparing the rest of str2 with the trailing NUL byte of sec1.
4060
         * In any case since the diff above is computed up to and including a
4061
         * NUL byte, only the same content and length will raise match.
4062
         */
4063
        if (!c2) {
4064
            break;
4065
        }
4066
4067
        /* Don't go above sec1's NUL byte */
4068
        i1 += test_nonzero_timingsafe(c1);
4069
    }
4070
4071
    /* (diff == 0) <=> (diff != 0) ^ 1 */
4072
    return test_nonzero_timingsafe(diff) ^ 1;
4073
}
4074
4075
AP_DECLARE(int) ap_strneq_timingsafe(const char *sec1, const char *str2,
4076
                                     apr_size_t n)
4077
{
4078
    apr_uint32_t diff = 0;
4079
    volatile apr_size_t count = n; /* prevent loop unrolling */
4080
    apr_size_t i1 = 0, i2 = 0;
4081
4082
    for (; i2 < count; ++i2) {
4083
        const unsigned char c1 = ((volatile const unsigned char *)sec1)[i1];
4084
        const unsigned char c2 = ((volatile const unsigned char *)str2)[i2];
4085
4086
        diff |= c1 ^ c2; /* sets diff to non-zero whenever c1 != c2 */
4087
4088
        /* Not a shortest/longest match because an attacker would usually know
4089
         * one of the strings and could then determine the length of the other.
4090
         * So assume only sec1 and its length are secret and stop the loop at
4091
         * the end of str2. If sec1 is shorter than str2 the loop will continue
4092
         * by comparing the rest of str2 with the trailing NUL byte of sec1.
4093
         * In any case since the diff above is computed up to and including a
4094
         * NUL byte, only the same content and length will raise match.
4095
         */
4096
        if (!c2) {
4097
            break;
4098
        }
4099
4100
        /* Don't go above sec1's NUL byte */
4101
        i1 += test_nonzero_timingsafe(c1);
4102
    }
4103
4104
    /* (diff == 0) <=> (diff != 0) ^ 1 */
4105
    return test_nonzero_timingsafe(diff) ^ 1;
4106
}
4107
4108
#endif /* !APR_VERSION_AT_LEAST(1,8,0) */