Coverage Report

Created: 2023-03-26 06:28

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