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
0
#define IS_SLASH(s) (s == '/')
88
0
#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
0
{
106
0
    const char *semi;
107
108
0
    if (intype == NULL) return NULL;
109
110
0
    semi = ap_strchr_c(intype, ';');
111
0
    if (semi == NULL) {
112
0
        return apr_pstrdup(p, intype);
113
0
    }
114
0
    else {
115
0
        while ((semi > intype) && apr_isspace(semi[-1])) {
116
0
            semi--;
117
0
        }
118
0
        return apr_pstrmemdup(p, intype, semi - intype);
119
0
    }
120
0
}
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
0
{
190
0
    apr_size_t x, y;
191
192
0
    for (x = 0, y = 0; expected[y]; ++y, ++x) {
193
0
        if (expected[y] == '*') {
194
0
            while (expected[++y] == '*');
195
0
            if (!expected[y])
196
0
                return 0;
197
0
            while (str[x]) {
198
0
                int ret;
199
0
                if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1)
200
0
                    return ret;
201
0
            }
202
0
            return -1;
203
0
        }
204
0
        else if (!str[x])
205
0
            return -1;
206
0
        else if ((expected[y] != '?') && (str[x] != expected[y]))
207
0
            return 1;
208
0
    }
209
0
    return (str[x] != '\0');
210
0
}
211
212
AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
213
0
{
214
0
    apr_size_t x, y;
215
216
0
    for (x = 0, y = 0; expected[y]; ++y, ++x) {
217
0
        if (!str[x] && expected[y] != '*')
218
0
            return -1;
219
0
        if (expected[y] == '*') {
220
0
            while (expected[++y] == '*');
221
0
            if (!expected[y])
222
0
                return 0;
223
0
            while (str[x]) {
224
0
                int ret;
225
0
                if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1)
226
0
                    return ret;
227
0
            }
228
0
            return -1;
229
0
        }
230
0
        else if (expected[y] != '?'
231
0
                 && apr_tolower(str[x]) != apr_tolower(expected[y]))
232
0
            return 1;
233
0
    }
234
0
    return (str[x] != '\0');
235
0
}
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
0
{
304
0
    char *p1, *p2;
305
0
    if (*s2 == '\0') {
306
        /* an empty s2 */
307
0
        return((char *)s1);
308
0
    }
309
0
    while(1) {
310
0
        for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
311
0
        if (*s1 == '\0') {
312
0
            return(NULL);
313
0
        }
314
        /* found first character of s2, see if the rest matches */
315
0
        p1 = (char *)s1;
316
0
        p2 = (char *)s2;
317
0
        for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
318
0
            if (*p1 == '\0') {
319
                /* both strings ended together */
320
0
                return((char *)s1);
321
0
            }
322
0
        }
323
0
        if (*p2 == '\0') {
324
            /* second string ended, a match */
325
0
            break;
326
0
        }
327
        /* didn't find a match here, try starting at next character in s1 */
328
0
        s1++;
329
0
    }
330
0
    return((char *)s1);
331
0
}
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
0
#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
0
{
504
0
    int ret = 1;
505
0
    apr_size_t l = 1, w = 1, n;
506
0
    int decode_unreserved = (flags & AP_NORMALIZE_DECODE_UNRESERVED) != 0;
507
0
    int merge_slashes = (flags & AP_NORMALIZE_MERGE_SLASHES) != 0;
508
509
0
    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
0
        if (path[0] == '*' && path[1] == '\0') {
514
0
            return 1;
515
0
        }
516
        /* However, AP_NORMALIZE_ALLOW_RELATIVE can be used to bypass
517
         * this restriction (e.g. for subrequest file lookups).
518
         */
519
0
        if (!(flags & AP_NORMALIZE_ALLOW_RELATIVE) || path[0] == '\0') {
520
0
            return 0;
521
0
        }
522
523
0
        l = w = 0;
524
0
    }
525
526
0
    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
0
        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
0
        if (w == 0 || IS_SLASH(path[w - 1])) {
551
            /* Collapse ///// sequences to / */
552
0
            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
0
            if (path[l] == '.') {
560
                /* Remove /./ segments */
561
0
                if (IS_SLASH_OR_NUL(path[l + 1])) {
562
0
                    l++;
563
0
                    if (path[l]) {
564
0
                        l++;
565
0
                    }
566
0
                    continue;
567
0
                }
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
0
                n = l + 1;
574
0
                if ((path[n] == '.' || (decode_unreserved
575
0
                                        && path[n] == '%'
576
0
                                        && path[++n] == '2'
577
0
                                        && (path[++n] == 'e'
578
0
                                            || path[n] == 'E')))
579
0
                        && IS_SLASH_OR_NUL(path[n + 1])) {
580
                    /* Wind w back to remove the previous segment */
581
0
                    if (w > 1) {
582
0
                        do {
583
0
                            w--;
584
0
                        } while (w && !IS_SLASH(path[w - 1]));
585
0
                    }
586
0
                    else {
587
                        /* Already at root, ignore and return a failure
588
                         * if asked to.
589
                         */
590
0
                        if (flags & AP_NORMALIZE_NOT_ABOVE_ROOT) {
591
0
                            ret = 0;
592
0
                        }
593
0
                    }
594
595
                    /* Move l forward to the next segment */
596
0
                    l = n + 1;
597
0
                    if (path[l]) {
598
0
                        l++;
599
0
                    }
600
0
                    continue;
601
0
                }
602
0
            }
603
0
        }
604
605
0
        path[w++] = path[l++];
606
0
    }
607
0
    path[w] = '\0';
608
609
0
    return ret;
610
0
}
611
612
/*
613
 * Parse .. so we don't compromise security
614
 */
615
AP_DECLARE(void) ap_getparents(char *name)
616
0
{
617
0
    if (!ap_normalize_path(name, AP_NORMALIZE_NOT_ABOVE_ROOT |
618
0
                                 AP_NORMALIZE_ALLOW_RELATIVE)) {
619
0
        name[0] = '\0';
620
0
    }
621
0
}
622
623
AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path)
624
0
{
625
626
0
    char *d, *s;
627
628
0
    if (!*name) {
629
0
        return;
630
0
    }
631
632
0
    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
0
    while (*s) {
641
0
        if ((*d++ = *s) == '/') {
642
0
            do {
643
0
                ++s;
644
0
            } while (*s == '/');
645
0
        }
646
0
        else {
647
0
            ++s;
648
0
        }
649
0
    }
650
0
    *d = '\0';
651
0
}
652
653
AP_DECLARE(void) ap_no2slash(char *name)
654
0
{
655
0
    ap_no2slash_ex(name, 1);
656
0
}
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
0
{
707
0
    const char *last_slash = ap_strrchr_c(s, '/');
708
0
    char *d;
709
0
    int l;
710
711
0
    if (last_slash == NULL) {
712
0
        return apr_pstrdup(p, "");
713
0
    }
714
0
    l = (last_slash - s) + 1;
715
0
    d = apr_pstrmemdup(p, s, l);
716
717
0
    return (d);
718
0
}
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
0
{
738
0
    const char *pos = *line;
739
0
    int len;
740
0
    char *res;
741
742
0
    while ((*pos != stop) && *pos) {
743
0
        ++pos;
744
0
    }
745
746
0
    len = pos - *line;
747
0
    res = apr_pstrmemdup(atrans, *line, len);
748
749
0
    if (stop) {
750
0
        while (*pos == stop) {
751
0
            ++pos;
752
0
        }
753
0
    }
754
0
    *line = pos;
755
756
0
    return res;
757
0
}
758
759
AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
760
0
{
761
0
    return ap_getword_white(atrans, (const char **) line);
762
0
}
763
764
AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
765
0
{
766
0
    const char *pos = *line;
767
0
    int len;
768
0
    char *res;
769
770
0
    while (!apr_isspace(*pos) && *pos) {
771
0
        ++pos;
772
0
    }
773
774
0
    len = pos - *line;
775
0
    res = apr_pstrmemdup(atrans, *line, len);
776
777
0
    while (apr_isspace(*pos)) {
778
0
        ++pos;
779
0
    }
780
781
0
    *line = pos;
782
783
0
    return res;
784
0
}
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
0
{
821
0
    char *result = apr_palloc(p, len + 1);
822
0
    char *resp = result;
823
0
    int i;
824
825
0
    for (i = 0; i < len; ++i) {
826
0
        if (start[i] == '\\' && (start[i + 1] == '\\'
827
0
                                 || (quote && start[i + 1] == quote)))
828
0
            *resp++ = start[++i];
829
0
        else
830
0
            *resp++ = start[i];
831
0
    }
832
833
0
    *resp++ = '\0';
834
#if RESOLVE_ENV_PER_TOKEN
835
    return (char *)ap_resolve_env(p,result);
836
#else
837
0
    return result;
838
0
#endif
839
0
}
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
0
{
848
0
    const char *str = *line, *strend;
849
0
    char *res;
850
0
    char quote;
851
852
0
    while (apr_isspace(*str))
853
0
        ++str;
854
855
0
    if (!*str) {
856
0
        *line = str;
857
0
        return "";
858
0
    }
859
860
0
    if ((quote = *str) == '"' || quote == '\'') {
861
0
        strend = str + 1;
862
0
        while (*strend && *strend != quote) {
863
0
            if (*strend == '\\' && strend[1] &&
864
0
                (strend[1] == quote || strend[1] == '\\')) {
865
0
                strend += 2;
866
0
            }
867
0
            else {
868
0
                ++strend;
869
0
            }
870
0
        }
871
0
        res = substring_conf(p, str + 1, strend - str - 1, quote);
872
873
0
        if (*strend == quote)
874
0
            ++strend;
875
0
    }
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
0
    while (apr_isspace(*strend))
885
0
        ++strend;
886
0
    *line = strend;
887
0
    return res;
888
0
}
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
0
{
897
0
    const char *str = *line, *strend;
898
0
    char *res;
899
0
    char quote;
900
0
    int count = 1;
901
902
0
    while (apr_isspace(*str))
903
0
        ++str;
904
905
0
    if (!*str) {
906
0
        *line = str;
907
0
        return "";
908
0
    }
909
910
0
    if ((quote = *str) == '"' || quote == '\'')
911
0
        return ap_getword_conf(p, line);
912
913
0
    if (quote == '{') {
914
0
        strend = str + 1;
915
0
        while (*strend) {
916
0
            if (*strend == '}' && !--count)
917
0
                break;
918
0
            if (*strend == '{')
919
0
                ++count;
920
0
            if (*strend == '\\' && strend[1] == '\\') {
921
0
                ++strend;
922
0
            }
923
0
            ++strend;
924
0
        }
925
0
        res = substring_conf(p, str + 1, strend - str - 1, 0);
926
927
0
        if (*strend == '}')
928
0
            ++strend;
929
0
    }
930
0
    else {
931
0
        strend = str;
932
0
        while (*strend && !apr_isspace(*strend))
933
0
            ++strend;
934
935
0
        res = substring_conf(p, str, strend - str, 0);
936
0
    }
937
938
0
    while (apr_isspace(*strend))
939
0
        ++strend;
940
0
    *line = strend;
941
0
    return res;
942
0
}
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
0
{
961
0
    return apr_file_getc(ch, param);
962
0
}
963
964
static apr_status_t cfg_getstr(void *buf, apr_size_t bufsiz, void *param)
965
0
{
966
0
    return apr_file_gets(buf, bufsiz, param);
967
0
}
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
0
{
973
0
    ap_configfile_t *new_cfg;
974
0
    apr_file_t *file = NULL;
975
0
    apr_finfo_t finfo;
976
0
    apr_status_t status;
977
#ifdef DEBUG
978
    char buf[120];
979
#endif
980
981
0
    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
0
    status = apr_file_open(&file, name, APR_READ | APR_BUFFERED,
988
0
                           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
0
    if (status != APR_SUCCESS)
996
0
        return status;
997
998
0
    status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file);
999
0
    if (status != APR_SUCCESS)
1000
0
        return status;
1001
1002
0
    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
0
        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
0
    new_cfg = apr_palloc(p, sizeof(*new_cfg));
1039
0
    new_cfg->param = file;
1040
0
    new_cfg->name = apr_pstrdup(p, name);
1041
0
    new_cfg->getch = cfg_getch;
1042
0
    new_cfg->getstr = cfg_getstr;
1043
0
    new_cfg->close = cfg_close;
1044
0
    new_cfg->line_number = 0;
1045
0
    *ret_cfg = new_cfg;
1046
0
    return APR_SUCCESS;
1047
0
}
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
0
{
1095
0
    apr_status_t rc;
1096
    /* If a "get string" function is defined, use it */
1097
0
    if (cfp->getstr != NULL) {
1098
0
        char *cp;
1099
0
        char *cbuf = buf + offset;
1100
0
        apr_size_t cbufsize = bufsize - offset;
1101
1102
0
        while (1) {
1103
0
            ++cfp->line_number;
1104
0
            rc = cfp->getstr(cbuf, cbufsize, cfp->param);
1105
0
            if (rc == APR_EOF) {
1106
0
                if (cbuf != buf + offset) {
1107
0
                    *cbuf = '\0';
1108
0
                    break;
1109
0
                }
1110
0
                else {
1111
0
                    return APR_EOF;
1112
0
                }
1113
0
            }
1114
0
            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
0
            cp = cbuf;
1123
0
            cp += strlen(cp);
1124
0
            if (cp > buf && cp[-1] == LF) {
1125
0
                cp--;
1126
0
                if (cp > buf && cp[-1] == CR)
1127
0
                    cp--;
1128
0
                if (cp > buf && cp[-1] == '\\') {
1129
0
                    cp--;
1130
                    /*
1131
                     * line continuation requested -
1132
                     * then remove backslash and continue
1133
                     */
1134
0
                    cbufsize -= (cp-cbuf);
1135
0
                    cbuf = cp;
1136
0
                    continue;
1137
0
                }
1138
0
            }
1139
0
            else if (cp - buf >= bufsize - 1) {
1140
0
                return APR_ENOSPC;
1141
0
            }
1142
0
            break;
1143
0
        }
1144
0
    } else {
1145
        /* No "get string" function defined; read character by character */
1146
0
        apr_size_t i = offset;
1147
1148
0
        if (bufsize < 2) {
1149
            /* too small, assume caller is crazy */
1150
0
            return APR_EINVAL;
1151
0
        }
1152
0
        buf[offset] = '\0';
1153
1154
0
        while (1) {
1155
0
            char c;
1156
0
            rc = cfp->getch(&c, cfp->param);
1157
0
            if (rc == APR_EOF) {
1158
0
                if (i > offset)
1159
0
                    break;
1160
0
                else
1161
0
                    return APR_EOF;
1162
0
            }
1163
0
            if (rc != APR_SUCCESS)
1164
0
                return rc;
1165
0
            if (c == LF) {
1166
0
                ++cfp->line_number;
1167
                /* check for line continuation */
1168
0
                if (i > 0 && buf[i-1] == '\\') {
1169
0
                    i--;
1170
0
                    continue;
1171
0
                }
1172
0
                else {
1173
0
                    break;
1174
0
                }
1175
0
            }
1176
0
            buf[i] = c;
1177
0
            ++i;
1178
0
            if (i >= bufsize - 1) {
1179
0
                return APR_ENOSPC;
1180
0
            }
1181
0
        }
1182
0
        buf[i] = '\0';
1183
0
    }
1184
0
    return APR_SUCCESS;
1185
0
}
1186
1187
static int cfg_trim_line(char *buf)
1188
0
{
1189
0
    char *start, *end;
1190
    /*
1191
     * Leading and trailing white space is eliminated completely
1192
     */
1193
0
    start = buf;
1194
0
    while (apr_isspace(*start))
1195
0
        ++start;
1196
    /* blast trailing whitespace */
1197
0
    end = &start[strlen(start)];
1198
0
    while (--end >= start && apr_isspace(*end))
1199
0
        *end = '\0';
1200
    /* Zap leading whitespace by shifting */
1201
0
    if (start != buf)
1202
0
        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
0
    return end - start + 1;
1207
0
}
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
0
{
1214
0
    apr_status_t rc = ap_cfg_getline_core(buf, bufsize, 0, cfp);
1215
0
    if (rc == APR_SUCCESS)
1216
0
        cfg_trim_line(buf);
1217
0
    return rc;
1218
0
}
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
0
{
1269
0
    const unsigned char *ptr = (const unsigned char *)*field;
1270
0
    const unsigned char *token;
1271
0
    int in_qpair, in_qstr, in_com;
1272
1273
    /* Find first non-comma, non-whitespace byte */
1274
1275
0
    while (*ptr == ',' || apr_isspace(*ptr))
1276
0
        ++ptr;
1277
1278
0
    token = ptr;
1279
1280
    /* Find the end of this item, skipping over dead bits */
1281
1282
0
    for (in_qpair = in_qstr = in_com = 0;
1283
0
         *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1284
0
         ++ptr) {
1285
1286
0
        if (in_qpair) {
1287
0
            in_qpair = 0;
1288
0
        }
1289
0
        else {
1290
0
            switch (*ptr) {
1291
0
                case '\\': in_qpair = 1;      /* quoted-pair         */
1292
0
                           break;
1293
0
                case '"' : if (!in_com)       /* quoted string delim */
1294
0
                               in_qstr = !in_qstr;
1295
0
                           break;
1296
0
                case '(' : if (!in_qstr)      /* comment (may nest)  */
1297
0
                               ++in_com;
1298
0
                           break;
1299
0
                case ')' : if (in_com)        /* end comment         */
1300
0
                               --in_com;
1301
0
                           break;
1302
0
                default  : break;
1303
0
            }
1304
0
        }
1305
0
    }
1306
1307
0
    if ((*len = (ptr - token)) == 0) {
1308
0
        *field = (const char *)ptr;
1309
0
        return NULL;
1310
0
    }
1311
1312
    /* Advance field pointer to the next non-comma, non-white byte */
1313
1314
0
    while (*ptr == ',' || apr_isspace(*ptr))
1315
0
        ++ptr;
1316
1317
0
    *field = (const char *)ptr;
1318
0
    return (const char *)token;
1319
0
}
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
0
{
1329
0
    const char *tok_start;
1330
0
    const unsigned char *ptr;
1331
0
    unsigned char *pos;
1332
0
    char *token;
1333
0
    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
0
    if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
1339
0
        return NULL;
1340
0
    }
1341
0
    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
0
    for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
1349
0
         *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1350
0
         ++ptr) {
1351
1352
0
        if (in_qpair) {
1353
0
            in_qpair = 0;
1354
0
            *pos++ = *ptr;
1355
0
        }
1356
0
        else {
1357
0
            switch (*ptr) {
1358
0
                case '\\': in_qpair = 1;
1359
0
                           if (addspace == 1)
1360
0
                               *pos++ = ' ';
1361
0
                           *pos++ = *ptr;
1362
0
                           addspace = 0;
1363
0
                           break;
1364
0
                case '"' : if (!in_com)
1365
0
                               in_qstr = !in_qstr;
1366
0
                           if (addspace == 1)
1367
0
                               *pos++ = ' ';
1368
0
                           *pos++ = *ptr;
1369
0
                           addspace = 0;
1370
0
                           break;
1371
0
                case '(' : if (!in_qstr)
1372
0
                               ++in_com;
1373
0
                           if (addspace == 1)
1374
0
                               *pos++ = ' ';
1375
0
                           *pos++ = *ptr;
1376
0
                           addspace = 0;
1377
0
                           break;
1378
0
                case ')' : if (in_com)
1379
0
                               --in_com;
1380
0
                           *pos++ = *ptr;
1381
0
                           addspace = 0;
1382
0
                           break;
1383
0
                case ' ' :
1384
0
                case '\t': if (addspace)
1385
0
                               break;
1386
0
                           if (in_com || in_qstr)
1387
0
                               *pos++ = *ptr;
1388
0
                           else
1389
0
                               addspace = 1;
1390
0
                           break;
1391
0
                case '=' :
1392
0
                case '/' :
1393
0
                case ';' : if (!(in_com || in_qstr))
1394
0
                               addspace = -1;
1395
0
                           *pos++ = *ptr;
1396
0
                           break;
1397
0
                default  : if (addspace == 1)
1398
0
                               *pos++ = ' ';
1399
0
                           *pos++ = (in_com || in_qstr) ? *ptr
1400
0
                                                        : apr_tolower(*ptr);
1401
0
                           addspace = 0;
1402
0
                           break;
1403
0
            }
1404
0
        }
1405
0
    }
1406
0
    *pos = '\0';
1407
1408
0
    return token;
1409
0
}
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
0
{
1425
0
    const unsigned char *pos;
1426
0
    const unsigned char *ptr = (const unsigned char *)line;
1427
0
    int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
1428
1429
0
    if (!line || !tok) {
1430
0
        return 0;
1431
0
    }
1432
0
    if (type == AP_ETAG_STRONG && *tok != '\"') {
1433
0
        return 0;
1434
0
    }
1435
0
    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
0
    do {  /* loop for each item in line's list */
1445
1446
        /* Find first non-comma, non-whitespace byte */
1447
0
        while (*ptr == ',' || apr_isspace(*ptr)) {
1448
0
            ++ptr;
1449
0
        }
1450
1451
        /* Account for strong or weak Etags, depending on our search */
1452
0
        if (type == AP_ETAG_STRONG && *ptr != '\"') {
1453
0
            break;
1454
0
        }
1455
0
        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
0
        if (*ptr)
1465
0
            good = 1;  /* until proven otherwise for this item */
1466
0
        else
1467
0
            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
0
        for (pos = (const unsigned char *)tok;
1474
0
             *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1475
0
             ++ptr) {
1476
1477
0
            if (in_qpair) {
1478
0
                in_qpair = 0;
1479
0
                if (good)
1480
0
                    good = (*pos++ == *ptr);
1481
0
            }
1482
0
            else {
1483
0
                switch (*ptr) {
1484
0
                    case '\\': in_qpair = 1;
1485
0
                               if (addspace == 1)
1486
0
                                   good = good && (*pos++ == ' ');
1487
0
                               good = good && (*pos++ == *ptr);
1488
0
                               addspace = 0;
1489
0
                               break;
1490
0
                    case '"' : if (!in_com)
1491
0
                                   in_qstr = !in_qstr;
1492
0
                               if (addspace == 1)
1493
0
                                   good = good && (*pos++ == ' ');
1494
0
                               good = good && (*pos++ == *ptr);
1495
0
                               addspace = 0;
1496
0
                               break;
1497
0
                    case '(' : if (!in_qstr)
1498
0
                                   ++in_com;
1499
0
                               if (addspace == 1)
1500
0
                                   good = good && (*pos++ == ' ');
1501
0
                               good = good && (*pos++ == *ptr);
1502
0
                               addspace = 0;
1503
0
                               break;
1504
0
                    case ')' : if (in_com)
1505
0
                                   --in_com;
1506
0
                               good = good && (*pos++ == *ptr);
1507
0
                               addspace = 0;
1508
0
                               break;
1509
0
                    case ' ' :
1510
0
                    case '\t': if (addspace || !good)
1511
0
                                   break;
1512
0
                               if (in_com || in_qstr)
1513
0
                                   good = (*pos++ == *ptr);
1514
0
                               else
1515
0
                                   addspace = 1;
1516
0
                               break;
1517
0
                    case '=' :
1518
0
                    case '/' :
1519
0
                    case ';' : if (!(in_com || in_qstr))
1520
0
                                   addspace = -1;
1521
0
                               good = good && (*pos++ == *ptr);
1522
0
                               break;
1523
0
                    default  : if (!good)
1524
0
                                   break;
1525
0
                               if (addspace == 1)
1526
0
                                   good = (*pos++ == ' ');
1527
0
                               if (in_com || in_qstr)
1528
0
                                   good = good && (*pos++ == *ptr);
1529
0
                               else
1530
0
                                   good = good
1531
0
                                       && (apr_tolower(*pos++) == apr_tolower(*ptr));
1532
0
                               addspace = 0;
1533
0
                               break;
1534
0
                }
1535
0
            }
1536
0
        }
1537
0
        if (good && *pos)
1538
0
            good = 0;          /* not good if only a prefix was matched */
1539
1540
0
    } while (*ptr && !good);
1541
1542
0
    return good;
1543
0
}
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
0
{
1553
0
    return find_list_item(p, line, tok, AP_ETAG_NONE);
1554
0
}
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
0
{
1580
0
    int in_leading_space = 1;
1581
0
    int in_trailing_space = 0;
1582
0
    int string_end = 0;
1583
0
    const char *tok_begin;
1584
0
    const char *cur;
1585
1586
0
    if (!str_in) {
1587
0
        return NULL;
1588
0
    }
1589
1590
0
    tok_begin = cur = str_in;
1591
1592
0
    while (!string_end) {
1593
0
        const unsigned char c = (unsigned char)*cur;
1594
1595
0
        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
0
            in_leading_space = 0;
1600
0
            if (in_trailing_space) {
1601
0
                return "Encountered illegal whitespace in token";
1602
0
            }
1603
0
        }
1604
0
        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
0
            if (in_leading_space) {
1609
                /* We're still in leading whitespace */
1610
0
                ++tok_begin;
1611
0
            }
1612
0
            else {
1613
                /* We must be in trailing whitespace */
1614
0
                ++in_trailing_space;
1615
0
            }
1616
0
        }
1617
0
        else if (c == ',' || c == '\0') {
1618
0
            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
0
                if (*tokens == NULL) {
1622
0
                    *tokens = apr_array_make(p, 4, sizeof(char *));
1623
0
                }
1624
0
                APR_ARRAY_PUSH(*tokens, char *) =
1625
0
                    apr_pstrmemdup((*tokens)->pool, tok_begin,
1626
0
                                   (cur - tok_begin) - in_trailing_space);
1627
0
            }
1628
            /* We're allowed to have null elements, just don't add them to the
1629
             * array */
1630
1631
0
            tok_begin = cur + 1;
1632
0
            in_leading_space = 1;
1633
0
            in_trailing_space = 0;
1634
0
            string_end = (c == '\0');
1635
0
        }
1636
0
        else {
1637
            /* Encountered illegal separator char */
1638
0
            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
0
            else {
1652
0
                return apr_psprintf(p, "Encountered illegal separator "
1653
0
                                    "'\\x%.2x'", (unsigned int)c);
1654
0
            }
1655
0
        }
1656
1657
0
        ++cur;
1658
0
    }
1659
1660
0
    return NULL;
1661
0
}
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
0
{
1703
0
    const char *ptr = *accept_line;
1704
0
    const char *tok_start;
1705
0
    char *token;
1706
1707
    /* Find first non-white byte */
1708
1709
0
    while (apr_isspace(*ptr))
1710
0
        ++ptr;
1711
1712
0
    tok_start = ptr;
1713
1714
    /* find token end, skipping over quoted strings.
1715
     * (comments are already gone).
1716
     */
1717
1718
0
    while (*ptr && (accept_white || !apr_isspace(*ptr))
1719
0
           && *ptr != ';' && *ptr != ',') {
1720
0
        if (*ptr++ == '"')
1721
0
            while (*ptr)
1722
0
                if (*ptr++ == '"')
1723
0
                    break;
1724
0
    }
1725
1726
0
    token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
1727
1728
    /* Advance accept_line pointer to the next non-white byte */
1729
1730
0
    while (apr_isspace(*ptr))
1731
0
        ++ptr;
1732
1733
0
    *accept_line = ptr;
1734
0
    return token;
1735
0
}
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
0
{
1741
0
    const unsigned char *start_token;
1742
0
    const unsigned char *s;
1743
1744
0
    if (!line)
1745
0
        return 0;
1746
1747
0
    s = (const unsigned char *)line;
1748
0
    for (;;) {
1749
        /* find start of token, skip all stop characters */
1750
0
        while (*s && TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1751
0
            ++s;
1752
0
        }
1753
0
        if (!*s) {
1754
0
            return 0;
1755
0
        }
1756
0
        start_token = s;
1757
        /* find end of the token */
1758
0
        while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1759
0
            ++s;
1760
0
        }
1761
0
        if (!ap_cstr_casecmpn((const char *)start_token, (const char *)tok,
1762
0
                         s - start_token)) {
1763
0
            return 1;
1764
0
        }
1765
0
        if (!*s) {
1766
0
            return 0;
1767
0
        }
1768
0
    }
1769
0
}
1770
1771
static const char *find_last_token(apr_pool_t *p, const char *line,
1772
                            const char *tok)
1773
0
{
1774
0
    int llen, tlen, lidx;
1775
1776
0
    if (!line)
1777
0
        return NULL;
1778
1779
0
    llen = strlen(line);
1780
0
    tlen = strlen(tok);
1781
0
    lidx = llen - tlen;
1782
1783
0
    if (lidx < 0 ||
1784
0
        (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1785
0
        return NULL;
1786
1787
0
    if (ap_cstr_casecmpn(&line[lidx], tok, tlen) == 0) { 
1788
0
        return &line[lidx];
1789
0
    }
1790
0
   return NULL;
1791
0
}
1792
1793
AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
1794
                                   const char *tok)
1795
0
{
1796
0
    return find_last_token(p, line, tok) != NULL;
1797
0
}
1798
1799
AP_DECLARE(int) ap_is_chunked(apr_pool_t *p, const char *line)
1800
0
{
1801
0
    const char *s;
1802
1803
0
    if (!line) 
1804
0
        return 0;
1805
0
    if (!ap_cstr_casecmp(line, "chunked")) { 
1806
0
        return 1;
1807
0
    }
1808
1809
0
    s = find_last_token(p, line, "chunked");
1810
1811
0
    if (!s) return 0;
1812
 
1813
    /* eat spaces right-to-left to see what precedes "chunked" */
1814
0
    while (--s > line) { 
1815
0
        if (*s != ' ') break;
1816
0
    }
1817
1818
    /* found delim, or leading ws (input wasn't parsed by httpd as a header) */
1819
0
    if (*s == ',' || *s == ' ') { 
1820
0
        return 1;
1821
0
    }
1822
0
    return 0;
1823
0
}
1824
1825
AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1826
0
{
1827
0
    char *cmd;
1828
0
    unsigned char *d;
1829
0
    const unsigned char *s;
1830
1831
0
    cmd = apr_palloc(p, 2 * strlen(str) + 1);        /* Be safe */
1832
0
    d = (unsigned char *)cmd;
1833
0
    s = (const unsigned char *)str;
1834
0
    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
0
        if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1849
0
            *d++ = '\\';
1850
0
        }
1851
0
        *d++ = *s;
1852
0
    }
1853
0
    *d = '\0';
1854
1855
0
    return cmd;
1856
0
}
1857
1858
static char x2c(const char *what)
1859
0
{
1860
0
    char digit;
1861
1862
0
#if !APR_CHARSET_EBCDIC
1863
0
    digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
1864
0
             : (what[0] - '0'));
1865
0
    digit *= 16;
1866
0
    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
1867
0
              : (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
0
    return (digit);
1879
0
}
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
0
{
1893
0
    const int keep_slashes = (flags & AP_UNESCAPE_URL_KEEP_SLASHES) != 0,
1894
0
              forbid_slashes = (flags & AP_UNESCAPE_URL_FORBID_SLASHES) != 0,
1895
0
              keep_unreserved = (flags & AP_UNESCAPE_URL_KEEP_UNRESERVED) != 0;
1896
0
    int badesc, badpath;
1897
0
    char *x, *y;
1898
1899
0
    badesc = 0;
1900
0
    badpath = 0;
1901
1902
0
    if (url == NULL) {
1903
0
        return OK;
1904
0
    }
1905
    /* Initial scan for first '%'. Don't bother writing values before
1906
     * seeing a '%' */
1907
0
    y = strchr(url, '%');
1908
0
    if (y == NULL) {
1909
0
        return OK;
1910
0
    }
1911
0
    for (x = y; *y; ++x, ++y) {
1912
0
        if (*y != '%') {
1913
0
            *x = *y;
1914
0
        }
1915
0
        else {
1916
0
            if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1917
0
                badesc = 1;
1918
0
                *x = '%';
1919
0
            }
1920
0
            else {
1921
0
                char decoded;
1922
0
                decoded = x2c(y + 1);
1923
0
                if ((decoded == '\0')
1924
0
                    || (forbid_slashes && IS_SLASH(decoded))
1925
0
                    || (forbid && ap_strchr_c(forbid, decoded))) {
1926
0
                    badpath = 1;
1927
0
                    *x = decoded;
1928
0
                    y += 2;
1929
0
                }
1930
0
                else if ((keep_unreserved && TEST_CHAR(decoded,
1931
0
                                                       T_URI_UNRESERVED))
1932
0
                         || (keep_slashes && IS_SLASH(decoded))
1933
0
                         || (reserved && ap_strchr_c(reserved, decoded))) {
1934
0
                    *x++ = *y++;
1935
0
                    *x++ = *y++;
1936
0
                    *x = *y;
1937
0
                }
1938
0
                else {
1939
0
                    *x = decoded;
1940
0
                    y += 2;
1941
0
                }
1942
0
            }
1943
0
        }
1944
0
    }
1945
0
    *x = '\0';
1946
0
    if (badesc) {
1947
0
        return HTTP_BAD_REQUEST;
1948
0
    }
1949
0
    else if (badpath) {
1950
0
        return HTTP_NOT_FOUND;
1951
0
    }
1952
0
    else {
1953
0
        return OK;
1954
0
    }
1955
0
}
1956
AP_DECLARE(int) ap_unescape_url(char *url)
1957
0
{
1958
    /* Traditional */
1959
0
    return unescape_url(url, SLASHES, NULL, 0);
1960
0
}
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
0
{
1996
0
    char *slider;
1997
1998
    /* replace plus with a space */
1999
0
    if (query) {
2000
0
        for (slider = query; *slider; slider++) {
2001
0
            if (*slider == '+') {
2002
0
                *slider = ' ';
2003
0
            }
2004
0
        }
2005
0
    }
2006
2007
    /* unescape everything else */
2008
0
    return unescape_url(query, NULL, NULL, 0);
2009
0
}
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
0
{
2042
#if APR_CHARSET_EBCDIC
2043
    what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
2044
#endif /*APR_CHARSET_EBCDIC*/
2045
0
    *where++ = prefix;
2046
0
    *where++ = c2x_table[what >> 4];
2047
0
    *where++ = c2x_table[what & 0xf];
2048
0
    return where;
2049
0
}
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
0
{
2068
0
    const unsigned char *s = (const unsigned char *)segment;
2069
0
    unsigned char *d = (unsigned char *)copy;
2070
0
    unsigned c;
2071
2072
0
    while ((c = *s)) {
2073
0
        if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
2074
0
            d = c2x(c, '%', d);
2075
0
        }
2076
0
        else {
2077
0
            *d++ = c;
2078
0
        }
2079
0
        ++s;
2080
0
    }
2081
0
    *d = '\0';
2082
0
    return copy;
2083
0
}
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
0
{
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
0
    char *copy = apr_palloc(p, 3 * strlen(path) + 3 + 1);
2097
0
    const unsigned char *s = (const unsigned char *)path;
2098
0
    unsigned char *d = (unsigned char *)copy;
2099
0
    unsigned c;
2100
2101
0
    if (!partial) {
2102
0
        const char *colon = ap_strchr_c(path, ':');
2103
0
        const char *slash = ap_strchr_c(path, '/');
2104
2105
0
        if (colon && (!slash || colon < slash)) {
2106
0
            *d++ = '.';
2107
0
            *d++ = '/';
2108
0
        }
2109
0
    }
2110
0
    while ((c = *s)) {
2111
0
        if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
2112
0
            d = c2x(c, '%', d);
2113
0
        }
2114
0
        else {
2115
0
            *d++ = c;
2116
0
        }
2117
0
        ++s;
2118
0
    }
2119
0
    *d = '\0';
2120
0
    return copy;
2121
0
}
2122
2123
AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer)
2124
0
{
2125
0
    const unsigned char *s = (const unsigned char *)buffer;
2126
0
    unsigned char *d = (unsigned char *)copy;
2127
0
    unsigned c;
2128
2129
0
    while ((c = *s)) {
2130
0
        if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
2131
0
            d = c2x(c, '%', d);
2132
0
        }
2133
0
        else if (c == ' ') {
2134
0
            *d++ = '+';
2135
0
        }
2136
0
        else {
2137
0
            *d++ = c;
2138
0
        }
2139
0
        ++s;
2140
0
    }
2141
0
    *d = '\0';
2142
0
    return copy;
2143
0
}
2144
2145
AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
2146
0
{
2147
0
    return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * strlen(buffer) + 1), buffer);
2148
0
}
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
0
{
2154
0
    apr_size_t i, j;
2155
0
    char *x;
2156
2157
    /* first, count the number of extra characters */
2158
0
    for (i = 0, j = 0; s[i] != '\0'; i++) {
2159
0
        if (i + j > APR_SIZE_MAX - 6) {
2160
0
            abort();
2161
0
        }
2162
0
        if (s[i] == '<' || s[i] == '>')
2163
0
            j += 3;
2164
0
        else if (s[i] == '&')
2165
0
            j += 4;
2166
0
        else if (s[i] == '"')
2167
0
            j += 5;
2168
0
        else if (toasc && !apr_isascii(s[i]))
2169
0
            j += 5;
2170
0
    }
2171
2172
0
    if (j == 0)
2173
0
        return apr_pstrmemdup(p, s, i);
2174
2175
0
    x = apr_palloc(p, i + j + 1);
2176
0
    for (i = 0, j = 0; s[i] != '\0'; i++, j++)
2177
0
        if (s[i] == '<') {
2178
0
            memcpy(&x[j], "&lt;", 4);
2179
0
            j += 3;
2180
0
        }
2181
0
        else if (s[i] == '>') {
2182
0
            memcpy(&x[j], "&gt;", 4);
2183
0
            j += 3;
2184
0
        }
2185
0
        else if (s[i] == '&') {
2186
0
            memcpy(&x[j], "&amp;", 5);
2187
0
            j += 4;
2188
0
        }
2189
0
        else if (s[i] == '"') {
2190
0
            memcpy(&x[j], "&quot;", 6);
2191
0
            j += 5;
2192
0
        }
2193
0
        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
0
        else
2199
0
            x[j] = s[i];
2200
2201
0
    x[j] = '\0';
2202
0
    return x;
2203
0
}
2204
AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
2205
0
{
2206
0
    char *ret;
2207
0
    unsigned char *d;
2208
0
    const unsigned char *s;
2209
0
    apr_size_t length, escapes = 0;
2210
2211
0
    if (!str) {
2212
0
        return NULL;
2213
0
    }
2214
2215
    /* Compute how many characters need to be escaped */
2216
0
    s = (const unsigned char *)str;
2217
0
    for (; *s; ++s) {
2218
0
        if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2219
0
            escapes++;
2220
0
        }
2221
0
    }
2222
    
2223
    /* Compute the length of the input string, including NULL */
2224
0
    length = s - (const unsigned char *)str + 1;
2225
    
2226
    /* Fast path: nothing to escape */
2227
0
    if (escapes == 0) {
2228
0
        return apr_pmemdup(p, str, length);
2229
0
    }
2230
    
2231
    /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
2232
0
    ret = apr_palloc(p, length + 3 * escapes);
2233
0
    d = (unsigned char *)ret;
2234
0
    s = (const unsigned char *)str;
2235
0
    for (; *s; ++s) {
2236
0
        if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2237
0
            *d++ = '\\';
2238
0
            switch(*s) {
2239
0
            case '\b':
2240
0
                *d++ = 'b';
2241
0
                break;
2242
0
            case '\n':
2243
0
                *d++ = 'n';
2244
0
                break;
2245
0
            case '\r':
2246
0
                *d++ = 'r';
2247
0
                break;
2248
0
            case '\t':
2249
0
                *d++ = 't';
2250
0
                break;
2251
0
            case '\v':
2252
0
                *d++ = 'v';
2253
0
                break;
2254
0
            case '\\':
2255
0
            case '"':
2256
0
                *d++ = *s;
2257
0
                break;
2258
0
            default:
2259
0
                c2x(*s, 'x', d);
2260
0
                d += 3;
2261
0
            }
2262
0
        }
2263
0
        else {
2264
0
            *d++ = *s;
2265
0
        }
2266
0
    }
2267
0
    *d = '\0';
2268
2269
0
    return ret;
2270
0
}
2271
2272
AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
2273
                                               apr_size_t buflen)
2274
0
{
2275
0
    unsigned char *d, *ep;
2276
0
    const unsigned char *s;
2277
2278
0
    if (!source || !buflen) { /* be safe */
2279
0
        return 0;
2280
0
    }
2281
2282
0
    d = (unsigned char *)dest;
2283
0
    s = (const unsigned char *)source;
2284
0
    ep = d + buflen - 1;
2285
2286
0
    for (; d < ep && *s; ++s) {
2287
2288
0
        if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2289
0
            *d++ = '\\';
2290
0
            if (d >= ep) {
2291
0
                --d;
2292
0
                break;
2293
0
            }
2294
2295
0
            switch(*s) {
2296
0
            case '\b':
2297
0
                *d++ = 'b';
2298
0
                break;
2299
0
            case '\n':
2300
0
                *d++ = 'n';
2301
0
                break;
2302
0
            case '\r':
2303
0
                *d++ = 'r';
2304
0
                break;
2305
0
            case '\t':
2306
0
                *d++ = 't';
2307
0
                break;
2308
0
            case '\v':
2309
0
                *d++ = 'v';
2310
0
                break;
2311
0
            case '\\':
2312
0
                *d++ = *s;
2313
0
                break;
2314
0
            case '"': /* no need for this in error log */
2315
0
                d[-1] = *s;
2316
0
                break;
2317
0
            default:
2318
0
                if (d >= ep - 2) {
2319
0
                    ep = --d; /* break the for loop as well */
2320
0
                    break;
2321
0
                }
2322
0
                c2x(*s, 'x', d);
2323
0
                d += 3;
2324
0
            }
2325
0
        }
2326
0
        else {
2327
0
            *d++ = *s;
2328
0
        }
2329
0
    }
2330
0
    *d = '\0';
2331
2332
0
    return (d - (unsigned char *)dest);
2333
0
}
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
0
{
2433
0
    while (*str) {
2434
0
        *str = apr_tolower(*str);
2435
0
        ++str;
2436
0
    }
2437
0
}
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
0
{
2500
0
    char *decoded;
2501
2502
0
    decoded = (char *) apr_palloc(p, apr_base64_decode_len(bufcoded));
2503
0
    apr_base64_decode(decoded, bufcoded);
2504
2505
0
    return decoded;
2506
0
}
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
0
{
2514
0
    apr_size_t end_index;
2515
0
    int last_group_len;
2516
0
    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
0
    end_index = strspn(encoded, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2523
0
                                "abcdefghijklmnopqrstuvwxyz"
2524
0
                                "0123456789+/");
2525
2526
0
    last_group_len = end_index % 4;
2527
0
    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
0
    if (last_group_len == 1) {
2536
        /* This isn't ever valid. */
2537
0
        return APR_EINVAL;
2538
0
    }
2539
0
    else if (last_group_len == 2) {
2540
        /* ...xY== */
2541
0
        if (*end != '=' || end[1] != '=') {
2542
0
            return APR_EINVAL;
2543
0
        }
2544
0
        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
0
            return APR_EINVAL;
2548
0
        }
2549
2550
0
        end += 2;
2551
0
    }
2552
0
    else if (last_group_len == 3) {
2553
        /* ...xyZ= */
2554
0
        if (*end != '=') {
2555
0
            return APR_EINVAL;
2556
0
        }
2557
0
        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
0
            return APR_EINVAL;
2561
0
        }
2562
2563
0
        end++;
2564
0
    }
2565
2566
    /* At this point, if the encoded buffer is correct, we should be at the end
2567
     * of the string. */
2568
0
    if (*end) {
2569
0
        return APR_EINVAL;
2570
0
    }
2571
2572
0
    *decoded = apr_palloc(p, apr_base64_decode_len(encoded));
2573
0
    *len = apr_base64_decode(*decoded, encoded);
2574
2575
0
    return APR_SUCCESS;
2576
0
}
2577
2578
AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
2579
0
{
2580
0
    char *encoded;
2581
0
    int l = strlen(string);
2582
2583
0
    encoded = (char *) apr_palloc(p, apr_base64_encode_len(l));
2584
0
    apr_base64_encode(encoded, string, l);
2585
2586
0
    return encoded;
2587
0
}
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
0
{
2598
0
    char *semi;
2599
2600
0
    semi = strchr(str, ';');
2601
0
    if (semi) {
2602
0
        *semi = '\0';
2603
0
    }
2604
2605
0
    ap_str_tolower(str);
2606
2607
0
    if (semi) {
2608
0
        *semi = ';';
2609
0
    }
2610
0
}
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
0
{
2617
0
    apr_size_t size, extra = 0;
2618
0
    const char *inchr = instring;
2619
0
    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
0
    while (*inchr != '\0') {
2626
0
        if (*inchr == '"') {
2627
0
            extra++;
2628
0
        }
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
0
        else if ((*inchr == '\\') && (inchr[1] != '\0')) {
2634
0
            inchr++;
2635
0
        }
2636
0
        inchr++;
2637
0
    }
2638
2639
0
    if (!extra) {
2640
0
        return apr_pstrdup(p, instring);
2641
0
    }
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
0
    ap_assert(inchr - instring > 0);
2657
0
    size = ((apr_size_t)(inchr - instring)) + 1;
2658
0
    ap_assert(size + extra > size);
2659
2660
0
    outstring = apr_palloc(p, size + extra);
2661
0
    inchr = instring;
2662
0
    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
0
    while (*inchr != '\0') {
2668
0
        if (*inchr == '"') {
2669
0
            *outchr++ = '\\';
2670
0
        }
2671
0
        else if ((*inchr == '\\') && (inchr[1] != '\0')) {
2672
0
            *outchr++ = *inchr++;
2673
0
        }
2674
0
        *outchr++ = *inchr++;
2675
0
    }
2676
0
    *outchr = '\0';
2677
0
    return outstring;
2678
0
}
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
0
#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
0
{
2718
0
    char *endp;
2719
0
    const char *time_str;
2720
0
    apr_int64_t tout;
2721
0
    apr_uint64_t check;
2722
2723
0
    tout = apr_strtoi64(timeout_parameter, &endp, 10);
2724
0
    if (errno) {
2725
0
        return errno;
2726
0
    }
2727
0
    if (!endp || !*endp) {
2728
0
        time_str = default_time_unit;
2729
0
    }
2730
0
    else {
2731
0
        time_str = endp;
2732
0
    }
2733
2734
0
    if (tout < 0) { 
2735
0
        return APR_EGENERAL;
2736
0
    }
2737
2738
0
    switch (*time_str) {
2739
        /* Time is in seconds */
2740
0
    case 's':
2741
0
    case 'S':
2742
0
        CHECK_OVERFLOW(tout, apr_time_sec(APR_INT64_MAX));
2743
0
        check = apr_time_from_sec(tout);
2744
0
        break;
2745
        /* Time is in hours */
2746
0
    case 'h':
2747
0
    case 'H':
2748
0
        CHECK_OVERFLOW(tout, apr_time_sec(APR_INT64_MAX / 3600));
2749
0
        check = apr_time_from_sec(tout * 3600);
2750
0
        break;
2751
0
    case 'm':
2752
0
    case 'M':
2753
0
        switch (*(++time_str)) {
2754
        /* Time is in milliseconds */
2755
0
        case 's':
2756
0
        case 'S':
2757
0
            CHECK_OVERFLOW(tout, apr_time_as_msec(APR_INT64_MAX));
2758
0
            check = apr_time_from_msec(tout);
2759
0
            break;
2760
        /* Time is in minutes */
2761
0
        case 'i':
2762
0
        case 'I':
2763
0
            CHECK_OVERFLOW(tout, apr_time_sec(APR_INT64_MAX / 60));
2764
0
            check = apr_time_from_sec(tout * 60);
2765
0
            break;
2766
0
        default:
2767
0
            return APR_EGENERAL;
2768
0
        }
2769
0
        break;
2770
0
    default:
2771
0
        return APR_EGENERAL;
2772
0
    }
2773
2774
0
    *timeout = (apr_interval_time_t)check;
2775
0
    return APR_SUCCESS;
2776
0
}
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
0
AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
2829
2830
0
    for ( ; *src; src++, dest++)
2831
0
    {
2832
0
        if (!apr_isprint(*src))
2833
0
            *dest = 'x';
2834
0
        else if (!apr_isalnum(*src))
2835
0
            *dest = '_';
2836
0
        else
2837
0
            *dest = (char)*src;
2838
0
    }
2839
0
    *dest = '\0';
2840
0
    return APR_SUCCESS;
2841
2842
0
}
2843
2844
AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
2845
                                        const char **dest)
2846
0
{
2847
0
    char *new = apr_palloc(p, strlen(src)+1);
2848
0
    if (!new)
2849
0
        return APR_ENOMEM;
2850
0
    *dest = new;
2851
0
    return ap_str2_alnum(src, new);
2852
0
}
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
183
{
3708
183
    const unsigned char *u1 = (const unsigned char *)s1;
3709
183
    const unsigned char *u2 = (const unsigned char *)s2;
3710
286
    for (;;) {
3711
286
        const int c2 = ucharmap[*u2++];
3712
286
        const int cmp = (int)ucharmap[*u1++] - c2;
3713
        /* Not necessary to test for !c1, this is caught by cmp */
3714
286
        if (cmp || !c2)
3715
183
            return cmp;
3716
286
    }
3717
183
}
3718
3719
AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
3720
0
{
3721
0
    const unsigned char *u1 = (const unsigned char *)s1;
3722
0
    const unsigned char *u2 = (const unsigned char *)s2;
3723
0
    while (n--) {
3724
0
        const int c2 = ucharmap[*u2++];
3725
0
        const int cmp = (int)ucharmap[*u1++] - c2;
3726
        /* Not necessary to test for !c1, this is caught by cmp */
3727
0
        if (cmp || !c2)
3728
0
            return cmp;
3729
0
    }
3730
0
    return 0;
3731
0
}
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
}