Coverage Report

Created: 2025-07-11 06:40

/src/httpd/server/util.c
Line
Count
Source (jump to first uncovered line)
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
 * contributor license agreements.  See the NOTICE file distributed with
3
 * this work for additional information regarding copyright ownership.
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * (the "License"); you may not use this file except in compliance with
6
 * the License.  You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
/*
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.25k
{
95
1.25k
    const char *semi;
96
97
1.25k
    if (intype == NULL) return NULL;
98
99
1.25k
    semi = ap_strchr_c(intype, ';');
100
1.25k
    if (semi == NULL) {
101
1.16k
        return apr_pstrdup(p, intype);
102
1.16k
    }
103
89
    else {
104
219
        while ((semi > intype) && apr_isspace(semi[-1])) {
105
130
            semi--;
106
130
        }
107
89
        return apr_pstrmemdup(p, intype, semi - intype);
108
89
    }
109
1.25k
}
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
4.78k
{
179
4.78k
    apr_size_t x, y;
180
181
7.61k
    for (x = 0, y = 0; expected[y]; ++y, ++x) {
182
7.05k
        if (expected[y] == '*') {
183
1.03k
            while (expected[++y] == '*');
184
568
            if (!expected[y])
185
5
                return 0;
186
3.58k
            while (str[x]) {
187
3.53k
                int ret;
188
3.53k
                if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1)
189
510
                    return ret;
190
3.53k
            }
191
53
            return -1;
192
563
        }
193
6.48k
        else if (!str[x])
194
14
            return -1;
195
6.47k
        else if ((expected[y] != '?') && (str[x] != expected[y]))
196
3.64k
            return 1;
197
7.05k
    }
198
555
    return (str[x] != '\0');
199
4.78k
}
200
201
AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
202
4.78k
{
203
4.78k
    apr_size_t x, y;
204
205
7.61k
    for (x = 0, y = 0; expected[y]; ++y, ++x) {
206
7.05k
        if (!str[x] && expected[y] != '*')
207
14
            return -1;
208
7.04k
        if (expected[y] == '*') {
209
1.03k
            while (expected[++y] == '*');
210
568
            if (!expected[y])
211
5
                return 0;
212
3.58k
            while (str[x]) {
213
3.53k
                int ret;
214
3.53k
                if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1)
215
510
                    return ret;
216
3.53k
            }
217
53
            return -1;
218
563
        }
219
6.47k
        else if (expected[y] != '?'
220
6.47k
                 && apr_tolower(str[x]) != apr_tolower(expected[y]))
221
3.64k
            return 1;
222
7.04k
    }
223
555
    return (str[x] != '\0');
224
4.78k
}
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
5.98k
{
260
5.98k
    ap_regfree((ap_regex_t *) preg);
261
5.98k
    return APR_SUCCESS;
262
5.98k
}
263
264
AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
265
                                     int cflags)
266
5.99k
{
267
5.99k
    ap_regex_t *preg = apr_palloc(p, sizeof *preg);
268
5.99k
    int err = ap_regcomp(preg, pattern, cflags);
269
5.99k
    if (err) {
270
1
        if (err == AP_REG_ESPACE)
271
0
            ap_abort_on_oom();
272
1
        return NULL;
273
1
    }
274
275
5.98k
    apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
276
5.98k
                              apr_pool_cleanup_null);
277
278
5.98k
    return preg;
279
5.99k
}
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.25k
{
293
1.25k
    char *p1, *p2;
294
1.25k
    if (*s2 == '\0') {
295
        /* an empty s2 */
296
192
        return((char *)s1);
297
192
    }
298
11.6k
    while(1) {
299
49.3k
        for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
300
11.6k
        if (*s1 == '\0') {
301
1.01k
            return(NULL);
302
1.01k
        }
303
        /* found first character of s2, see if the rest matches */
304
10.5k
        p1 = (char *)s1;
305
10.5k
        p2 = (char *)s2;
306
68.5k
        for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
307
57.9k
            if (*p1 == '\0') {
308
                /* both strings ended together */
309
12
                return((char *)s1);
310
12
            }
311
57.9k
        }
312
10.5k
        if (*p2 == '\0') {
313
            /* second string ended, a match */
314
31
            break;
315
31
        }
316
        /* didn't find a match here, try starting at next character in s1 */
317
10.5k
        s1++;
318
10.5k
    }
319
31
    return((char *)s1);
320
1.05k
}
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
915
#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
383
{
493
383
    int ret = 1;
494
383
    apr_size_t l = 1, w = 1, n;
495
383
    int decode_unreserved = (flags & AP_NORMALIZE_DECODE_UNRESERVED) != 0;
496
383
    int merge_slashes = (flags & AP_NORMALIZE_MERGE_SLASHES) != 0;
497
498
383
    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
369
        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
368
        if (!(flags & AP_NORMALIZE_ALLOW_RELATIVE) || path[0] == '\0') {
509
49
            return 0;
510
49
        }
511
512
319
        l = w = 0;
513
319
    }
514
515
15.0k
    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
14.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
14.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
585
                if (IS_SLASH_OR_NUL(path[l + 1])) {
551
174
                    l++;
552
174
                    if (path[l]) {
553
172
                        l++;
554
172
                    }
555
174
                    continue;
556
174
                }
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
411
                n = l + 1;
563
411
                if ((path[n] == '.' || (decode_unreserved
564
81
                                        && path[n] == '%'
565
81
                                        && path[++n] == '2'
566
81
                                        && (path[++n] == 'e'
567
0
                                            || path[n] == 'E')))
568
411
                        && IS_SLASH_OR_NUL(path[n + 1])) {
569
                    /* Wind w back to remove the previous segment */
570
230
                    if (w > 1) {
571
902
                        do {
572
902
                            w--;
573
902
                        } while (w && !AP_IS_SLASH(path[w - 1]));
574
146
                    }
575
84
                    else {
576
                        /* Already at root, ignore and return a failure
577
                         * if asked to.
578
                         */
579
84
                        if (flags & AP_NORMALIZE_NOT_ABOVE_ROOT) {
580
84
                            ret = 0;
581
84
                        }
582
84
                    }
583
584
                    /* Move l forward to the next segment */
585
230
                    l = n + 1;
586
230
                    if (path[l]) {
587
226
                        l++;
588
226
                    }
589
230
                    continue;
590
230
                }
591
411
            }
592
1.35k
        }
593
594
14.2k
        path[w++] = path[l++];
595
14.2k
    }
596
333
    path[w] = '\0';
597
598
333
    return ret;
599
383
}
600
601
/*
602
 * Parse .. so we don't compromise security
603
 */
604
AP_DECLARE(void) ap_getparents(char *name)
605
383
{
606
383
    if (!ap_normalize_path(name, AP_NORMALIZE_NOT_ABOVE_ROOT |
607
383
                                 AP_NORMALIZE_ALLOW_RELATIVE)) {
608
68
        name[0] = '\0';
609
68
    }
610
383
}
611
612
AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path)
613
313
{
614
615
313
    char *d, *s;
616
617
313
    if (!*name) {
618
40
        return;
619
40
    }
620
621
273
    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
11.7k
    while (*s) {
630
11.4k
        if ((*d++ = *s) == '/') {
631
479
            do {
632
479
                ++s;
633
479
            } while (*s == '/');
634
198
        }
635
11.2k
        else {
636
11.2k
            ++s;
637
11.2k
        }
638
11.4k
    }
639
273
    *d = '\0';
640
273
}
641
642
AP_DECLARE(void) ap_no2slash(char *name)
643
313
{
644
313
    ap_no2slash_ex(name, 1);
645
313
}
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
203
{
696
203
    const char *last_slash = ap_strrchr_c(s, '/');
697
203
    char *d;
698
203
    int l;
699
700
203
    if (last_slash == NULL) {
701
189
        return apr_pstrdup(p, "");
702
189
    }
703
14
    l = (last_slash - s) + 1;
704
14
    d = apr_pstrmemdup(p, s, l);
705
706
14
    return (d);
707
203
}
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.25k
{
727
1.25k
    const char *pos = *line;
728
1.25k
    int len;
729
1.25k
    char *res;
730
731
56.3k
    while ((*pos != stop) && *pos) {
732
55.0k
        ++pos;
733
55.0k
    }
734
735
1.25k
    len = pos - *line;
736
1.25k
    res = apr_pstrmemdup(atrans, *line, len);
737
738
1.25k
    if (stop) {
739
0
        while (*pos == stop) {
740
0
            ++pos;
741
0
        }
742
0
    }
743
1.25k
    *line = pos;
744
745
1.25k
    return res;
746
1.25k
}
747
748
AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
749
174
{
750
174
    return ap_getword_white(atrans, (const char **) line);
751
174
}
752
753
AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
754
174
{
755
174
    const char *pos = *line;
756
174
    int len;
757
174
    char *res;
758
759
3.48k
    while (!apr_isspace(*pos) && *pos) {
760
3.31k
        ++pos;
761
3.31k
    }
762
763
174
    len = pos - *line;
764
174
    res = apr_pstrmemdup(atrans, *line, len);
765
766
744
    while (apr_isspace(*pos)) {
767
570
        ++pos;
768
570
    }
769
770
174
    *line = pos;
771
772
174
    return res;
773
174
}
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.23k
{
810
1.23k
    char *result = apr_palloc(p, len + 1);
811
1.23k
    char *resp = result;
812
1.23k
    int i;
813
814
33.4k
    for (i = 0; i < len; ++i) {
815
32.2k
        if (start[i] == '\\' && (start[i + 1] == '\\'
816
1.57k
                                 || (quote && start[i + 1] == quote)))
817
868
            *resp++ = start[++i];
818
31.3k
        else
819
31.3k
            *resp++ = start[i];
820
32.2k
    }
821
822
1.23k
    *resp++ = '\0';
823
#if RESOLVE_ENV_PER_TOKEN
824
    return (char *)ap_resolve_env(p,result);
825
#else
826
1.23k
    return result;
827
1.23k
#endif
828
1.23k
}
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
113
{
837
113
    const char *str = *line, *strend;
838
113
    char *res;
839
113
    char quote;
840
841
351
    while (apr_isspace(*str))
842
238
        ++str;
843
844
113
    if (!*str) {
845
0
        *line = str;
846
0
        return "";
847
0
    }
848
849
113
    if ((quote = *str) == '"' || quote == '\'') {
850
113
        strend = str + 1;
851
3.64k
        while (*strend && *strend != quote) {
852
3.53k
            if (*strend == '\\' && strend[1] &&
853
3.53k
                (strend[1] == quote || strend[1] == '\\')) {
854
311
                strend += 2;
855
311
            }
856
3.22k
            else {
857
3.22k
                ++strend;
858
3.22k
            }
859
3.53k
        }
860
113
        res = substring_conf(p, str + 1, strend - str - 1, quote);
861
862
113
        if (*strend == quote)
863
44
            ++strend;
864
113
    }
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
323
    while (apr_isspace(*strend))
874
210
        ++strend;
875
113
    *line = strend;
876
113
    return res;
877
113
}
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.25k
{
886
1.25k
    const char *str = *line, *strend;
887
1.25k
    char *res;
888
1.25k
    char quote;
889
1.25k
    int count = 1;
890
891
2.82k
    while (apr_isspace(*str))
892
1.57k
        ++str;
893
894
1.25k
    if (!*str) {
895
19
        *line = str;
896
19
        return "";
897
19
    }
898
899
1.23k
    if ((quote = *str) == '"' || quote == '\'')
900
113
        return ap_getword_conf(p, line);
901
902
1.11k
    if (quote == '{') {
903
76
        strend = str + 1;
904
3.33k
        while (*strend) {
905
3.26k
            if (*strend == '}' && !--count)
906
6
                break;
907
3.25k
            if (*strend == '{')
908
368
                ++count;
909
3.25k
            if (*strend == '\\' && strend[1] == '\\') {
910
215
                ++strend;
911
215
            }
912
3.25k
            ++strend;
913
3.25k
        }
914
76
        res = substring_conf(p, str + 1, strend - str - 1, 0);
915
916
76
        if (*strend == '}')
917
6
            ++strend;
918
76
    }
919
1.04k
    else {
920
1.04k
        strend = str;
921
26.7k
        while (*strend && !apr_isspace(*strend))
922
25.7k
            ++strend;
923
924
1.04k
        res = substring_conf(p, str, strend - str, 0);
925
1.04k
    }
926
927
2.90k
    while (apr_isspace(*strend))
928
1.78k
        ++strend;
929
1.11k
    *line = strend;
930
1.11k
    return res;
931
1.23k
}
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
15.9k
{
950
15.9k
    return apr_file_getc(ch, param);
951
15.9k
}
952
953
static apr_status_t cfg_getstr(void *buf, apr_size_t bufsiz, void *param)
954
756k
{
955
756k
    return apr_file_gets(buf, bufsiz, param);
956
756k
}
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.25k
{
962
1.25k
    ap_configfile_t *new_cfg;
963
1.25k
    apr_file_t *file = NULL;
964
1.25k
    apr_finfo_t finfo;
965
1.25k
    apr_status_t status;
966
#ifdef DEBUG
967
    char buf[120];
968
#endif
969
970
1.25k
    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.25k
    status = apr_file_open(&file, name, APR_READ | APR_BUFFERED,
977
1.25k
                           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.25k
    if (status != APR_SUCCESS)
985
0
        return status;
986
987
1.25k
    status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file);
988
1.25k
    if (status != APR_SUCCESS)
989
0
        return status;
990
991
1.25k
    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
1.25k
        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.25k
    new_cfg = apr_palloc(p, sizeof(*new_cfg));
1028
1.25k
    new_cfg->param = file;
1029
1.25k
    new_cfg->name = apr_pstrdup(p, name);
1030
1.25k
    new_cfg->getch = cfg_getch;
1031
1.25k
    new_cfg->getstr = cfg_getstr;
1032
1.25k
    new_cfg->close = cfg_close;
1033
1.25k
    new_cfg->line_number = 0;
1034
1.25k
    *ret_cfg = new_cfg;
1035
1.25k
    return APR_SUCCESS;
1036
1.25k
}
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.25k
{
1084
1.25k
    apr_status_t rc;
1085
    /* If a "get string" function is defined, use it */
1086
1.25k
    if (cfp->getstr != NULL) {
1087
1.13k
        char *cp;
1088
1.13k
        char *cbuf = buf + offset;
1089
1.13k
        apr_size_t cbufsize = bufsize - offset;
1090
1091
756k
        while (1) {
1092
756k
            ++cfp->line_number;
1093
756k
            rc = cfp->getstr(cbuf, cbufsize, cfp->param);
1094
756k
            if (rc == APR_EOF) {
1095
14
                if (cbuf != buf + offset) {
1096
11
                    *cbuf = '\0';
1097
11
                    break;
1098
11
                }
1099
3
                else {
1100
3
                    return APR_EOF;
1101
3
                }
1102
14
            }
1103
756k
            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
756k
            cp = cbuf;
1112
756k
            cp += strlen(cp);
1113
756k
            if (cp > buf && cp[-1] == LF) {
1114
755k
                cp--;
1115
755k
                if (cp > buf && cp[-1] == CR)
1116
718
                    cp--;
1117
755k
                if (cp > buf && cp[-1] == '\\') {
1118
755k
                    cp--;
1119
                    /*
1120
                     * line continuation requested -
1121
                     * then remove backslash and continue
1122
                     */
1123
755k
                    cbufsize -= (cp-cbuf);
1124
755k
                    cbuf = cp;
1125
755k
                    continue;
1126
755k
                }
1127
755k
            }
1128
949
            else if (cp - buf >= bufsize - 1) {
1129
157
                return APR_ENOSPC;
1130
157
            }
1131
967
            break;
1132
756k
        }
1133
1.13k
    } else {
1134
        /* No "get string" function defined; read character by character */
1135
112
        apr_size_t i = offset;
1136
1137
112
        if (bufsize < 2) {
1138
            /* too small, assume caller is crazy */
1139
0
            return APR_EINVAL;
1140
0
        }
1141
112
        buf[offset] = '\0';
1142
1143
15.9k
        while (1) {
1144
15.9k
            char c;
1145
15.9k
            rc = cfp->getch(&c, cfp->param);
1146
15.9k
            if (rc == APR_EOF) {
1147
11
                if (i > offset)
1148
11
                    break;
1149
0
                else
1150
0
                    return APR_EOF;
1151
11
            }
1152
15.9k
            if (rc != APR_SUCCESS)
1153
0
                return rc;
1154
15.9k
            if (c == LF) {
1155
4.21k
                ++cfp->line_number;
1156
                /* check for line continuation */
1157
4.21k
                if (i > 0 && buf[i-1] == '\\') {
1158
4.16k
                    i--;
1159
4.16k
                    continue;
1160
4.16k
                }
1161
46
                else {
1162
46
                    break;
1163
46
                }
1164
4.21k
            }
1165
11.7k
            buf[i] = c;
1166
11.7k
            ++i;
1167
11.7k
            if (i >= bufsize - 1) {
1168
55
                return APR_ENOSPC;
1169
55
            }
1170
11.7k
        }
1171
57
        buf[i] = '\0';
1172
57
    }
1173
1.03k
    return APR_SUCCESS;
1174
1.25k
}
1175
1176
static int cfg_trim_line(char *buf)
1177
1.03k
{
1178
1.03k
    char *start, *end;
1179
    /*
1180
     * Leading and trailing white space is eliminated completely
1181
     */
1182
1.03k
    start = buf;
1183
2.32k
    while (apr_isspace(*start))
1184
1.28k
        ++start;
1185
    /* blast trailing whitespace */
1186
1.03k
    end = &start[strlen(start)];
1187
1.55k
    while (--end >= start && apr_isspace(*end))
1188
516
        *end = '\0';
1189
    /* Zap leading whitespace by shifting */
1190
1.03k
    if (start != buf)
1191
232
        memmove(buf, start, end - start + 2);
1192
#ifdef DEBUG_CFG_LINES
1193
    ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, APLOGNO(00555) "Read config: '%s'", buf);
1194
#endif
1195
1.03k
    return end - start + 1;
1196
1.03k
}
1197
1198
/* Read one line from open ap_configfile_t, strip LF, increase line number */
1199
/* If custom handler does not define a getstr() function, read char by char */
1200
AP_DECLARE(apr_status_t) ap_cfg_getline(char *buf, apr_size_t bufsize,
1201
                                        ap_configfile_t *cfp)
1202
1.25k
{
1203
1.25k
    apr_status_t rc = ap_cfg_getline_core(buf, bufsize, 0, cfp);
1204
1.25k
    if (rc == APR_SUCCESS)
1205
1.03k
        cfg_trim_line(buf);
1206
1.25k
    return rc;
1207
1.25k
}
1208
1209
AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb,
1210
                                               ap_configfile_t *cfp,
1211
                                               apr_size_t max_len)
1212
0
{
1213
0
    apr_status_t rc;
1214
0
    apr_size_t new_len;
1215
0
    vb->strlen = 0;
1216
0
    *vb->buf = '\0';
1217
1218
0
    if (vb->strlen == AP_VARBUF_UNKNOWN)
1219
0
        vb->strlen = strlen(vb->buf);
1220
0
    if (vb->avail - vb->strlen < 3) {
1221
0
        new_len = vb->avail * 2;
1222
0
        if (new_len > max_len)
1223
0
            new_len = max_len;
1224
0
        else if (new_len < 3)
1225
0
            new_len = 3;
1226
0
        ap_varbuf_grow(vb, new_len);
1227
0
    }
1228
1229
0
    for (;;) {
1230
0
        rc = ap_cfg_getline_core(vb->buf, vb->avail, vb->strlen, cfp);
1231
0
        if (rc == APR_ENOSPC || rc == APR_SUCCESS)
1232
0
            vb->strlen += strlen(vb->buf + vb->strlen);
1233
0
        if (rc != APR_ENOSPC)
1234
0
            break;
1235
0
        if (vb->avail >= max_len)
1236
0
            return APR_ENOSPC;
1237
0
        new_len = vb->avail * 2;
1238
0
        if (new_len > max_len)
1239
0
            new_len = max_len;
1240
0
        ap_varbuf_grow(vb, new_len);
1241
0
        --cfp->line_number;
1242
0
    }
1243
0
    if (vb->strlen > max_len)
1244
0
        return APR_ENOSPC;
1245
0
    if (rc == APR_SUCCESS)
1246
0
        vb->strlen = cfg_trim_line(vb->buf);
1247
0
    return rc;
1248
0
}
1249
1250
/* Size an HTTP header field list item, as separated by a comma.
1251
 * The return value is a pointer to the beginning of the non-empty list item
1252
 * within the original string (or NULL if there is none) and the address
1253
 * of field is shifted to the next non-comma, non-whitespace character.
1254
 * len is the length of the item excluding any beginning whitespace.
1255
 */
1256
AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len)
1257
1.25k
{
1258
1.25k
    const unsigned char *ptr = (const unsigned char *)*field;
1259
1.25k
    const unsigned char *token;
1260
1.25k
    int in_qpair, in_qstr, in_com;
1261
1262
    /* Find first non-comma, non-whitespace byte */
1263
1264
3.06k
    while (*ptr == ',' || apr_isspace(*ptr))
1265
1.81k
        ++ptr;
1266
1267
1.25k
    token = ptr;
1268
1269
    /* Find the end of this item, skipping over dead bits */
1270
1271
1.25k
    for (in_qpair = in_qstr = in_com = 0;
1272
43.7k
         *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1273
42.4k
         ++ptr) {
1274
1275
42.4k
        if (in_qpair) {
1276
2.60k
            in_qpair = 0;
1277
2.60k
        }
1278
39.8k
        else {
1279
39.8k
            switch (*ptr) {
1280
2.62k
                case '\\': in_qpair = 1;      /* quoted-pair         */
1281
2.62k
                           break;
1282
956
                case '"' : if (!in_com)       /* quoted string delim */
1283
746
                               in_qstr = !in_qstr;
1284
956
                           break;
1285
1.12k
                case '(' : if (!in_qstr)      /* comment (may nest)  */
1286
913
                               ++in_com;
1287
1.12k
                           break;
1288
498
                case ')' : if (in_com)        /* end comment         */
1289
203
                               --in_com;
1290
498
                           break;
1291
34.6k
                default  : break;
1292
39.8k
            }
1293
39.8k
        }
1294
42.4k
    }
1295
1296
1.25k
    if ((*len = (ptr - token)) == 0) {
1297
21
        *field = (const char *)ptr;
1298
21
        return NULL;
1299
21
    }
1300
1301
    /* Advance field pointer to the next non-comma, non-white byte */
1302
1303
1.95k
    while (*ptr == ',' || apr_isspace(*ptr))
1304
724
        ++ptr;
1305
1306
1.22k
    *field = (const char *)ptr;
1307
1.22k
    return (const char *)token;
1308
1.25k
}
1309
1310
/* Retrieve an HTTP header field list item, as separated by a comma,
1311
 * while stripping insignificant whitespace and lowercasing anything not in
1312
 * a quoted string or comment.  The return value is a new string containing
1313
 * the converted list item (or NULL if none) and the address pointed to by
1314
 * field is shifted to the next non-comma, non-whitespace.
1315
 */
1316
AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field)
1317
1.25k
{
1318
1.25k
    const char *tok_start;
1319
1.25k
    const unsigned char *ptr;
1320
1.25k
    unsigned char *pos;
1321
1.25k
    char *token;
1322
1.25k
    int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
1323
1324
    /* Find the beginning and maximum length of the list item so that
1325
     * we can allocate a buffer for the new string and reset the field.
1326
     */
1327
1.25k
    if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
1328
21
        return NULL;
1329
21
    }
1330
1.22k
    token = apr_palloc(p, tok_len + 1);
1331
1332
    /* Scan the token again, but this time copy only the good bytes.
1333
     * We skip extra whitespace and any whitespace around a '=', '/',
1334
     * or ';' and lowercase normal characters not within a comment,
1335
     * quoted-string or quoted-pair.
1336
     */
1337
1.22k
    for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
1338
43.6k
         *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1339
42.4k
         ++ptr) {
1340
1341
42.4k
        if (in_qpair) {
1342
2.60k
            in_qpair = 0;
1343
2.60k
            *pos++ = *ptr;
1344
2.60k
        }
1345
39.8k
        else {
1346
39.8k
            switch (*ptr) {
1347
2.62k
                case '\\': in_qpair = 1;
1348
2.62k
                           if (addspace == 1)
1349
66
                               *pos++ = ' ';
1350
2.62k
                           *pos++ = *ptr;
1351
2.62k
                           addspace = 0;
1352
2.62k
                           break;
1353
956
                case '"' : if (!in_com)
1354
746
                               in_qstr = !in_qstr;
1355
956
                           if (addspace == 1)
1356
55
                               *pos++ = ' ';
1357
956
                           *pos++ = *ptr;
1358
956
                           addspace = 0;
1359
956
                           break;
1360
1.12k
                case '(' : if (!in_qstr)
1361
913
                               ++in_com;
1362
1.12k
                           if (addspace == 1)
1363
68
                               *pos++ = ' ';
1364
1.12k
                           *pos++ = *ptr;
1365
1.12k
                           addspace = 0;
1366
1.12k
                           break;
1367
498
                case ')' : if (in_com)
1368
203
                               --in_com;
1369
498
                           *pos++ = *ptr;
1370
498
                           addspace = 0;
1371
498
                           break;
1372
2.12k
                case ' ' :
1373
3.49k
                case '\t': if (addspace)
1374
1.86k
                               break;
1375
1.63k
                           if (in_com || in_qstr)
1376
866
                               *pos++ = *ptr;
1377
764
                           else
1378
764
                               addspace = 1;
1379
1.63k
                           break;
1380
305
                case '=' :
1381
858
                case '/' :
1382
1.15k
                case ';' : if (!(in_com || in_qstr))
1383
700
                               addspace = -1;
1384
1.15k
                           *pos++ = *ptr;
1385
1.15k
                           break;
1386
30.0k
                default  : if (addspace == 1)
1387
482
                               *pos++ = ' ';
1388
30.0k
                           *pos++ = (in_com || in_qstr) ? *ptr
1389
30.0k
                                                        : apr_tolower(*ptr);
1390
30.0k
                           addspace = 0;
1391
30.0k
                           break;
1392
39.8k
            }
1393
39.8k
        }
1394
42.4k
    }
1395
1.22k
    *pos = '\0';
1396
1397
1.22k
    return token;
1398
1.22k
}
1399
1400
typedef enum ap_etag_e {
1401
    AP_ETAG_NONE,
1402
    AP_ETAG_WEAK,
1403
    AP_ETAG_STRONG
1404
} ap_etag_e;
1405
1406
/* Find an item in canonical form (lowercase, no extra spaces) within
1407
 * an HTTP field value list.  Returns 1 if found, 0 if not found.
1408
 * This would be much more efficient if we stored header fields as
1409
 * an array of list items as they are received instead of a plain string.
1410
 */
1411
static int find_list_item(apr_pool_t *p, const char *line,
1412
                                  const char *tok, ap_etag_e type)
1413
1.25k
{
1414
1.25k
    const unsigned char *pos;
1415
1.25k
    const unsigned char *ptr = (const unsigned char *)line;
1416
1.25k
    int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
1417
1418
1.25k
    if (!line || !tok) {
1419
0
        return 0;
1420
0
    }
1421
1.25k
    if (type == AP_ETAG_STRONG && *tok != '\"') {
1422
0
        return 0;
1423
0
    }
1424
1.25k
    if (type == AP_ETAG_WEAK) {
1425
0
        if (*tok == 'W' && (*(tok+1)) == '/' && (*(tok+2)) == '\"') {
1426
0
            tok += 2;
1427
0
        }
1428
0
        else if (*tok != '\"') {
1429
0
            return 0;
1430
0
        }
1431
0
    }
1432
1433
2.94k
    do {  /* loop for each item in line's list */
1434
1435
        /* Find first non-comma, non-whitespace byte */
1436
7.50k
        while (*ptr == ',' || apr_isspace(*ptr)) {
1437
4.55k
            ++ptr;
1438
4.55k
        }
1439
1440
        /* Account for strong or weak Etags, depending on our search */
1441
2.94k
        if (type == AP_ETAG_STRONG && *ptr != '\"') {
1442
0
            break;
1443
0
        }
1444
2.94k
        if (type == AP_ETAG_WEAK) {
1445
0
            if (*ptr == 'W' && (*(ptr+1)) == '/' && (*(ptr+2)) == '\"') {
1446
0
                ptr += 2;
1447
0
            }
1448
0
            else if (*ptr != '\"') {
1449
0
                break;
1450
0
            }
1451
0
        }
1452
1453
2.94k
        if (*ptr)
1454
2.89k
            good = 1;  /* until proven otherwise for this item */
1455
48
        else
1456
48
            break;     /* no items left and nothing good found */
1457
1458
        /* We skip extra whitespace and any whitespace around a '=', '/',
1459
         * or ';' and lowercase normal characters not within a comment,
1460
         * quoted-string or quoted-pair.
1461
         */
1462
2.89k
        for (pos = (const unsigned char *)tok;
1463
53.3k
             *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1464
50.4k
             ++ptr) {
1465
1466
50.4k
            if (in_qpair) {
1467
2.92k
                in_qpair = 0;
1468
2.92k
                if (good)
1469
0
                    good = (*pos++ == *ptr);
1470
2.92k
            }
1471
47.5k
            else {
1472
47.5k
                switch (*ptr) {
1473
2.95k
                    case '\\': in_qpair = 1;
1474
2.95k
                               if (addspace == 1)
1475
33
                                   good = good && (*pos++ == ' ');
1476
2.95k
                               good = good && (*pos++ == *ptr);
1477
2.95k
                               addspace = 0;
1478
2.95k
                               break;
1479
1.34k
                    case '"' : if (!in_com)
1480
1.08k
                                   in_qstr = !in_qstr;
1481
1.34k
                               if (addspace == 1)
1482
39
                                   good = good && (*pos++ == ' ');
1483
1.34k
                               good = good && (*pos++ == *ptr);
1484
1.34k
                               addspace = 0;
1485
1.34k
                               break;
1486
1.29k
                    case '(' : if (!in_qstr)
1487
1.07k
                                   ++in_com;
1488
1.29k
                               if (addspace == 1)
1489
34
                                   good = good && (*pos++ == ' ');
1490
1.29k
                               good = good && (*pos++ == *ptr);
1491
1.29k
                               addspace = 0;
1492
1.29k
                               break;
1493
899
                    case ')' : if (in_com)
1494
317
                                   --in_com;
1495
899
                               good = good && (*pos++ == *ptr);
1496
899
                               addspace = 0;
1497
899
                               break;
1498
2.60k
                    case ' ' :
1499
4.24k
                    case '\t': if (addspace || !good)
1500
4.05k
                                   break;
1501
187
                               if (in_com || in_qstr)
1502
0
                                   good = (*pos++ == *ptr);
1503
187
                               else
1504
187
                                   addspace = 1;
1505
187
                               break;
1506
390
                    case '=' :
1507
1.10k
                    case '/' :
1508
1.47k
                    case ';' : if (!(in_com || in_qstr))
1509
970
                                   addspace = -1;
1510
1.47k
                               good = good && (*pos++ == *ptr);
1511
1.47k
                               break;
1512
35.3k
                    default  : if (!good)
1513
32.7k
                                   break;
1514
2.65k
                               if (addspace == 1)
1515
75
                                   good = (*pos++ == ' ');
1516
2.65k
                               if (in_com || in_qstr)
1517
0
                                   good = good && (*pos++ == *ptr);
1518
2.65k
                               else
1519
2.65k
                                   good = good
1520
2.65k
                                       && (apr_tolower(*pos++) == apr_tolower(*ptr));
1521
2.65k
                               addspace = 0;
1522
2.65k
                               break;
1523
47.5k
                }
1524
47.5k
            }
1525
50.4k
        }
1526
2.89k
        if (good && *pos)
1527
166
            good = 0;          /* not good if only a prefix was matched */
1528
1529
2.89k
    } while (*ptr && !good);
1530
1531
1.25k
    return good;
1532
1.25k
}
1533
1534
/* Find an item in canonical form (lowercase, no extra spaces) within
1535
 * an HTTP field value list.  Returns 1 if found, 0 if not found.
1536
 * This would be much more efficient if we stored header fields as
1537
 * an array of list items as they are received instead of a plain string.
1538
 */
1539
AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
1540
                                  const char *tok)
1541
1.25k
{
1542
1.25k
    return find_list_item(p, line, tok, AP_ETAG_NONE);
1543
1.25k
}
1544
1545
/* Find a strong Etag in canonical form (lowercase, no extra spaces) within
1546
 * an HTTP field value list.  Returns 1 if found, 0 if not found.
1547
 */
1548
AP_DECLARE(int) ap_find_etag_strong(apr_pool_t *p, const char *line,
1549
                                    const char *tok)
1550
0
{
1551
0
    return find_list_item(p, line, tok, AP_ETAG_STRONG);
1552
0
}
1553
1554
/* Find a weak ETag in canonical form (lowercase, no extra spaces) within
1555
 * an HTTP field value list.  Returns 1 if found, 0 if not found.
1556
 */
1557
AP_DECLARE(int) ap_find_etag_weak(apr_pool_t *p, const char *line,
1558
                                  const char *tok)
1559
0
{
1560
0
    return find_list_item(p, line, tok, AP_ETAG_WEAK);
1561
0
}
1562
1563
/* Grab a list of tokens of the format 1#token (from RFC7230) */
1564
AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p,
1565
                                                const char *str_in,
1566
                                                apr_array_header_t **tokens,
1567
                                                int skip_invalid)
1568
1.25k
{
1569
1.25k
    int in_leading_space = 1;
1570
1.25k
    int in_trailing_space = 0;
1571
1.25k
    int string_end = 0;
1572
1.25k
    const char *tok_begin;
1573
1.25k
    const char *cur;
1574
1575
1.25k
    if (!str_in) {
1576
0
        return NULL;
1577
0
    }
1578
1579
1.25k
    tok_begin = cur = str_in;
1580
1581
14.1k
    while (!string_end) {
1582
13.9k
        const unsigned char c = (unsigned char)*cur;
1583
1584
13.9k
        if (!TEST_CHAR(c, T_HTTP_TOKEN_STOP)) {
1585
            /* Non-separator character; we are finished with leading
1586
             * whitespace. We must never have encountered any trailing
1587
             * whitespace before the delimiter (comma) */
1588
9.96k
            in_leading_space = 0;
1589
9.96k
            if (in_trailing_space) {
1590
33
                return "Encountered illegal whitespace in token";
1591
33
            }
1592
9.96k
        }
1593
3.95k
        else if (c == ' ' || c == '\t') {
1594
            /* "Linear whitespace" only includes ASCII CRLF, space, and tab;
1595
             * we can't get a CRLF since headers are split on them already,
1596
             * so only look for a space or a tab */
1597
1.84k
            if (in_leading_space) {
1598
                /* We're still in leading whitespace */
1599
1.26k
                ++tok_begin;
1600
1.26k
            }
1601
589
            else {
1602
                /* We must be in trailing whitespace */
1603
589
                ++in_trailing_space;
1604
589
            }
1605
1.84k
        }
1606
2.10k
        else if (c == ',' || c == '\0') {
1607
1.12k
            if (!in_leading_space) {
1608
                /* If we're out of the leading space, we know we've read some
1609
                 * characters of a token */
1610
758
                if (*tokens == NULL) {
1611
258
                    *tokens = apr_array_make(p, 4, sizeof(char *));
1612
258
                }
1613
758
                APR_ARRAY_PUSH(*tokens, char *) =
1614
758
                    apr_pstrmemdup((*tokens)->pool, tok_begin,
1615
758
                                   (cur - tok_begin) - in_trailing_space);
1616
758
            }
1617
            /* We're allowed to have null elements, just don't add them to the
1618
             * array */
1619
1620
1.12k
            tok_begin = cur + 1;
1621
1.12k
            in_leading_space = 1;
1622
1.12k
            in_trailing_space = 0;
1623
1.12k
            string_end = (c == '\0');
1624
1.12k
        }
1625
987
        else {
1626
            /* Encountered illegal separator char */
1627
987
            if (skip_invalid) {
1628
                /* Skip to the next separator */
1629
0
                const char *temp;
1630
0
                temp = ap_strchr_c(cur, ',');
1631
0
                if(!temp) {
1632
0
                    temp = ap_strchr_c(cur, '\0');
1633
0
                }
1634
1635
                /* Act like we haven't seen a token so we reset */
1636
0
                cur = temp - 1;
1637
0
                in_leading_space = 1;
1638
0
                in_trailing_space = 0;
1639
0
            }
1640
987
            else {
1641
987
                return apr_psprintf(p, "Encountered illegal separator "
1642
987
                                    "'\\x%.2x'", (unsigned int)c);
1643
987
            }
1644
987
        }
1645
1646
12.9k
        ++cur;
1647
12.9k
    }
1648
1649
230
    return NULL;
1650
1.25k
}
1651
1652
/* Scan a string for HTTP VCHAR/obs-text characters including HT and SP
1653
 * (as used in header values, for example, in RFC 7230 section 3.2)
1654
 * returning the pointer to the first non-HT ASCII ctrl character.
1655
 */
1656
AP_DECLARE(const char *) ap_scan_http_field_content(const char *ptr)
1657
0
{
1658
0
    for ( ; !TEST_CHAR(*ptr, T_HTTP_CTRLS); ++ptr) ;
1659
1660
0
    return ptr;
1661
0
}
1662
1663
/* Scan a string for HTTP token characters, returning the pointer to
1664
 * the first non-token character.
1665
 */
1666
AP_DECLARE(const char *) ap_scan_http_token(const char *ptr)
1667
356
{
1668
2.64k
    for ( ; !TEST_CHAR(*ptr, T_HTTP_TOKEN_STOP); ++ptr) ;
1669
1670
356
    return ptr;
1671
356
}
1672
1673
/* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+)
1674
 * and return a pointer to the first ctrl/space character encountered.
1675
 */
1676
AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr)
1677
709
{
1678
12.5k
    for ( ; TEST_CHAR(*ptr, T_VCHAR_OBSTEXT); ++ptr) ;
1679
1680
709
    return ptr;
1681
709
}
1682
1683
/* Retrieve a token, spacing over it and returning a pointer to
1684
 * the first non-white byte afterwards.  Note that these tokens
1685
 * are delimited by semis and commas; and can also be delimited
1686
 * by whitespace at the caller's option.
1687
 */
1688
1689
AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line,
1690
                                int accept_white)
1691
1.25k
{
1692
1.25k
    const char *ptr = *accept_line;
1693
1.25k
    const char *tok_start;
1694
1.25k
    char *token;
1695
1696
    /* Find first non-white byte */
1697
1698
2.82k
    while (apr_isspace(*ptr))
1699
1.57k
        ++ptr;
1700
1701
1.25k
    tok_start = ptr;
1702
1703
    /* find token end, skipping over quoted strings.
1704
     * (comments are already gone).
1705
     */
1706
1707
35.8k
    while (*ptr && (accept_white || !apr_isspace(*ptr))
1708
35.8k
           && *ptr != ';' && *ptr != ',') {
1709
34.6k
        if (*ptr++ == '"')
1710
4.46k
            while (*ptr)
1711
4.36k
                if (*ptr++ == '"')
1712
482
                    break;
1713
34.6k
    }
1714
1715
1.25k
    token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
1716
1717
    /* Advance accept_line pointer to the next non-white byte */
1718
1719
1.25k
    while (apr_isspace(*ptr))
1720
0
        ++ptr;
1721
1722
1.25k
    *accept_line = ptr;
1723
1.25k
    return token;
1724
1.25k
}
1725
1726
1727
/* find http tokens, see the definition of token from RFC2068 */
1728
AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1729
1.25k
{
1730
1.25k
    const unsigned char *start_token;
1731
1.25k
    const unsigned char *s;
1732
1733
1.25k
    if (!line)
1734
0
        return 0;
1735
1736
1.25k
    s = (const unsigned char *)line;
1737
4.83k
    for (;;) {
1738
        /* find start of token, skip all stop characters */
1739
37.4k
        while (*s && TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1740
32.6k
            ++s;
1741
32.6k
        }
1742
4.83k
        if (!*s) {
1743
720
            return 0;
1744
720
        }
1745
4.11k
        start_token = s;
1746
        /* find end of the token */
1747
22.6k
        while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1748
18.5k
            ++s;
1749
18.5k
        }
1750
4.11k
        if (!ap_cstr_casecmpn((const char *)start_token, (const char *)tok,
1751
4.11k
                         s - start_token)) {
1752
105
            return 1;
1753
105
        }
1754
4.01k
        if (!*s) {
1755
425
            return 0;
1756
425
        }
1757
4.01k
    }
1758
1.25k
}
1759
1760
static const char *find_last_token(apr_pool_t *p, const char *line,
1761
                            const char *tok)
1762
2.49k
{
1763
2.49k
    int llen, tlen, lidx;
1764
1765
2.49k
    if (!line)
1766
0
        return NULL;
1767
1768
2.49k
    llen = strlen(line);
1769
2.49k
    tlen = strlen(tok);
1770
2.49k
    lidx = llen - tlen;
1771
1772
2.49k
    if (lidx < 0 ||
1773
2.49k
        (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1774
2.06k
        return NULL;
1775
1776
424
    if (ap_cstr_casecmpn(&line[lidx], tok, tlen) == 0) { 
1777
21
        return &line[lidx];
1778
21
    }
1779
403
   return NULL;
1780
424
}
1781
1782
AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
1783
                                   const char *tok)
1784
1.25k
{
1785
1.25k
    return find_last_token(p, line, tok) != NULL;
1786
1.25k
}
1787
1788
AP_DECLARE(int) ap_is_chunked(apr_pool_t *p, const char *line)
1789
1.25k
{
1790
1.25k
    const char *s;
1791
1792
1.25k
    if (!line) 
1793
0
        return 0;
1794
1.25k
    if (!ap_cstr_casecmp(line, "chunked")) { 
1795
9
        return 1;
1796
9
    }
1797
1798
1.24k
    s = find_last_token(p, line, "chunked");
1799
1800
1.24k
    if (!s) return 0;
1801
 
1802
    /* eat spaces right-to-left to see what precedes "chunked" */
1803
296
    while (--s > line) { 
1804
293
        if (*s != ' ') break;
1805
293
    }
1806
1807
    /* found delim, or leading ws (input wasn't parsed by httpd as a header) */
1808
20
    if (*s == ',' || *s == ' ') { 
1809
4
        return 1;
1810
4
    }
1811
16
    return 0;
1812
20
}
1813
1814
AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1815
1.25k
{
1816
1.25k
    char *cmd;
1817
1.25k
    unsigned char *d;
1818
1.25k
    const unsigned char *s;
1819
1820
1.25k
    cmd = apr_palloc(p, 2 * strlen(str) + 1);        /* Be safe */
1821
1.25k
    d = (unsigned char *)cmd;
1822
1.25k
    s = (const unsigned char *)str;
1823
56.3k
    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
55.0k
        if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1838
15.2k
            *d++ = '\\';
1839
15.2k
        }
1840
55.0k
        *d++ = *s;
1841
55.0k
    }
1842
1.25k
    *d = '\0';
1843
1844
1.25k
    return cmd;
1845
1.25k
}
1846
1847
static char x2c(const char *what)
1848
457
{
1849
457
    char digit;
1850
1851
457
#if !APR_CHARSET_EBCDIC
1852
457
    digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
1853
457
             : (what[0] - '0'));
1854
457
    digit *= 16;
1855
457
    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
1856
457
              : (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
457
    return (digit);
1868
457
}
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
540
{
1882
540
    const int keep_slashes = (flags & AP_UNESCAPE_URL_KEEP_SLASHES) != 0,
1883
540
              forbid_slashes = (flags & AP_UNESCAPE_URL_FORBID_SLASHES) != 0,
1884
540
              keep_unreserved = (flags & AP_UNESCAPE_URL_KEEP_UNRESERVED) != 0;
1885
540
    int badesc, badpath;
1886
540
    char *x, *y;
1887
1888
540
    badesc = 0;
1889
540
    badpath = 0;
1890
1891
540
    if (url == NULL) {
1892
0
        return OK;
1893
0
    }
1894
    /* Initial scan for first '%'. Don't bother writing values before
1895
     * seeing a '%' */
1896
540
    y = strchr(url, '%');
1897
540
    if (y == NULL) {
1898
435
        return OK;
1899
435
    }
1900
3.63k
    for (x = y; *y; ++x, ++y) {
1901
3.53k
        if (*y != '%') {
1902
2.22k
            *x = *y;
1903
2.22k
        }
1904
1.30k
        else {
1905
1.30k
            if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1906
850
                badesc = 1;
1907
850
                *x = '%';
1908
850
            }
1909
457
            else {
1910
457
                char decoded;
1911
457
                decoded = x2c(y + 1);
1912
457
                if ((decoded == '\0')
1913
457
                    || (forbid_slashes && AP_IS_SLASH(decoded))
1914
457
                    || (forbid && ap_strchr_c(forbid, decoded))) {
1915
178
                    badpath = 1;
1916
178
                    *x = decoded;
1917
178
                    y += 2;
1918
178
                }
1919
279
                else if ((keep_unreserved && TEST_CHAR(decoded,
1920
279
                                                       T_URI_UNRESERVED))
1921
279
                         || (keep_slashes && AP_IS_SLASH(decoded))
1922
279
                         || (reserved && ap_strchr_c(reserved, decoded))) {
1923
0
                    *x++ = *y++;
1924
0
                    *x++ = *y++;
1925
0
                    *x = *y;
1926
0
                }
1927
279
                else {
1928
279
                    *x = decoded;
1929
279
                    y += 2;
1930
279
                }
1931
457
            }
1932
1.30k
        }
1933
3.53k
    }
1934
105
    *x = '\0';
1935
105
    if (badesc) {
1936
83
        return HTTP_BAD_REQUEST;
1937
83
    }
1938
22
    else if (badpath) {
1939
7
        return HTTP_NOT_FOUND;
1940
7
    }
1941
15
    else {
1942
15
        return OK;
1943
15
    }
1944
105
}
1945
AP_DECLARE(int) ap_unescape_url(char *url)
1946
290
{
1947
    /* Traditional */
1948
290
    return unescape_url(url, AP_SLASHES, NULL, 0);
1949
290
}
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
250
{
1985
250
    char *slider;
1986
1987
    /* replace plus with a space */
1988
250
    if (query) {
1989
9.71k
        for (slider = query; *slider; slider++) {
1990
9.46k
            if (*slider == '+') {
1991
183
                *slider = ' ';
1992
183
            }
1993
9.46k
        }
1994
250
    }
1995
1996
    /* unescape everything else */
1997
250
    return unescape_url(query, NULL, NULL, 0);
1998
250
}
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
117k
{
2031
#if APR_CHARSET_EBCDIC
2032
    what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
2033
#endif /*APR_CHARSET_EBCDIC*/
2034
117k
    *where++ = prefix;
2035
117k
    *where++ = c2x_table[what >> 4];
2036
117k
    *where++ = c2x_table[what & 0xf];
2037
117k
    return where;
2038
117k
}
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.25k
{
2057
1.25k
    const unsigned char *s = (const unsigned char *)segment;
2058
1.25k
    unsigned char *d = (unsigned char *)copy;
2059
1.25k
    unsigned c;
2060
2061
56.3k
    while ((c = *s)) {
2062
55.0k
        if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
2063
30.4k
            d = c2x(c, '%', d);
2064
30.4k
        }
2065
24.6k
        else {
2066
24.6k
            *d++ = c;
2067
24.6k
        }
2068
55.0k
        ++s;
2069
55.0k
    }
2070
1.25k
    *d = '\0';
2071
1.25k
    return copy;
2072
1.25k
}
2073
2074
AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
2075
0
{
2076
0
    return ap_escape_path_segment_buffer(apr_palloc(p, 3 * strlen(segment) + 1), segment);
2077
0
}
2078
2079
AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
2080
1.25k
{
2081
    /* Allocate +3 for potential "./" and trailing NULL.
2082
     * Allocate another +1 to allow the caller to add a trailing '/' (see
2083
     * comment in 'ap_sub_req_lookup_dirent')
2084
     */
2085
1.25k
    char *copy = apr_palloc(p, 3 * strlen(path) + 3 + 1);
2086
1.25k
    const unsigned char *s = (const unsigned char *)path;
2087
1.25k
    unsigned char *d = (unsigned char *)copy;
2088
1.25k
    unsigned c;
2089
2090
1.25k
    if (!partial) {
2091
1.25k
        const char *colon = ap_strchr_c(path, ':');
2092
1.25k
        const char *slash = ap_strchr_c(path, '/');
2093
2094
1.25k
        if (colon && (!slash || colon < slash)) {
2095
44
            *d++ = '.';
2096
44
            *d++ = '/';
2097
44
        }
2098
1.25k
    }
2099
56.3k
    while ((c = *s)) {
2100
55.0k
        if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
2101
29.3k
            d = c2x(c, '%', d);
2102
29.3k
        }
2103
25.7k
        else {
2104
25.7k
            *d++ = c;
2105
25.7k
        }
2106
55.0k
        ++s;
2107
55.0k
    }
2108
1.25k
    *d = '\0';
2109
1.25k
    return copy;
2110
1.25k
}
2111
2112
AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer)
2113
1.25k
{
2114
1.25k
    const unsigned char *s = (const unsigned char *)buffer;
2115
1.25k
    unsigned char *d = (unsigned char *)copy;
2116
1.25k
    unsigned c;
2117
2118
56.3k
    while ((c = *s)) {
2119
55.0k
        if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
2120
33.6k
            d = c2x(c, '%', d);
2121
33.6k
        }
2122
21.4k
        else if (c == ' ') {
2123
3.55k
            *d++ = '+';
2124
3.55k
        }
2125
17.8k
        else {
2126
17.8k
            *d++ = c;
2127
17.8k
        }
2128
55.0k
        ++s;
2129
55.0k
    }
2130
1.25k
    *d = '\0';
2131
1.25k
    return copy;
2132
1.25k
}
2133
2134
AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
2135
1.25k
{
2136
1.25k
    return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * strlen(buffer) + 1), buffer);
2137
1.25k
}
2138
2139
/* ap_escape_uri is now a macro for os_escape_path */
2140
2141
AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
2142
1.25k
{
2143
1.25k
    apr_size_t i, j;
2144
1.25k
    char *x;
2145
2146
    /* first, count the number of extra characters */
2147
56.3k
    for (i = 0, j = 0; s[i] != '\0'; i++) {
2148
55.0k
        if (i + j > APR_SIZE_MAX - 6) {
2149
0
            abort();
2150
0
        }
2151
55.0k
        if (s[i] == '<' || s[i] == '>')
2152
601
            j += 3;
2153
54.4k
        else if (s[i] == '&')
2154
397
            j += 4;
2155
54.0k
        else if (s[i] == '"')
2156
1.55k
            j += 5;
2157
52.5k
        else if (toasc && !apr_isascii(s[i]))
2158
0
            j += 5;
2159
55.0k
    }
2160
2161
1.25k
    if (j == 0)
2162
923
        return apr_pstrmemdup(p, s, i);
2163
2164
327
    x = apr_palloc(p, i + j + 1);
2165
19.2k
    for (i = 0, j = 0; s[i] != '\0'; i++, j++)
2166
18.9k
        if (s[i] == '<') {
2167
288
            memcpy(&x[j], "&lt;", 4);
2168
288
            j += 3;
2169
288
        }
2170
18.6k
        else if (s[i] == '>') {
2171
313
            memcpy(&x[j], "&gt;", 4);
2172
313
            j += 3;
2173
313
        }
2174
18.3k
        else if (s[i] == '&') {
2175
397
            memcpy(&x[j], "&amp;", 5);
2176
397
            j += 4;
2177
397
        }
2178
17.9k
        else if (s[i] == '"') {
2179
1.55k
            memcpy(&x[j], "&quot;", 6);
2180
1.55k
            j += 5;
2181
1.55k
        }
2182
16.3k
        else if (toasc && !apr_isascii(s[i])) {
2183
0
            char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]);
2184
0
            memcpy(&x[j], esc, 6);
2185
0
            j += 5;
2186
0
        }
2187
16.3k
        else
2188
16.3k
            x[j] = s[i];
2189
2190
327
    x[j] = '\0';
2191
327
    return x;
2192
1.25k
}
2193
AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
2194
1.25k
{
2195
1.25k
    char *ret;
2196
1.25k
    unsigned char *d;
2197
1.25k
    const unsigned char *s;
2198
1.25k
    apr_size_t length, escapes = 0;
2199
2200
1.25k
    if (!str) {
2201
0
        return NULL;
2202
0
    }
2203
2204
    /* Compute how many characters need to be escaped */
2205
1.25k
    s = (const unsigned char *)str;
2206
56.3k
    for (; *s; ++s) {
2207
55.0k
        if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2208
23.3k
            escapes++;
2209
23.3k
        }
2210
55.0k
    }
2211
    
2212
    /* Compute the length of the input string, including NULL */
2213
1.25k
    length = s - (const unsigned char *)str + 1;
2214
    
2215
    /* Fast path: nothing to escape */
2216
1.25k
    if (escapes == 0) {
2217
249
        return apr_pmemdup(p, str, length);
2218
249
    }
2219
    
2220
    /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
2221
1.00k
    ret = apr_palloc(p, length + 3 * escapes);
2222
1.00k
    d = (unsigned char *)ret;
2223
1.00k
    s = (const unsigned char *)str;
2224
50.8k
    for (; *s; ++s) {
2225
49.8k
        if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2226
23.3k
            *d++ = '\\';
2227
23.3k
            switch(*s) {
2228
186
            case '\b':
2229
186
                *d++ = 'b';
2230
186
                break;
2231
2.16k
            case '\n':
2232
2.16k
                *d++ = 'n';
2233
2.16k
                break;
2234
336
            case '\r':
2235
336
                *d++ = 'r';
2236
336
                break;
2237
2.35k
            case '\t':
2238
2.35k
                *d++ = 't';
2239
2.35k
                break;
2240
436
            case '\v':
2241
436
                *d++ = 'v';
2242
436
                break;
2243
4.43k
            case '\\':
2244
5.99k
            case '"':
2245
5.99k
                *d++ = *s;
2246
5.99k
                break;
2247
11.8k
            default:
2248
11.8k
                c2x(*s, 'x', d);
2249
11.8k
                d += 3;
2250
23.3k
            }
2251
23.3k
        }
2252
26.5k
        else {
2253
26.5k
            *d++ = *s;
2254
26.5k
        }
2255
49.8k
    }
2256
1.00k
    *d = '\0';
2257
2258
1.00k
    return ret;
2259
1.00k
}
2260
2261
AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
2262
                                               apr_size_t buflen)
2263
1.25k
{
2264
1.25k
    unsigned char *d, *ep;
2265
1.25k
    const unsigned char *s;
2266
2267
1.25k
    if (!source || !buflen) { /* be safe */
2268
0
        return 0;
2269
0
    }
2270
2271
1.25k
    d = (unsigned char *)dest;
2272
1.25k
    s = (const unsigned char *)source;
2273
1.25k
    ep = d + buflen - 1;
2274
2275
56.3k
    for (; d < ep && *s; ++s) {
2276
2277
55.0k
        if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2278
23.3k
            *d++ = '\\';
2279
23.3k
            if (d >= ep) {
2280
0
                --d;
2281
0
                break;
2282
0
            }
2283
2284
23.3k
            switch(*s) {
2285
186
            case '\b':
2286
186
                *d++ = 'b';
2287
186
                break;
2288
2.16k
            case '\n':
2289
2.16k
                *d++ = 'n';
2290
2.16k
                break;
2291
336
            case '\r':
2292
336
                *d++ = 'r';
2293
336
                break;
2294
2.35k
            case '\t':
2295
2.35k
                *d++ = 't';
2296
2.35k
                break;
2297
436
            case '\v':
2298
436
                *d++ = 'v';
2299
436
                break;
2300
4.43k
            case '\\':
2301
4.43k
                *d++ = *s;
2302
4.43k
                break;
2303
1.55k
            case '"': /* no need for this in error log */
2304
1.55k
                d[-1] = *s;
2305
1.55k
                break;
2306
11.8k
            default:
2307
11.8k
                if (d >= ep - 2) {
2308
0
                    ep = --d; /* break the for loop as well */
2309
0
                    break;
2310
0
                }
2311
11.8k
                c2x(*s, 'x', d);
2312
11.8k
                d += 3;
2313
23.3k
            }
2314
23.3k
        }
2315
31.7k
        else {
2316
31.7k
            *d++ = *s;
2317
31.7k
        }
2318
55.0k
    }
2319
1.25k
    *d = '\0';
2320
2321
1.25k
    return (d - (unsigned char *)dest);
2322
1.25k
}
2323
2324
AP_DECLARE(void) ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
2325
0
{
2326
0
    const unsigned char *in = src;
2327
0
    apr_size_t i;
2328
2329
0
    for (i = 0; i < srclen; i++) {
2330
0
        *dest++ = c2x_table[in[i] >> 4];
2331
0
        *dest++ = c2x_table[in[i] & 0xf];
2332
0
    }
2333
0
    *dest = '\0';
2334
0
}
2335
2336
AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
2337
0
{
2338
0
    apr_finfo_t finfo;
2339
2340
0
    if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS)
2341
0
        return 0;                /* in error condition, just return no */
2342
2343
0
    return (finfo.filetype == APR_DIR);
2344
0
}
2345
2346
AP_DECLARE(int) ap_is_rdirectory(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_LINK | 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(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
2357
                                  const char *src2)
2358
0
{
2359
0
    apr_size_t len1, len2;
2360
0
    char *path;
2361
2362
0
    len1 = strlen(src1);
2363
0
    len2 = strlen(src2);
2364
     /* allocate +3 for '/' delimiter, trailing NULL and overallocate
2365
      * one extra byte to allow the caller to add a trailing '/'
2366
      */
2367
0
    path = (char *)apr_palloc(a, len1 + len2 + 3);
2368
0
    if (len1 == 0) {
2369
0
        *path = '/';
2370
0
        memcpy(path + 1, src2, len2 + 1);
2371
0
    }
2372
0
    else {
2373
0
        char *next;
2374
0
        memcpy(path, src1, len1);
2375
0
        next = path + len1;
2376
0
        if (next[-1] != '/') {
2377
0
            *next++ = '/';
2378
0
        }
2379
0
        memcpy(next, src2, len2 + 1);
2380
0
    }
2381
0
    return path;
2382
0
}
2383
2384
/*
2385
 * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
2386
 */
2387
AP_DECLARE(int) ap_is_url(const char *u)
2388
0
{
2389
0
    int x;
2390
2391
0
    for (x = 0; u[x] != ':'; x++) {
2392
0
        if ((!u[x]) ||
2393
0
            ((!apr_isalnum(u[x])) &&
2394
0
             (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
2395
0
            return 0;
2396
0
        }
2397
0
    }
2398
2399
0
    return (x ? 1 : 0);                /* If the first character is ':', it's broken, too */
2400
0
}
2401
2402
AP_DECLARE(int) ap_ind(const char *s, char c)
2403
0
{
2404
0
    const char *p = ap_strchr_c(s, c);
2405
2406
0
    if (p == NULL)
2407
0
        return -1;
2408
0
    return p - s;
2409
0
}
2410
2411
AP_DECLARE(int) ap_rind(const char *s, char c)
2412
0
{
2413
0
    const char *p = ap_strrchr_c(s, c);
2414
2415
0
    if (p == NULL)
2416
0
        return -1;
2417
0
    return p - s;
2418
0
}
2419
2420
AP_DECLARE(void) ap_str_tolower(char *str)
2421
217
{
2422
8.69k
    while (*str) {
2423
8.47k
        *str = apr_tolower(*str);
2424
8.47k
        ++str;
2425
8.47k
    }
2426
217
}
2427
2428
AP_DECLARE(void) ap_str_toupper(char *str)
2429
0
{
2430
0
    while (*str) {
2431
0
        *str = apr_toupper(*str);
2432
0
        ++str;
2433
0
    }
2434
0
}
2435
2436
/*
2437
 * We must return a FQDN
2438
 */
2439
char *ap_get_local_host(apr_pool_t *a)
2440
0
{
2441
0
#ifndef MAXHOSTNAMELEN
2442
0
#define MAXHOSTNAMELEN 256
2443
0
#endif
2444
0
    char str[MAXHOSTNAMELEN + 1];
2445
0
    char *server_hostname = NULL;
2446
0
    apr_sockaddr_t *sockaddr;
2447
0
    char *hostname;
2448
2449
0
    if (apr_gethostname(str, sizeof(str) - 1, a) != APR_SUCCESS) {
2450
0
        ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00556)
2451
0
                     "%s: apr_gethostname() failed to determine ServerName",
2452
0
                     ap_server_argv0);
2453
0
    } else {
2454
0
        str[sizeof(str) - 1] = '\0';
2455
0
        if (apr_sockaddr_info_get(&sockaddr, str, APR_UNSPEC, 0, 0, a) == APR_SUCCESS) {
2456
0
            if ( (apr_getnameinfo(&hostname, sockaddr, 0) == APR_SUCCESS) &&
2457
0
                (ap_strchr_c(hostname, '.')) ) {
2458
0
                server_hostname = apr_pstrdup(a, hostname);
2459
0
                return server_hostname;
2460
0
            } else if (ap_strchr_c(str, '.')) {
2461
0
                server_hostname = apr_pstrdup(a, str);
2462
0
            } else {
2463
0
                apr_sockaddr_ip_get(&hostname, sockaddr);
2464
0
                server_hostname = apr_pstrdup(a, hostname);
2465
0
            }
2466
0
        } else {
2467
0
            ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00557)
2468
0
                         "%s: apr_sockaddr_info_get() failed for %s",
2469
0
                         ap_server_argv0, str);
2470
0
        }
2471
0
    }
2472
2473
0
    if (!server_hostname)
2474
0
        server_hostname = apr_pstrdup(a, "127.0.0.1");
2475
2476
0
    ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, a, APLOGNO(00558)
2477
0
                 "%s: Could not reliably determine the server's fully qualified "
2478
0
                 "domain name, using %s. Set the 'ServerName' directive globally "
2479
0
                 "to suppress this message",
2480
0
                 ap_server_argv0, server_hostname);
2481
2482
0
    return server_hostname;
2483
0
}
2484
2485
/* simple 'pool' alloc()ing glue to apr_base64.c
2486
 */
2487
AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
2488
1.25k
{
2489
1.25k
    char *decoded;
2490
2491
1.25k
    decoded = (char *) apr_palloc(p, apr_base64_decode_len(bufcoded));
2492
1.25k
    apr_base64_decode(decoded, bufcoded);
2493
2494
1.25k
    return decoded;
2495
1.25k
}
2496
2497
/* a stringent version of ap_pbase64decode() */
2498
AP_DECLARE(apr_status_t) ap_pbase64decode_strict(apr_pool_t *p,
2499
                                                 const char *encoded,
2500
                                                 char **decoded,
2501
                                                 apr_size_t *len)
2502
199
{
2503
199
    apr_size_t end_index;
2504
199
    int last_group_len;
2505
199
    const char *end;
2506
2507
    /* Sanity check.
2508
     * TODO: this would be a lot more efficient if we had access to the lookup
2509
     * table used by APR. If that gets pulled in at any point, make use of it.
2510
     */
2511
199
    end_index = strspn(encoded, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2512
199
                                "abcdefghijklmnopqrstuvwxyz"
2513
199
                                "0123456789+/");
2514
2515
199
    last_group_len = end_index % 4;
2516
199
    end = encoded + end_index;
2517
2518
    /* The only non-alphabet character allowed is the padding character '=' at
2519
     * the end of the string. There are two allowable padding cases for the last
2520
     * group of four: "xY==" or "xyZ=". We require the final (non-padding)
2521
     * character to have been zero-padded during encoding, which limits the
2522
     * character choices.
2523
     */
2524
199
    if (last_group_len == 1) {
2525
        /* This isn't ever valid. */
2526
9
        return APR_EINVAL;
2527
9
    }
2528
190
    else if (last_group_len == 2) {
2529
        /* ...xY== */
2530
19
        if (*end != '=' || end[1] != '=') {
2531
16
            return APR_EINVAL;
2532
16
        }
2533
3
        else if (!ap_strchr("AQgw", end[-1])) {
2534
            /* Correctly zero-padded input data will result in a final character
2535
             * that is one of the four above. */
2536
1
            return APR_EINVAL;
2537
1
        }
2538
2539
2
        end += 2;
2540
2
    }
2541
171
    else if (last_group_len == 3) {
2542
        /* ...xyZ= */
2543
24
        if (*end != '=') {
2544
21
            return APR_EINVAL;
2545
21
        }
2546
3
        else if (!ap_strchr("AEIMQUYcgkosw048", end[-1])) {
2547
            /* Correctly zero-padded input data will result in a final character
2548
             * that is one of the sixteen above. */
2549
1
            return APR_EINVAL;
2550
1
        }
2551
2552
2
        end++;
2553
2
    }
2554
2555
    /* At this point, if the encoded buffer is correct, we should be at the end
2556
     * of the string. */
2557
151
    if (*end) {
2558
121
        return APR_EINVAL;
2559
121
    }
2560
2561
30
    *decoded = apr_palloc(p, apr_base64_decode_len(encoded));
2562
30
    *len = apr_base64_decode(*decoded, encoded);
2563
2564
30
    return APR_SUCCESS;
2565
151
}
2566
2567
AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
2568
1.25k
{
2569
1.25k
    char *encoded;
2570
1.25k
    int l = strlen(string);
2571
2572
1.25k
    encoded = (char *) apr_palloc(p, apr_base64_encode_len(l));
2573
1.25k
    apr_base64_encode(encoded, string, l);
2574
2575
1.25k
    return encoded;
2576
1.25k
}
2577
2578
/* we want to downcase the type/subtype for comparison purposes
2579
 * but nothing else because ;parameter=foo values are case sensitive.
2580
 * XXX: in truth we want to downcase parameter names... but really,
2581
 * apache has never handled parameters and such correctly.  You
2582
 * also need to compress spaces and such to be able to compare
2583
 * properly. -djg
2584
 */
2585
AP_DECLARE(void) ap_content_type_tolower(char *str)
2586
217
{
2587
217
    char *semi;
2588
2589
217
    semi = strchr(str, ';');
2590
217
    if (semi) {
2591
8
        *semi = '\0';
2592
8
    }
2593
2594
217
    ap_str_tolower(str);
2595
2596
217
    if (semi) {
2597
8
        *semi = ';';
2598
8
    }
2599
217
}
2600
2601
/*
2602
 * Given a string, replace any bare " with \" .
2603
 */
2604
AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
2605
1.25k
{
2606
1.25k
    apr_size_t size, extra = 0;
2607
1.25k
    const char *inchr = instring;
2608
1.25k
    char *outchr, *outstring;
2609
2610
    /*
2611
     * Look through the input string, jogging the length of the output
2612
     * string up by an extra byte each time we find an unescaped ".
2613
     */
2614
53.3k
    while (*inchr != '\0') {
2615
52.1k
        if (*inchr == '"') {
2616
1.34k
            extra++;
2617
1.34k
        }
2618
        /*
2619
         * If we find a slosh, and it's not the last byte in the string,
2620
         * it's escaping something - advance past both bytes.
2621
         */
2622
50.7k
        else if ((*inchr == '\\') && (inchr[1] != '\0')) {
2623
2.92k
            inchr++;
2624
2.92k
        }
2625
52.1k
        inchr++;
2626
52.1k
    }
2627
2628
1.25k
    if (!extra) {
2629
1.02k
        return apr_pstrdup(p, instring);
2630
1.02k
    }
2631
2632
    /* How large will the string become, once we escaped all the quotes?
2633
     * The tricky cases are
2634
     * - an `instring` that is already longer than `ptrdiff_t`
2635
     *   can hold (which is an undefined case in C, as C defines ptrdiff_t as
2636
     *   a signed difference between pointers into the same array and one index
2637
     *   beyond).
2638
     * - an `instring` that, including the `extra` chars we want to add, becomes
2639
     *   even larger than apr_size_t can handle.
2640
     * Since this function was not designed to ever return NULL for failure, we
2641
     * can only trigger a hard assertion failure. It seems more a programming
2642
     * mistake (or failure to verify the input causing this) that leads to this
2643
     * situation.
2644
     */
2645
225
    ap_assert(inchr - instring > 0);
2646
225
    size = ((apr_size_t)(inchr - instring)) + 1;
2647
225
    ap_assert(size + extra > size);
2648
2649
225
    outstring = apr_palloc(p, size + extra);
2650
225
    inchr = instring;
2651
225
    outchr = outstring;
2652
    /*
2653
     * Now copy the input string to the output string, inserting a slosh
2654
     * in front of every " that doesn't already have one.
2655
     */
2656
12.2k
    while (*inchr != '\0') {
2657
12.0k
        if (*inchr == '"') {
2658
1.34k
            *outchr++ = '\\';
2659
1.34k
        }
2660
10.7k
        else if ((*inchr == '\\') && (inchr[1] != '\0')) {
2661
876
            *outchr++ = *inchr++;
2662
876
        }
2663
12.0k
        *outchr++ = *inchr++;
2664
12.0k
    }
2665
225
    *outchr = '\0';
2666
225
    return outstring;
2667
225
}
2668
2669
/*
2670
 * Given a string, append the PID deliminated by delim.
2671
 * Usually used to create a pid-appended filepath name
2672
 * (eg: /a/b/foo -> /a/b/foo.6726). A function, and not
2673
 * a macro, to avoid unistd.h dependency
2674
 */
2675
AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
2676
                                    const char *delim)
2677
0
{
2678
0
    return apr_psprintf(p, "%s%s%" APR_PID_T_FMT, string,
2679
0
                        delim, getpid());
2680
2681
0
}
2682
2683
/**
2684
 * Parse a given timeout parameter string into an apr_interval_time_t value.
2685
 * The unit of the time interval is given as postfix string to the numeric
2686
 * string. Currently the following units are understood (case insensitive):
2687
 *
2688
 * ms    : milliseconds
2689
 * s     : seconds
2690
 * mi[n] : minutes
2691
 * h     : hours
2692
 *
2693
 * If no unit is contained in the given timeout parameter the default_time_unit
2694
 * will be used instead.
2695
 * @param timeout_parameter The string containing the timeout parameter.
2696
 * @param timeout The timeout value to be returned.
2697
 * @param default_time_unit The default time unit to use if none is specified
2698
 * in timeout_parameter.
2699
 * @return Status value indicating whether the parsing was successful or not.
2700
 */
2701
414
#define CHECK_OVERFLOW(a, b) if (a > b) return APR_EGENERAL
2702
AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
2703
                                               const char *timeout_parameter,
2704
                                               apr_interval_time_t *timeout,
2705
                                               const char *default_time_unit)
2706
1.25k
{
2707
1.25k
    char *endp;
2708
1.25k
    const char *time_str;
2709
1.25k
    apr_int64_t tout;
2710
1.25k
    apr_uint64_t check;
2711
2712
1.25k
    tout = apr_strtoi64(timeout_parameter, &endp, 10);
2713
1.25k
    if (errno) {
2714
4
        return errno;
2715
4
    }
2716
1.24k
    if (!endp || !*endp) {
2717
127
        time_str = default_time_unit;
2718
127
    }
2719
1.11k
    else {
2720
1.11k
        time_str = endp;
2721
1.11k
    }
2722
2723
1.24k
    if (tout < 0) { 
2724
90
        return APR_EGENERAL;
2725
90
    }
2726
2727
1.15k
    switch (*time_str) {
2728
        /* Time is in seconds */
2729
58
    case 's':
2730
93
    case 'S':
2731
93
        CHECK_OVERFLOW(tout, apr_time_sec(APR_INT64_MAX));
2732
57
        check = apr_time_from_sec(tout);
2733
57
        break;
2734
        /* Time is in hours */
2735
33
    case 'h':
2736
101
    case 'H':
2737
101
        CHECK_OVERFLOW(tout, apr_time_sec(APR_INT64_MAX / 3600));
2738
53
        check = apr_time_from_sec(tout * 3600);
2739
53
        break;
2740
201
    case 'm':
2741
224
    case 'M':
2742
224
        switch (*(++time_str)) {
2743
        /* Time is in milliseconds */
2744
119
        case 's':
2745
123
        case 'S':
2746
123
            CHECK_OVERFLOW(tout, apr_time_as_msec(APR_INT64_MAX));
2747
91
            check = apr_time_from_msec(tout);
2748
91
            break;
2749
        /* Time is in minutes */
2750
71
        case 'i':
2751
97
        case 'I':
2752
97
            CHECK_OVERFLOW(tout, apr_time_sec(APR_INT64_MAX / 60));
2753
50
            check = apr_time_from_sec(tout * 60);
2754
50
            break;
2755
4
        default:
2756
4
            return APR_EGENERAL;
2757
224
        }
2758
141
        break;
2759
738
    default:
2760
738
        return APR_EGENERAL;
2761
1.15k
    }
2762
2763
251
    *timeout = (apr_interval_time_t)check;
2764
251
    return APR_SUCCESS;
2765
1.15k
}
2766
#undef CHECK_OVERFLOW
2767
2768
AP_DECLARE(int) ap_parse_strict_length(apr_off_t *len, const char *str)
2769
0
{
2770
0
    char *end;
2771
2772
0
    return (apr_isdigit(*str)
2773
0
            && apr_strtoff(len, str, &end, 10) == APR_SUCCESS
2774
0
            && *end == '\0');
2775
0
}
2776
2777
/**
2778
 * Determine if a request has a request body or not.
2779
 *
2780
 * @param r the request_rec of the request
2781
 * @return truth value
2782
 */
2783
AP_DECLARE(int) ap_request_has_body(request_rec *r)
2784
0
{
2785
0
    apr_off_t cl;
2786
0
    const char *cls;
2787
2788
0
    return (!r->header_only
2789
0
            && (r->kept_body
2790
0
                || apr_table_get(r->headers_in, "Transfer-Encoding")
2791
0
                || ((cls = apr_table_get(r->headers_in, "Content-Length"))
2792
0
                    && ap_parse_strict_length(&cl, cls) && cl > 0)));
2793
0
}
2794
2795
/**
2796
 * Check whether a request is tainted by exposure to something
2797
 * potentially untrusted.  
2798
 *
2799
 */
2800
AP_DECLARE(int) ap_request_tainted(request_rec *r, int flags)
2801
0
{
2802
    /** Potential future: a hook or callback here could serve modules
2803
     *  like mod_security and ironbee with more complex needs.
2804
     */
2805
0
    return r && ((r->taint&flags)
2806
0
                 || ap_request_tainted(r->main, flags)
2807
0
                 || ap_request_tainted(r->prev, flags));
2808
0
}
2809
2810
AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
2811
0
{
2812
0
    void **ptr = (void **)data_;
2813
0
    *ptr = NULL;
2814
0
    return APR_SUCCESS;
2815
0
}
2816
2817
1.25k
AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
2818
2819
56.3k
    for ( ; *src; src++, dest++)
2820
55.0k
    {
2821
55.0k
        if (!apr_isprint(*src))
2822
17.3k
            *dest = 'x';
2823
37.7k
        else if (!apr_isalnum(*src))
2824
22.2k
            *dest = '_';
2825
15.5k
        else
2826
15.5k
            *dest = (char)*src;
2827
55.0k
    }
2828
1.25k
    *dest = '\0';
2829
1.25k
    return APR_SUCCESS;
2830
2831
1.25k
}
2832
2833
AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
2834
                                        const char **dest)
2835
1.25k
{
2836
1.25k
    char *new = apr_palloc(p, strlen(src)+1);
2837
1.25k
    if (!new)
2838
0
        return APR_ENOMEM;
2839
1.25k
    *dest = new;
2840
1.25k
    return ap_str2_alnum(src, new);
2841
1.25k
}
2842
2843
/**
2844
 * Read the body and parse any form found, which must be of the
2845
 * type application/x-www-form-urlencoded.
2846
 *
2847
 * Name/value pairs are returned in an array, with the names as
2848
 * strings with a maximum length of HUGE_STRING_LEN, and the
2849
 * values as bucket brigades. This allows values to be arbitrarily
2850
 * large.
2851
 *
2852
 * All url-encoding is removed from both the names and the values
2853
 * on the fly. The names are interpreted as strings, while the
2854
 * values are interpreted as blocks of binary data, that may
2855
 * contain the 0 character.
2856
 *
2857
 * In order to ensure that resource limits are not exceeded, a
2858
 * maximum size must be provided. If the sum of the lengths of
2859
 * the names and the values exceed this size, this function
2860
 * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
2861
 *
2862
 * An optional number of parameters can be provided, if the number
2863
 * of parameters provided exceeds this amount, this function will
2864
 * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
2865
 * no limit is imposed, and the number of parameters is in turn
2866
 * constrained by the size parameter above.
2867
 *
2868
 * This function honours any kept_body configuration, and the
2869
 * original raw request body will be saved to the kept_body brigade
2870
 * if so configured, just as ap_discard_request_body does.
2871
 *
2872
 * NOTE: File upload is not yet supported, but can be without change
2873
 * to the function call.
2874
 */
2875
2876
/* form parsing stuff */
2877
typedef enum {
2878
    FORM_NORMAL,
2879
    FORM_AMP,
2880
    FORM_NAME,
2881
    FORM_VALUE,
2882
    FORM_PERCENTA,
2883
    FORM_PERCENTB,
2884
    FORM_ABORT
2885
} ap_form_type_t;
2886
2887
AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
2888
                                   apr_array_header_t **ptr,
2889
                                   apr_size_t num, apr_size_t usize)
2890
0
{
2891
0
    apr_bucket_brigade *bb = NULL;
2892
0
    int seen_eos = 0;
2893
0
    char buffer[HUGE_STRING_LEN + 1];
2894
0
    const char *ct;
2895
0
    apr_size_t offset = 0;
2896
0
    apr_ssize_t size;
2897
0
    ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
2898
0
    ap_form_pair_t *pair = NULL;
2899
0
    apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
2900
0
    char escaped_char[2] = { 0 };
2901
2902
0
    *ptr = pairs;
2903
2904
    /* sanity check - we only support forms for now */
2905
0
    ct = apr_table_get(r->headers_in, "Content-Type");
2906
0
    if (!ct || ap_cstr_casecmpn("application/x-www-form-urlencoded", ct, 33)) {
2907
0
        return ap_discard_request_body(r);
2908
0
    }
2909
2910
0
    if (usize > APR_SIZE_MAX >> 1)
2911
0
        size = APR_SIZE_MAX >> 1;
2912
0
    else
2913
0
        size = usize;
2914
2915
0
    if (!f) {
2916
0
        f = r->input_filters;
2917
0
    }
2918
2919
0
    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2920
0
    do {
2921
0
        apr_bucket *bucket = NULL, *last = NULL;
2922
2923
0
        int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
2924
0
                                APR_BLOCK_READ, HUGE_STRING_LEN);
2925
0
        if (rv != APR_SUCCESS) {
2926
0
            apr_brigade_destroy(bb);
2927
0
            return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
2928
0
        }
2929
2930
0
        for (bucket = APR_BRIGADE_FIRST(bb);
2931
0
             bucket != APR_BRIGADE_SENTINEL(bb);
2932
0
             last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
2933
0
            const char *data;
2934
0
            apr_size_t len, slide;
2935
2936
0
            if (last) {
2937
0
                apr_bucket_delete(last);
2938
0
            }
2939
0
            if (APR_BUCKET_IS_EOS(bucket)) {
2940
0
                seen_eos = 1;
2941
0
                break;
2942
0
            }
2943
0
            if (bucket->length == 0) {
2944
0
                continue;
2945
0
            }
2946
2947
0
            rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
2948
0
            if (rv != APR_SUCCESS) {
2949
0
                apr_brigade_destroy(bb);
2950
0
                return HTTP_BAD_REQUEST;
2951
0
            }
2952
2953
0
            slide = len;
2954
0
            while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
2955
0
                char c = *data++;
2956
0
                if ('+' == c) {
2957
0
                    c = ' ';
2958
0
                }
2959
0
                else if ('&' == c) {
2960
0
                    state = FORM_AMP;
2961
0
                }
2962
0
                if ('%' == c) {
2963
0
                    percent = FORM_PERCENTA;
2964
0
                    continue;
2965
0
                }
2966
0
                if (FORM_PERCENTA == percent) {
2967
0
                    escaped_char[0] = c;
2968
0
                    percent = FORM_PERCENTB;
2969
0
                    continue;
2970
0
                }
2971
0
                if (FORM_PERCENTB == percent) {
2972
0
                    escaped_char[1] = c;
2973
0
                    c = x2c(escaped_char);
2974
0
                    percent = FORM_NORMAL;
2975
0
                }
2976
0
                switch (state) {
2977
0
                    case FORM_AMP:
2978
0
                        if (pair) {
2979
0
                            const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2980
0
                            apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2981
0
                            APR_BRIGADE_INSERT_TAIL(pair->value, b);
2982
0
                        }
2983
0
                        state = FORM_NAME;
2984
0
                        pair = NULL;
2985
0
                        offset = 0;
2986
0
                        num--;
2987
0
                        break;
2988
0
                    case FORM_NAME:
2989
0
                        if (offset < HUGE_STRING_LEN) {
2990
0
                            if ('=' == c) {
2991
0
                                pair = (ap_form_pair_t *) apr_array_push(pairs);
2992
0
                                pair->name = apr_pstrmemdup(r->pool, buffer, offset);
2993
0
                                pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2994
0
                                state = FORM_VALUE;
2995
0
                                offset = 0;
2996
0
                            }
2997
0
                            else {
2998
0
                                buffer[offset++] = c;
2999
0
                                size--;
3000
0
                            }
3001
0
                        }
3002
0
                        else {
3003
0
                            state = FORM_ABORT;
3004
0
                        }
3005
0
                        break;
3006
0
                    case FORM_VALUE:
3007
0
                        if (offset >= HUGE_STRING_LEN) {
3008
0
                            const char *tmp = apr_pmemdup(r->pool, buffer, offset);
3009
0
                            apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
3010
0
                            APR_BRIGADE_INSERT_TAIL(pair->value, b);
3011
0
                            offset = 0;
3012
0
                        }
3013
0
                        buffer[offset++] = c;
3014
0
                        size--;
3015
0
                        break;
3016
0
                    default:
3017
0
                        break;
3018
0
                }
3019
0
            }
3020
3021
0
        }
3022
3023
0
        apr_brigade_cleanup(bb);
3024
0
    } while (!seen_eos);
3025
3026
0
    if (FORM_ABORT == state || size < 0 || num == 0) {
3027
0
        return HTTP_REQUEST_ENTITY_TOO_LARGE;
3028
0
    }
3029
0
    else if (FORM_VALUE == state && pair && offset > 0) {
3030
0
        const char *tmp = apr_pmemdup(r->pool, buffer, offset);
3031
0
        apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
3032
0
        APR_BRIGADE_INSERT_TAIL(pair->value, b);
3033
0
    }
3034
3035
0
    return OK;
3036
3037
0
}
3038
3039
0
#define VARBUF_SMALL_SIZE 2048
3040
0
#define VARBUF_MAX_SIZE   (APR_SIZE_MAX - 1 -                                \
3041
0
                           APR_ALIGN_DEFAULT(sizeof(struct ap_varbuf_info)))
3042
3043
struct ap_varbuf_info {
3044
    struct apr_memnode_t *node;
3045
    apr_allocator_t *allocator;
3046
};
3047
3048
static apr_status_t varbuf_cleanup(void *info_)
3049
0
{
3050
0
    struct ap_varbuf_info *info = info_;
3051
0
    info->node->next = NULL;
3052
0
    apr_allocator_free(info->allocator, info->node);
3053
0
    return APR_SUCCESS;
3054
0
}
3055
3056
static const char nul = '\0';
3057
static char * const varbuf_empty = (char *)&nul;
3058
3059
AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
3060
                                apr_size_t init_size)
3061
0
{
3062
0
    vb->buf = varbuf_empty;
3063
0
    vb->avail = 0;
3064
0
    vb->strlen = AP_VARBUF_UNKNOWN;
3065
0
    vb->pool = p;
3066
0
    vb->info = NULL;
3067
3068
0
    ap_varbuf_grow(vb, init_size);
3069
0
}
3070
3071
AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
3072
0
{
3073
0
    apr_memnode_t *new_node = NULL;
3074
0
    apr_allocator_t *allocator;
3075
0
    struct ap_varbuf_info *new_info;
3076
0
    char *new;
3077
3078
0
    AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen);
3079
3080
0
    if (new_len <= vb->avail)
3081
0
        return;
3082
3083
0
    if (new_len < 2 * vb->avail && vb->avail < VARBUF_MAX_SIZE/2) {
3084
        /* at least double the size, to avoid repeated reallocations */
3085
0
        new_len = 2 * vb->avail;
3086
0
    }
3087
0
    else if (new_len > VARBUF_MAX_SIZE) {
3088
0
        apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
3089
0
        ap_assert(abort_fn != NULL);
3090
0
        abort_fn(APR_ENOMEM);
3091
0
        return;
3092
0
    }
3093
3094
0
    new_len++;  /* add space for trailing \0 */
3095
0
    if (new_len <= VARBUF_SMALL_SIZE) {
3096
0
        new_len = APR_ALIGN_DEFAULT(new_len);
3097
0
        new = apr_palloc(vb->pool, new_len);
3098
0
        if (vb->avail && vb->strlen != 0) {
3099
0
            AP_DEBUG_ASSERT(vb->buf != NULL);
3100
0
            AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
3101
0
            if (new == vb->buf + vb->avail + 1) {
3102
                /* We are lucky: the new memory lies directly after our old
3103
                 * buffer, we can now use both.
3104
                 */
3105
0
                vb->avail += new_len;
3106
0
                return;
3107
0
            }
3108
0
            else {
3109
                /* copy up to vb->strlen + 1 bytes */
3110
0
                memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
3111
0
                                     vb->avail + 1 : vb->strlen + 1);
3112
0
            }
3113
0
        }
3114
0
        else {
3115
0
            *new = '\0';
3116
0
        }
3117
0
        vb->avail = new_len - 1;
3118
0
        vb->buf = new;
3119
0
        return;
3120
0
    }
3121
3122
    /* The required block is rather larger. Use allocator directly so that
3123
     * the memory can be freed independently from the pool. */
3124
0
    allocator = apr_pool_allocator_get(vb->pool);
3125
    /* Happens if APR was compiled with APR_POOL_DEBUG */
3126
0
    if (allocator == NULL) {
3127
0
        apr_allocator_create(&allocator);
3128
0
        ap_assert(allocator != NULL);
3129
0
    }
3130
0
    if (new_len <= VARBUF_MAX_SIZE)
3131
0
        new_node = apr_allocator_alloc(allocator,
3132
0
                                       new_len + APR_ALIGN_DEFAULT(sizeof(*new_info)));
3133
0
    if (!new_node) {
3134
0
        apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
3135
0
        ap_assert(abort_fn != NULL);
3136
0
        abort_fn(APR_ENOMEM);
3137
0
        return;
3138
0
    }
3139
0
    new_info = (struct ap_varbuf_info *)new_node->first_avail;
3140
0
    new_node->first_avail += APR_ALIGN_DEFAULT(sizeof(*new_info));
3141
0
    new_info->node = new_node;
3142
0
    new_info->allocator = allocator;
3143
0
    new = new_node->first_avail;
3144
0
    AP_DEBUG_ASSERT(new_node->endp - new_node->first_avail >= new_len);
3145
0
    new_len = new_node->endp - new_node->first_avail;
3146
3147
0
    if (vb->avail && vb->strlen != 0)
3148
0
        memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
3149
0
                             vb->avail + 1 : vb->strlen + 1);
3150
0
    else
3151
0
        *new = '\0';
3152
0
    if (vb->info)
3153
0
        apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
3154
0
    apr_pool_cleanup_register(vb->pool, new_info, varbuf_cleanup,
3155
0
                              apr_pool_cleanup_null);
3156
0
    vb->info = new_info;
3157
0
    vb->buf = new;
3158
0
    vb->avail = new_len - 1;
3159
0
}
3160
3161
AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
3162
                                     int len)
3163
0
{
3164
0
    if (len == 0)
3165
0
        return;
3166
0
    if (!vb->avail) {
3167
0
        ap_varbuf_grow(vb, len);
3168
0
        memcpy(vb->buf, str, len);
3169
0
        vb->buf[len] = '\0';
3170
0
        vb->strlen = len;
3171
0
        return;
3172
0
    }
3173
0
    if (vb->strlen == AP_VARBUF_UNKNOWN)
3174
0
        vb->strlen = strlen(vb->buf);
3175
0
    ap_varbuf_grow(vb, vb->strlen + len);
3176
0
    memcpy(vb->buf + vb->strlen, str, len);
3177
0
    vb->strlen += len;
3178
0
    vb->buf[vb->strlen] = '\0';
3179
0
}
3180
3181
AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
3182
0
{
3183
0
    if (vb->info) {
3184
0
        apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
3185
0
        vb->info = NULL;
3186
0
    }
3187
0
    vb->buf = NULL;
3188
0
}
3189
3190
AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf,
3191
                                  const char *prepend, apr_size_t prepend_len,
3192
                                  const char *append, apr_size_t append_len,
3193
                                  apr_size_t *new_len)
3194
0
{
3195
0
    apr_size_t i = 0;
3196
0
    struct iovec vec[3];
3197
3198
0
    if (prepend) {
3199
0
        vec[i].iov_base = (void *)prepend;
3200
0
        vec[i].iov_len = prepend_len;
3201
0
        i++;
3202
0
    }
3203
0
    if (buf->avail && buf->strlen) {
3204
0
        if (buf->strlen == AP_VARBUF_UNKNOWN)
3205
0
            buf->strlen = strlen(buf->buf);
3206
0
        vec[i].iov_base = (void *)buf->buf;
3207
0
        vec[i].iov_len = buf->strlen;
3208
0
        i++;
3209
0
    }
3210
0
    if (append) {
3211
0
        vec[i].iov_base = (void *)append;
3212
0
        vec[i].iov_len = append_len;
3213
0
        i++;
3214
0
    }
3215
0
    if (i)
3216
0
        return apr_pstrcatv(p, vec, i, new_len);
3217
3218
0
    if (new_len)
3219
0
        *new_len = 0;
3220
0
    return "";
3221
0
}
3222
3223
AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
3224
                                          const char *input,
3225
                                          const char *source,
3226
                                          apr_size_t nmatch,
3227
                                          ap_regmatch_t pmatch[],
3228
                                          apr_size_t maxlen)
3229
0
{
3230
0
    return regsub_core(NULL, NULL, vb, input, source, nmatch, pmatch, maxlen);
3231
0
}
3232
3233
static const char * const oom_message = "[crit] Memory allocation failed, "
3234
                                        "aborting process." APR_EOL_STR;
3235
3236
AP_DECLARE(void) ap_abort_on_oom(void)
3237
0
{
3238
0
    int written, count = strlen(oom_message);
3239
0
    const char *buf = oom_message;
3240
0
    do {
3241
0
        written = write(STDERR_FILENO, buf, count);
3242
0
        if (written == count)
3243
0
            break;
3244
0
        if (written > 0) {
3245
0
            buf += written;
3246
0
            count -= written;
3247
0
        }
3248
0
    } while (written >= 0 || errno == EINTR);
3249
0
    abort();
3250
0
}
3251
3252
AP_DECLARE(void *) ap_malloc(size_t size)
3253
0
{
3254
0
    void *p = malloc(size);
3255
0
    if (p == NULL && size != 0)
3256
0
        ap_abort_on_oom();
3257
0
    return p;
3258
0
}
3259
3260
AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size)
3261
0
{
3262
0
    void *p = calloc(nelem, size);
3263
0
    if (p == NULL && nelem != 0 && size != 0)
3264
0
        ap_abort_on_oom();
3265
0
    return p;
3266
0
}
3267
3268
AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
3269
0
{
3270
0
    void *p = realloc(ptr, size);
3271
0
    if (p == NULL && size != 0)
3272
0
        ap_abort_on_oom();
3273
0
    return p;
3274
0
}
3275
3276
#if APR_HAS_THREADS
3277
3278
#if AP_HAS_THREAD_LOCAL && !APR_VERSION_AT_LEAST(1,8,0)
3279
static AP_THREAD_LOCAL apr_thread_t *current_thread = NULL;
3280
#endif
3281
3282
struct thread_ctx {
3283
    apr_thread_start_t func;
3284
    void *data;
3285
};
3286
3287
static void *APR_THREAD_FUNC thread_start(apr_thread_t *thread, void *data)
3288
0
{
3289
0
    struct thread_ctx *ctx = data;
3290
3291
    /* Don't let the thread's pool allocator with no limits, though there
3292
     * is possibly no allocator with APR <= 1.7 and APR_POOL_DEBUG.
3293
     */
3294
0
    {
3295
0
        apr_pool_t *tp = apr_thread_pool_get(thread);
3296
0
        apr_allocator_t *ta = apr_pool_allocator_get(tp);
3297
0
        if (ta) {
3298
0
            apr_allocator_max_free_set(ta, ap_max_mem_free);
3299
0
        }
3300
0
    }
3301
3302
#if AP_HAS_THREAD_LOCAL && !APR_VERSION_AT_LEAST(1,8,0)
3303
    current_thread = thread;
3304
#endif
3305
0
    return ctx->func(thread, ctx->data);
3306
0
}
3307
3308
AP_DECLARE(apr_status_t) ap_thread_create(apr_thread_t **thread, 
3309
                                          apr_threadattr_t *attr, 
3310
                                          apr_thread_start_t func, 
3311
                                          void *data, apr_pool_t *pool)
3312
0
{
3313
0
    struct thread_ctx *ctx = apr_palloc(pool, sizeof(*ctx));
3314
3315
0
    ctx->func = func;
3316
0
    ctx->data = data;
3317
0
    return apr_thread_create(thread, attr, thread_start, ctx, pool);
3318
0
}
3319
3320
static apr_status_t main_thread_cleanup(void *arg)
3321
0
{
3322
0
    apr_thread_t *thd = arg;
3323
0
    apr_pool_destroy(apr_thread_pool_get(thd));
3324
0
    return APR_SUCCESS;
3325
0
}
3326
3327
AP_DECLARE(apr_status_t) ap_thread_main_create(apr_thread_t **thread,
3328
                                               apr_pool_t *pool)
3329
0
{
3330
0
    apr_status_t rv;
3331
0
    apr_threadattr_t *attr = NULL;
3332
3333
    /* Create an apr_thread_t for the main child thread to set up its Thread
3334
     * Local Storage. Since it's detached and won't apr_thread_exit(), destroy
3335
     * its pool before exiting via a cleanup of the given pool.
3336
     */
3337
0
    if ((rv = apr_threadattr_create(&attr, pool))
3338
0
            || (rv = apr_threadattr_detach_set(attr, 1))
3339
0
#if APR_VERSION_AT_LEAST(1,8,0)
3340
0
            || (rv = apr_threadattr_max_free_set(attr, ap_max_mem_free))
3341
0
#endif
3342
0
            || (rv = ap_thread_current_create(thread, attr, pool))) {
3343
0
        *thread = NULL;
3344
0
        return rv;
3345
0
    }
3346
3347
0
    apr_pool_cleanup_register(pool, *thread, main_thread_cleanup,
3348
0
                              apr_pool_cleanup_null);
3349
0
    return APR_SUCCESS;
3350
0
}
3351
3352
#if !APR_VERSION_AT_LEAST(1,8,0)
3353
3354
AP_DECLARE(apr_status_t) ap_thread_current_create(apr_thread_t **current,
3355
                                                  apr_threadattr_t *attr,
3356
                                                  apr_pool_t *pool)
3357
{
3358
#if AP_HAS_THREAD_LOCAL
3359
    apr_status_t rv;
3360
    apr_allocator_t *ta;
3361
    apr_abortfunc_t abort_fn;
3362
    apr_os_thread_t osthd;
3363
    apr_pool_t *p;
3364
3365
    *current = ap_thread_current();
3366
    if (*current) {
3367
        return APR_EEXIST;
3368
    }
3369
3370
    abort_fn = (pool) ? apr_pool_abort_get(pool) : NULL;
3371
    rv = apr_allocator_create(&ta);
3372
    if (rv != APR_SUCCESS) {
3373
        if (abort_fn)
3374
            abort_fn(rv);
3375
        return rv;
3376
    }
3377
    /* Don't let the thread's pool allocator with no limits */
3378
    apr_allocator_max_free_set(ta, ap_max_mem_free);
3379
    rv = apr_pool_create_unmanaged_ex(&p, abort_fn, ta);
3380
    if (rv != APR_SUCCESS) {
3381
        return rv;
3382
    }
3383
    apr_allocator_owner_set(ta, p);
3384
3385
    osthd = apr_os_thread_current();
3386
    rv = apr_os_thread_put(current, &osthd, p);
3387
    if (rv != APR_SUCCESS) {
3388
        apr_pool_destroy(p);
3389
        return rv;
3390
    }
3391
3392
    current_thread = *current;
3393
    return APR_SUCCESS;
3394
#else
3395
    return APR_ENOTIMPL;
3396
#endif
3397
}
3398
3399
AP_DECLARE(void) ap_thread_current_after_fork(void)
3400
{
3401
#if AP_HAS_THREAD_LOCAL
3402
    current_thread = NULL;
3403
#endif
3404
}
3405
3406
AP_DECLARE(apr_thread_t *) ap_thread_current(void)
3407
{
3408
#if AP_HAS_THREAD_LOCAL
3409
    return current_thread;
3410
#else
3411
    return NULL;
3412
#endif
3413
}
3414
3415
#endif /* !APR_VERSION_AT_LEAST(1,8,0) */
3416
3417
#endif /* APR_HAS_THREADS */
3418
3419
AP_DECLARE(void) ap_get_sload(ap_sload_t *ld)
3420
0
{
3421
0
    int i, j, server_limit, thread_limit;
3422
0
    int ready = 0;
3423
0
    int busy = 0;
3424
0
    int total;
3425
0
    ap_generation_t mpm_generation;
3426
3427
    /* preload errored fields, we overwrite */
3428
0
    ld->idle = -1;
3429
0
    ld->busy = -1;
3430
0
    ld->bytes_served = 0;
3431
0
    ld->access_count = 0;
3432
3433
0
    ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
3434
0
    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
3435
0
    ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
3436
3437
0
    for (i = 0; i < server_limit; i++) {
3438
0
        process_score *ps;
3439
0
        ps = ap_get_scoreboard_process(i);
3440
3441
0
        for (j = 0; j < thread_limit; j++) {
3442
0
            int res;
3443
0
            worker_score *ws = NULL;
3444
0
            ws = &ap_scoreboard_image->servers[i][j];
3445
0
            res = ws->status;
3446
3447
0
            if (!ps->quiescing && ps->pid) {
3448
0
                if (res == SERVER_READY && ps->generation == mpm_generation) {
3449
0
                    ready++;
3450
0
                }
3451
0
                else if (res != SERVER_DEAD &&
3452
0
                         res != SERVER_STARTING && res != SERVER_IDLE_KILL &&
3453
0
                         ps->generation == mpm_generation) {
3454
0
                    busy++;
3455
0
                }   
3456
0
            }
3457
3458
0
            if (ap_extended_status && !ps->quiescing && ps->pid) {
3459
0
                if (ws->access_count != 0 
3460
0
                    || (res != SERVER_READY && res != SERVER_DEAD)) {
3461
0
                    ld->access_count += ws->access_count;
3462
0
                    ld->bytes_served += ws->bytes_served;
3463
0
                }
3464
0
            }
3465
0
        }
3466
0
    }
3467
0
    total = busy + ready;
3468
0
    if (total) {
3469
0
        ld->idle = ready * 100 / total;
3470
0
        ld->busy = busy * 100 / total;
3471
0
    }
3472
0
}
3473
3474
AP_DECLARE(void) ap_get_loadavg(ap_loadavg_t *ld)
3475
0
{
3476
    /* preload errored fields, we overwrite */
3477
0
    ld->loadavg = -1.0;
3478
0
    ld->loadavg5 = -1.0;
3479
0
    ld->loadavg15 = -1.0;
3480
3481
0
#if HAVE_GETLOADAVG
3482
0
    {
3483
0
        double la[3];
3484
0
        int num;
3485
3486
0
        num = getloadavg(la, 3);
3487
0
        if (num > 0) {
3488
0
            ld->loadavg = (float)la[0];
3489
0
        }
3490
0
        if (num > 1) {
3491
0
            ld->loadavg5 = (float)la[1];
3492
0
        }
3493
0
        if (num > 2) {
3494
0
            ld->loadavg15 = (float)la[2];
3495
0
        }
3496
0
    }
3497
0
#endif
3498
0
}
3499
3500
static const char * const pw_cache_note_name = "conn_cache_note";
3501
struct pw_cache {
3502
    /* varbuf contains concatenated password and hash */
3503
    struct ap_varbuf vb;
3504
    apr_size_t pwlen;
3505
    apr_status_t result;
3506
};
3507
3508
AP_DECLARE(apr_status_t) ap_password_validate(request_rec *r,
3509
                                              const char *username,
3510
                                              const char *passwd,
3511
                                              const char *hash)
3512
0
{
3513
0
    struct pw_cache *cache;
3514
0
    apr_size_t hashlen;
3515
3516
0
    cache = (struct pw_cache *)apr_table_get(r->connection->notes, pw_cache_note_name);
3517
0
    if (cache != NULL) {
3518
0
        if (strncmp(passwd, cache->vb.buf, cache->pwlen) == 0
3519
0
            && strcmp(hash, cache->vb.buf + cache->pwlen) == 0) {
3520
0
            return cache->result;
3521
0
        }
3522
        /* make ap_varbuf_grow below not copy the old data */
3523
0
        cache->vb.strlen = 0;
3524
0
    }
3525
0
    else {
3526
0
        cache = apr_palloc(r->connection->pool, sizeof(struct pw_cache));
3527
0
        ap_varbuf_init(r->connection->pool, &cache->vb, 0);
3528
0
        apr_table_setn(r->connection->notes, pw_cache_note_name, (void *)cache);
3529
0
    }
3530
0
    cache->pwlen = strlen(passwd);
3531
0
    hashlen = strlen(hash);
3532
0
    ap_varbuf_grow(&cache->vb, cache->pwlen + hashlen + 1);
3533
0
    memcpy(cache->vb.buf, passwd, cache->pwlen);
3534
0
    memcpy(cache->vb.buf + cache->pwlen, hash, hashlen + 1);
3535
0
    cache->result = apr_password_validate(passwd, hash);
3536
0
    return cache->result;
3537
0
}
3538
3539
AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p,
3540
                                    const char *cmd,
3541
                                    const char * const * argv)
3542
0
{
3543
0
    char buf[MAX_STRING_LEN];
3544
0
    apr_procattr_t *procattr;
3545
0
    apr_proc_t *proc;
3546
0
    apr_file_t *fp;
3547
0
    apr_size_t nbytes = 1;
3548
0
    char c;
3549
0
    int k;
3550
3551
0
    if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
3552
0
        return NULL;
3553
0
    if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
3554
0
                            APR_FULL_BLOCK) != APR_SUCCESS)
3555
0
        return NULL;
3556
0
    if (apr_procattr_dir_set(procattr,
3557
0
                             ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
3558
0
        return NULL;
3559
0
    if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
3560
0
        return NULL;
3561
0
    proc = apr_pcalloc(p, sizeof(apr_proc_t));
3562
0
    if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
3563
0
        return NULL;
3564
0
    fp = proc->out;
3565
3566
0
    if (fp == NULL)
3567
0
        return NULL;
3568
    /* XXX: we are reading 1 byte at a time here */
3569
0
    for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
3570
0
                && nbytes == 1 && (k < MAX_STRING_LEN-1)     ; ) {
3571
0
        if (c == '\n' || c == '\r')
3572
0
            break;
3573
0
        buf[k++] = c;
3574
0
    }
3575
0
    buf[k] = '\0'; 
3576
0
    apr_file_close(fp);
3577
3578
0
    return apr_pstrndup(p, buf, k);
3579
0
}
3580
3581
AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array, 
3582
                                   const char *s,
3583
                                   int start)
3584
0
{
3585
0
    if (start >= 0) {
3586
0
        int i;
3587
        
3588
0
        for (i = start; i < array->nelts; i++) {
3589
0
            const char *p = APR_ARRAY_IDX(array, i, const char *);
3590
0
            if (!strcmp(p, s)) {
3591
0
                return i;
3592
0
            }
3593
0
        }
3594
0
    }
3595
    
3596
0
    return -1;
3597
0
}
3598
3599
AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array, 
3600
                                      const char *s)
3601
0
{
3602
0
    return (ap_array_str_index(array, s, 0) >= 0);
3603
0
}
3604
3605
#if !APR_CHARSET_EBCDIC
3606
/*
3607
 * Our own known-fast translation table for casecmp by character.
3608
 * Only ASCII alpha characters 41-5A are folded to 61-7A, other
3609
 * octets (such as extended latin alphabetics) are never case-folded.
3610
 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3611
 */
3612
static const unsigned char ucharmap[256] = {
3613
    0x0,  0x1,  0x2,  0x3,  0x4,  0x5,  0x6,  0x7,
3614
    0x8,  0x9,  0xa,  0xb,  0xc,  0xd,  0xe,  0xf,
3615
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3616
    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3617
    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3618
    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3619
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3620
    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3621
    0x40,  'a',  'b',  'c',  'd',  'e',  'f',  'g',
3622
     'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
3623
     'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
3624
     'x',  'y',  'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3625
    0x60,  'a',  'b',  'c',  'd',  'e',  'f',  'g',
3626
     'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
3627
     'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
3628
     'x',  'y',  'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3629
    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3630
    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3631
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3632
    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3633
    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3634
    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3635
    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3636
    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3637
    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3638
    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3639
    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3640
    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3641
    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3642
    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3643
    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3644
    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3645
};
3646
#else /* APR_CHARSET_EBCDIC */
3647
/*
3648
 * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison,
3649
 * provides unique identity of every char value (strict ISO-646
3650
 * conformance, arbitrary election of an ISO-8859-1 ordering, and
3651
 * very arbitrary control code assignments into C1 to achieve
3652
 * identity and a reversible mapping of code points),
3653
 * then folding the equivalences of ASCII 41-5A into 61-7A, 
3654
 * presenting comparison results in a somewhat ISO/IEC 10646
3655
 * (ASCII-like) order, depending on the EBCDIC code page in use.
3656
 *
3657
 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3658
 */
3659
static const unsigned char ucharmap[256] = {
3660
    0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
3661
    0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
3662
    0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
3663
    0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
3664
    0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
3665
    0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
3666
    0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
3667
    0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
3668
    0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,
3669
    0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
3670
    0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,
3671
    0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
3672
    0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,
3673
    0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
3674
    0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,
3675
    0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
3676
    0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3677
    0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
3678
    0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3679
    0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
3680
    0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3681
    0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,
3682
    0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,
3683
    0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,
3684
    0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3685
    0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
3686
    0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3687
    0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
3688
    0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3689
    0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
3690
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3691
    0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F
3692
};
3693
#endif
3694
3695
AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2)
3696
2.64k
{
3697
2.64k
    const unsigned char *u1 = (const unsigned char *)s1;
3698
2.64k
    const unsigned char *u2 = (const unsigned char *)s2;
3699
3.37k
    for (;;) {
3700
3.37k
        const int c2 = ucharmap[*u2++];
3701
3.37k
        const int cmp = (int)ucharmap[*u1++] - c2;
3702
        /* Not necessary to test for !c1, this is caught by cmp */
3703
3.37k
        if (cmp || !c2)
3704
2.64k
            return cmp;
3705
3.37k
    }
3706
2.64k
}
3707
3708
AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
3709
5.75k
{
3710
5.75k
    const unsigned char *u1 = (const unsigned char *)s1;
3711
5.75k
    const unsigned char *u2 = (const unsigned char *)s2;
3712
8.25k
    while (n--) {
3713
8.11k
        const int c2 = ucharmap[*u2++];
3714
8.11k
        const int cmp = (int)ucharmap[*u1++] - c2;
3715
        /* Not necessary to test for !c1, this is caught by cmp */
3716
8.11k
        if (cmp || !c2)
3717
5.60k
            return cmp;
3718
8.11k
    }
3719
141
    return 0;
3720
5.75k
}
3721
3722
typedef struct {
3723
    const char *fname;
3724
} fnames;
3725
3726
static int fname_alphasort(const void *fn1, const void *fn2)
3727
0
{
3728
0
    const fnames *f1 = fn1;
3729
0
    const fnames *f2 = fn2;
3730
3731
0
    return strcmp(f1->fname, f2->fname);
3732
0
}
3733
3734
AP_DECLARE(ap_dir_match_t *)ap_dir_cfgmatch(cmd_parms *cmd, int flags,
3735
        const char *(*cb)(ap_dir_match_t *w, const char *fname), void *ctx)
3736
0
{
3737
0
    ap_dir_match_t *w = apr_palloc(cmd->temp_pool, sizeof(*w));
3738
3739
0
    w->prefix = apr_pstrcat(cmd->pool, cmd->cmd->name, ": ", NULL);
3740
0
    w->p = cmd->pool;
3741
0
    w->ptemp = cmd->temp_pool;
3742
0
    w->flags = flags;
3743
0
    w->cb = cb;
3744
0
    w->ctx = ctx;
3745
0
    w->depth = 0;
3746
3747
0
    return w;
3748
0
}
3749
3750
AP_DECLARE(const char *)ap_dir_nofnmatch(ap_dir_match_t *w, const char *fname)
3751
0
{
3752
0
    const char *error;
3753
0
    apr_status_t rv;
3754
3755
0
    if ((w->flags & AP_DIR_FLAG_RECURSIVE) && ap_is_directory(w->ptemp, fname)) {
3756
0
        apr_dir_t *dirp;
3757
0
        apr_finfo_t dirent;
3758
0
        int current;
3759
0
        apr_array_header_t *candidates = NULL;
3760
0
        fnames *fnew;
3761
0
        char *path = apr_pstrdup(w->ptemp, fname);
3762
3763
0
        if (++w->depth > AP_MAX_FNMATCH_DIR_DEPTH) {
3764
0
            return apr_psprintf(w->p, "%sDirectory '%s' exceeds the maximum include "
3765
0
                    "directory nesting level of %u. You have "
3766
0
                    "probably a recursion somewhere.", w->prefix ? w->prefix : "", path,
3767
0
                    AP_MAX_FNMATCH_DIR_DEPTH);
3768
0
        }
3769
3770
        /*
3771
         * first course of business is to grok all the directory
3772
         * entries here and store 'em away. Recall we need full pathnames
3773
         * for this.
3774
         */
3775
0
        rv = apr_dir_open(&dirp, path, w->ptemp);
3776
0
        if (rv != APR_SUCCESS) {
3777
0
            return apr_psprintf(w->p, "%sCould not open directory %s: %pm",
3778
0
                    w->prefix ? w->prefix : "", path, &rv);
3779
0
        }
3780
3781
0
        candidates = apr_array_make(w->ptemp, 1, sizeof(fnames));
3782
0
        while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) {
3783
            /* strip out '.' and '..' */
3784
0
            if (strcmp(dirent.name, ".")
3785
0
                && strcmp(dirent.name, "..")) {
3786
0
                fnew = (fnames *) apr_array_push(candidates);
3787
0
                fnew->fname = ap_make_full_path(w->ptemp, path, dirent.name);
3788
0
            }
3789
0
        }
3790
3791
0
        apr_dir_close(dirp);
3792
0
        if (candidates->nelts != 0) {
3793
0
            qsort((void *) candidates->elts, candidates->nelts,
3794
0
                  sizeof(fnames), fname_alphasort);
3795
3796
            /*
3797
             * Now recurse these... we handle errors and subdirectories
3798
             * via the recursion, which is nice
3799
             */
3800
0
            for (current = 0; current < candidates->nelts; ++current) {
3801
0
                fnew = &((fnames *) candidates->elts)[current];
3802
0
                error = ap_dir_nofnmatch(w, fnew->fname);
3803
0
                if (error) {
3804
0
                    return error;
3805
0
                }
3806
0
            }
3807
0
        }
3808
3809
0
        w->depth--;
3810
3811
0
        return NULL;
3812
0
    }
3813
0
    else if (w->flags & AP_DIR_FLAG_OPTIONAL) {
3814
        /* If the optional flag is set (like for IncludeOptional) we can
3815
         * tolerate that no file or directory is present and bail out.
3816
         */
3817
0
        apr_finfo_t finfo;
3818
0
        if (apr_stat(&finfo, fname, APR_FINFO_TYPE, w->ptemp) != APR_SUCCESS
3819
0
            || finfo.filetype == APR_NOFILE)
3820
0
            return NULL;
3821
0
    }
3822
3823
0
    return w->cb(w, fname);
3824
0
}
3825
3826
AP_DECLARE(const char *)ap_dir_fnmatch(ap_dir_match_t *w, const char *path,
3827
        const char *fname)
3828
0
{
3829
0
    const char *rest;
3830
0
    apr_status_t rv;
3831
0
    apr_dir_t *dirp;
3832
0
    apr_finfo_t dirent;
3833
0
    apr_array_header_t *candidates = NULL;
3834
0
    fnames *fnew;
3835
0
    int current;
3836
3837
    /* find the first part of the filename */
3838
0
    rest = ap_strchr_c(fname, '/');
3839
0
    if (rest) {
3840
0
        fname = apr_pstrmemdup(w->ptemp, fname, rest - fname);
3841
0
        rest++;
3842
0
    }
3843
3844
    /* optimisation - if the filename isn't a wildcard, process it directly */
3845
0
    if (!apr_fnmatch_test(fname)) {
3846
0
        path = path ? ap_make_full_path(w->ptemp, path, fname) : fname;
3847
0
        if (!rest) {
3848
0
            return ap_dir_nofnmatch(w, path);
3849
0
        }
3850
0
        else {
3851
0
            return ap_dir_fnmatch(w, path, rest);
3852
0
        }
3853
0
    }
3854
3855
    /*
3856
     * first course of business is to grok all the directory
3857
     * entries here and store 'em away. Recall we need full pathnames
3858
     * for this.
3859
     */
3860
0
    rv = apr_dir_open(&dirp, path, w->ptemp);
3861
0
    if (rv != APR_SUCCESS) {
3862
        /* If the directory doesn't exist and the optional flag is set
3863
         * there is no need to return an error.
3864
         */
3865
0
        if (rv == APR_ENOENT && (w->flags & AP_DIR_FLAG_OPTIONAL)) {
3866
0
            return NULL;
3867
0
        }
3868
0
        return apr_psprintf(w->p, "%sCould not open directory %s: %pm",
3869
0
                w->prefix ? w->prefix : "", path, &rv);
3870
0
    }
3871
3872
0
    candidates = apr_array_make(w->ptemp, 1, sizeof(fnames));
3873
0
    while (apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_TYPE, dirp) == APR_SUCCESS) {
3874
        /* strip out '.' and '..' */
3875
0
        if (strcmp(dirent.name, ".")
3876
0
            && strcmp(dirent.name, "..")
3877
0
            && (apr_fnmatch(fname, dirent.name,
3878
0
                            APR_FNM_PERIOD) == APR_SUCCESS)) {
3879
0
            const char *full_path = ap_make_full_path(w->ptemp, path, dirent.name);
3880
            /* If matching internal to path, and we happen to match something
3881
             * other than a directory, skip it
3882
             */
3883
0
            if (rest && (dirent.filetype != APR_DIR)) {
3884
0
                continue;
3885
0
            }
3886
0
            fnew = (fnames *) apr_array_push(candidates);
3887
0
            fnew->fname = full_path;
3888
0
        }
3889
0
    }
3890
3891
0
    apr_dir_close(dirp);
3892
0
    if (candidates->nelts != 0) {
3893
0
        const char *error;
3894
3895
0
        qsort((void *) candidates->elts, candidates->nelts,
3896
0
              sizeof(fnames), fname_alphasort);
3897
3898
        /*
3899
         * Now recurse these... we handle errors and subdirectories
3900
         * via the recursion, which is nice
3901
         */
3902
0
        for (current = 0; current < candidates->nelts; ++current) {
3903
0
            fnew = &((fnames *) candidates->elts)[current];
3904
0
            if (!rest) {
3905
0
                error = ap_dir_nofnmatch(w, fnew->fname);
3906
0
            }
3907
0
            else {
3908
0
                error = ap_dir_fnmatch(w, fnew->fname, rest);
3909
0
            }
3910
0
            if (error) {
3911
0
                return error;
3912
0
            }
3913
0
        }
3914
0
    }
3915
0
    else {
3916
3917
0
        if (!(w->flags & AP_DIR_FLAG_OPTIONAL)) {
3918
0
            return apr_psprintf(w->p, "%sNo matches for the wildcard '%s' in '%s', failing",
3919
0
                    w->prefix ? w->prefix : "", fname, path);
3920
0
        }
3921
0
    }
3922
3923
0
    return NULL;
3924
0
}