Coverage Report

Created: 2026-09-04 06:29

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