]> granicus.if.org Git - apache/blob - server/util.c
This is always displayed to the console. There is no reason to print the
[apache] / server / util.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  *    if any, must include the following acknowledgment:
21  *       "This product includes software developed by the
22  *        Apache Software Foundation (http://www.apache.org/)."
23  *    Alternately, this acknowledgment may appear in the software itself,
24  *    if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  *    not be used to endorse or promote products derived from this
28  *    software without prior written permission. For written
29  *    permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  *    nor may "Apache" appear in their name, without prior written
33  *    permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation.  For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  *
54  * Portions of this software are based upon public domain software
55  * originally written at the National Center for Supercomputing Applications,
56  * University of Illinois, Urbana-Champaign.
57  */
58
59 /*
60  * util.c: string utility things
61  * 
62  * 3/21/93 Rob McCool
63  * 1995-96 Many changes by the Apache Software Foundation
64  * 
65  */
66
67 /* Debugging aid:
68  * #define DEBUG            to trace all cfg_open*()/cfg_closefile() calls
69  * #define DEBUG_CFG_LINES  to trace every line read from the config files
70  */
71
72 #define CORE_PRIVATE
73
74 #include "ap_config.h"
75 #include "ap_base64.h"
76 #include "apr_strings.h"
77 #include "httpd.h"
78 #include "http_main.h"
79 #include "http_log.h"
80 #include "http_protocol.h"
81 #include "http_config.h"
82 #include "util_ebcdic.h"
83
84 #ifdef HAVE_STDIO_H
85 #include <stdio.h>
86 #endif
87 #ifdef HAVE_UNISTD_H
88 #include <unistd.h>
89 #endif
90 #ifdef HAVE_NETINET_IN_H
91 #include <netinet/in.h>
92 #endif
93 #ifdef HAVE_SYS_SOCKET_H
94 #include <sys/socket.h>
95 #endif
96 #ifdef HAVE_NETDB_H
97 #include <netdb.h>
98 #endif
99 #ifdef HAVE_ARPA_INET_H
100 #include <arpa/inet.h>
101 #endif
102 #ifdef HAVE_PWD_H
103 #include <pwd.h>
104 #endif
105 #ifdef HAVE_GRP_H
106 #include <grp.h>
107 #endif
108 #ifdef HAVE_STRINGS_H
109 #include <strings.h>
110 #endif
111
112 /* A bunch of functions in util.c scan strings looking for certain characters.
113  * To make that more efficient we encode a lookup table.  The test_char_table
114  * is generated automatically by gen_test_char.c.
115  */
116 #include "test_char.h"
117
118 /* we assume the folks using this ensure 0 <= c < 256... which means
119  * you need a cast to (unsigned char) first, you can't just plug a
120  * char in here and get it to work, because if char is signed then it
121  * will first be sign extended.
122  */
123 #define TEST_CHAR(c, f) (test_char_table[(unsigned)(c)] & (f))
124
125 /*
126  * Examine a field value (such as a media-/content-type) string and return
127  * it sans any parameters; e.g., strip off any ';charset=foo' and the like.
128  */
129 AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype)
130 {
131     const char *semi;
132
133     if (intype == NULL) return NULL;
134
135     semi = ap_strchr_c(intype, ';');
136     if (semi == NULL) {
137         return apr_pstrdup(p, intype);
138     } 
139     else {
140         while ((semi > intype) && apr_isspace(semi[-1])) {
141             semi--;
142         }
143         return apr_pstrndup(p, intype, semi - intype);
144     }
145 }
146
147 AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt, int gmt)
148 {
149     apr_size_t retcode;
150     char ts[MAX_STRING_LEN];
151     char tf[MAX_STRING_LEN];
152     apr_exploded_time_t xt;
153
154     if (gmt) {
155         const char *f;
156         char *strp;
157
158         apr_explode_gmt(&xt, t);
159         /* Convert %Z to "GMT" and %z to "+0000";
160          * on hosts that do not have a time zone string in struct tm,
161          * strftime must assume its argument is local time.
162          */
163         for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f)
164             ; f++, strp++) {
165             if (*f != '%') continue;
166             switch (f[1]) {
167             case '%':
168                 *++strp = *++f;
169                 break;
170             case 'Z':
171                 *strp++ = 'G';
172                 *strp++ = 'M';
173                 *strp = 'T';
174                 f++;
175                 break;
176             case 'z': /* common extension */
177                 *strp++ = '+';
178                 *strp++ = '0';
179                 *strp++ = '0';
180                 *strp++ = '0';
181                 *strp = '0';
182                 f++;
183                 break;
184             }
185         }
186         *strp = '\0';
187         fmt = tf;
188     }
189     else {
190         apr_explode_localtime(&xt, t);
191     }
192
193     /* check return code? */
194     apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt);
195     ts[MAX_STRING_LEN - 1] = '\0';
196     return apr_pstrdup(p, ts);
197 }
198
199 /* Roy owes Rob beer. */
200 /* Rob owes Roy dinner. */
201
202 /* These legacy comments would make a lot more sense if Roy hadn't
203  * replaced the old later_than() routine with util_date.c.
204  *
205  * Well, okay, they still wouldn't make any sense.
206  */
207
208 /* Match = 0, NoMatch = 1, Abort = -1
209  * Based loosely on sections of wildmat.c by Rich Salz
210  * Hmmm... shouldn't this really go component by component?
211  */
212 AP_DECLARE(int) ap_strcmp_match(const char *str, const char *exp)
213 {
214     int x, y;
215
216     for (x = 0, y = 0; exp[y]; ++y, ++x) {
217         if ((!str[x]) && (exp[y] != '*'))
218             return -1;
219         if (exp[y] == '*') {
220             while (exp[++y] == '*');
221             if (!exp[y])
222                 return 0;
223             while (str[x]) {
224                 int ret;
225                 if ((ret = ap_strcmp_match(&str[x++], &exp[y])) != 1)
226                     return ret;
227             }
228             return -1;
229         }
230         else if ((exp[y] != '?') && (str[x] != exp[y]))
231             return 1;
232     }
233     return (str[x] != '\0');
234 }
235
236 AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *exp)
237 {
238     int x, y;
239
240     for (x = 0, y = 0; exp[y]; ++y, ++x) {
241         if ((!str[x]) && (exp[y] != '*'))
242             return -1;
243         if (exp[y] == '*') {
244             while (exp[++y] == '*');
245             if (!exp[y])
246                 return 0;
247             while (str[x]) {
248                 int ret;
249                 if ((ret = ap_strcasecmp_match(&str[x++], &exp[y])) != 1)
250                     return ret;
251             }
252             return -1;
253         }
254         else if ((exp[y] != '?') && (apr_tolower(str[x]) != apr_tolower(exp[y])))
255             return 1;
256     }
257     return (str[x] != '\0');
258 }
259
260 AP_DECLARE(int) ap_is_matchexp(const char *str)
261 {
262     register int x;
263
264     for (x = 0; str[x]; x++)
265         if ((str[x] == '*') || (str[x] == '?'))
266             return 1;
267     return 0;
268 }
269
270 /*
271  * Here's a pool-based interface to POSIX regex's regcomp().
272  * Note that we return regex_t instead of being passed one.
273  * The reason is that if you use an already-used regex_t structure,
274  * the memory that you've already allocated gets forgotten, and
275  * regfree() doesn't clear it. So we don't allow it.
276  */
277
278 static apr_status_t regex_cleanup(void *preg)
279 {
280     regfree((regex_t *) preg);
281     return APR_SUCCESS;
282 }
283
284 AP_DECLARE(regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
285                                    int cflags)
286 {
287     regex_t *preg = apr_palloc(p, sizeof(regex_t));
288
289     if (regcomp(preg, pattern, cflags)) {
290         return NULL;
291     }
292
293     apr_register_cleanup(p, (void *) preg, regex_cleanup, regex_cleanup);
294
295     return preg;
296 }
297
298 AP_DECLARE(void) ap_pregfree(apr_pool_t *p, regex_t * reg)
299 {
300     regfree(reg);
301     apr_kill_cleanup(p, (void *) reg, regex_cleanup);
302 }
303
304 /*
305  * Similar to standard strstr() but we ignore case in this version.
306  * Based on the strstr() implementation further below.
307  */
308 AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2)
309 {
310     char *p1, *p2;
311     if (*s2 == '\0') {
312         /* an empty s2 */
313         return((char *)s1);
314     }
315     while(1) {
316         for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
317         if (*s1 == '\0') return(NULL);
318         /* found first character of s2, see if the rest matches */
319         p1 = (char *)s1;
320         p2 = (char *)s2;
321         while (apr_tolower(*++p1) == apr_tolower(*++p2)) {
322             if (*p1 == '\0') {
323                 /* both strings ended together */
324                 return((char *)s1);
325             }
326         }
327         if (*p2 == '\0') {
328             /* second string ended, a match */
329             break;
330         }
331         /* didn't find a match here, try starting at next character in s1 */
332         s1++;
333     }
334     return((char *)s1);
335 }
336
337 /*
338  * Returns an offsetted pointer in bigstring immediately after
339  * prefix. Returns bigstring if bigstring doesn't start with
340  * prefix or if prefix is longer than bigstring while still matching.
341  * NOTE: pointer returned is relative to bigstring, so we
342  * can use standard pointer comparisons in the calling function
343  * (eg: test if ap_stripprefix(a,b) == a)
344  */
345 AP_DECLARE(const char *) ap_stripprefix(const char *bigstring,
346                                         const char *prefix)
347 {
348     const char *p1;
349
350     if (*prefix == '\0')
351         return bigstring;
352
353     p1 = bigstring;
354     while (*p1 && *prefix) {
355         if (*p1++ != *prefix++)
356             return bigstring;
357     }
358     if (*prefix == '\0')
359         return p1;
360
361     /* hit the end of bigstring! */
362     return bigstring;
363 }
364
365 /* 
366  * Apache stub function for the regex libraries regexec() to make sure the
367  * whole regex(3) API is available through the Apache (exported) namespace.
368  * This is especially important for the DSO situations of modules.
369  * DO NOT MAKE A MACRO OUT OF THIS FUNCTION!
370  */
371 AP_DECLARE(int) ap_regexec(regex_t *preg, const char *string,
372                            size_t nmatch, regmatch_t pmatch[], int eflags)
373 {
374     return regexec(preg, string, nmatch, pmatch, eflags);
375 }
376
377 AP_DECLARE(size_t) ap_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
378 {
379     return regerror(errcode, preg, errbuf, errbuf_size);
380 }
381
382
383 /* This function substitutes for $0-$9, filling in regular expression
384  * submatches. Pass it the same nmatch and pmatch arguments that you
385  * passed ap_regexec(). pmatch should not be greater than the maximum number
386  * of subexpressions - i.e. one more than the re_nsub member of regex_t.
387  *
388  * input should be the string with the $-expressions, source should be the
389  * string that was matched against.
390  *
391  * It returns the substituted string, or NULL on error.
392  *
393  * Parts of this code are based on Henry Spencer's regsub(), from his
394  * AT&T V8 regexp package.
395  */
396
397 AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input, const char *source,
398                            size_t nmatch, regmatch_t pmatch[])
399 {
400     const char *src = input;
401     char *dest, *dst;
402     char c;
403     size_t no;
404     int len;
405
406     if (!source)
407         return NULL;
408     if (!nmatch)
409         return apr_pstrdup(p, src);
410
411     /* First pass, find the size */
412
413     len = 0;
414
415     while ((c = *src++) != '\0') {
416         if (c == '&')
417             no = 0;
418         else if (c == '$' && apr_isdigit(*src))
419             no = *src++ - '0';
420         else
421             no = 10;
422
423         if (no > 9) {           /* Ordinary character. */
424             if (c == '\\' && (*src == '$' || *src == '&'))
425                 c = *src++;
426             len++;
427         }
428         else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
429             len += pmatch[no].rm_eo - pmatch[no].rm_so;
430         }
431
432     }
433
434     dest = dst = apr_pcalloc(p, len + 1);
435
436     /* Now actually fill in the string */
437
438     src = input;
439
440     while ((c = *src++) != '\0') {
441         if (c == '&')
442             no = 0;
443         else if (c == '$' && apr_isdigit(*src))
444             no = *src++ - '0';
445         else
446             no = 10;
447
448         if (no > 9) {           /* Ordinary character. */
449             if (c == '\\' && (*src == '$' || *src == '&'))
450                 c = *src++;
451             *dst++ = c;
452         }
453         else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
454             len = pmatch[no].rm_eo - pmatch[no].rm_so;
455             memcpy(dst, source + pmatch[no].rm_so, len);
456             dst += len;
457         }
458
459     }
460     *dst = '\0';
461
462     return dest;
463 }
464
465 /*
466  * Parse .. so we don't compromise security
467  */
468 AP_DECLARE(void) ap_getparents(char *name)
469 {
470     int l, w;
471
472     /* Four paseses, as per RFC 1808 */
473     /* a) remove ./ path segments */
474
475     for (l = 0, w = 0; name[l] != '\0';) {
476         if (name[l] == '.' && name[l + 1] == '/' && (l == 0 || name[l - 1] == '/'))
477             l += 2;
478         else
479             name[w++] = name[l++];
480     }
481
482     /* b) remove trailing . path, segment */
483     if (w == 1 && name[0] == '.')
484         w--;
485     else if (w > 1 && name[w - 1] == '.' && name[w - 2] == '/')
486         w--;
487     name[w] = '\0';
488
489     /* c) remove all xx/../ segments. (including leading ../ and /../) */
490     l = 0;
491
492     while (name[l] != '\0') {
493         if (name[l] == '.' && name[l + 1] == '.' && name[l + 2] == '/' &&
494             (l == 0 || name[l - 1] == '/')) {
495             register int m = l + 3, n;
496
497             l = l - 2;
498             if (l >= 0) {
499                 while (l >= 0 && name[l] != '/')
500                     l--;
501                 l++;
502             }
503             else
504                 l = 0;
505             n = l;
506             while ((name[n] = name[m]))
507                 (++n, ++m);
508         }
509         else
510             ++l;
511     }
512
513     /* d) remove trailing xx/.. segment. */
514     if (l == 2 && name[0] == '.' && name[1] == '.')
515         name[0] = '\0';
516     else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.' && name[l - 3] == '/') {
517         l = l - 4;
518         if (l >= 0) {
519             while (l >= 0 && name[l] != '/')
520                 l--;
521             l++;
522         }
523         else
524             l = 0;
525         name[l] = '\0';
526     }
527 }
528
529 AP_DECLARE(void) ap_no2slash(char *name)
530 {
531     char *d, *s;
532
533     s = d = name;
534
535 #ifdef HAVE_UNC_PATHS
536     /* Check for UNC names.  Leave leading two slashes. */
537     if (s[0] == '/' && s[1] == '/')
538         *d++ = *s++;
539 #endif
540
541     while (*s) {
542         if ((*d++ = *s) == '/') {
543             do {
544                 ++s;
545             } while (*s == '/');
546         }
547         else {
548             ++s;
549         }
550     }
551     *d = '\0';
552 }
553
554
555 /*
556  * copy at most n leading directories of s into d
557  * d should be at least as large as s plus 1 extra byte
558  * assumes n > 0
559  * the return value is the ever useful pointer to the trailing \0 of d
560  *
561  * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments, 
562  * so that if n == 0, "/" is returned in d with n == 1 
563  * and s == "e:/test.html", "e:/" is returned in d
564  * *** See also directory_walk in src/main/http_request.c
565
566  * examples:
567  *    /a/b, 0  ==> /  (true for all platforms)
568  *    /a/b, 1  ==> /
569  *    /a/b, 2  ==> /a/
570  *    /a/b, 3  ==> /a/b/
571  *    /a/b, 4  ==> /a/b/
572  *
573  *    c:/a/b 0 ==> /
574  *    c:/a/b 1 ==> c:/
575  *    c:/a/b 2 ==> c:/a/
576  *    c:/a/b 3 ==> c:/a/b
577  *    c:/a/b 4 ==> c:/a/b
578  */
579 AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
580 {
581     if (n < 1) {
582         *d = '/';
583         *++d = '\0';
584         return (d);
585     }
586
587     for (;;) {
588         if (*s == '\0' || (*s == '/' && (--n) == 0)) {
589             *d = '/';
590             break;
591         }
592         *d++ = *s++;
593     }
594     *++d = 0;
595     return (d);
596 }
597
598
599 /*
600  * return the parent directory name including trailing / of the file s
601  */
602 AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s)
603 {
604     const char *last_slash = ap_strrchr_c(s, '/');
605     char *d;
606     int l;
607
608     if (last_slash == NULL) {
609         /* XXX: well this is really broken if this happens */
610         return (apr_pstrdup(p, "/"));
611     }
612     l = (last_slash - s) + 1;
613     d = apr_palloc(p, l + 1);
614     memcpy(d, s, l);
615     d[l] = 0;
616     return (d);
617 }
618
619
620 AP_DECLARE(int) ap_count_dirs(const char *path)
621 {
622     register int x, n;
623
624     for (x = 0, n = 0; path[x]; x++)
625         if (path[x] == '/')
626             n++;
627     return n;
628 }
629
630
631 AP_DECLARE(void) ap_chdir_file(const char *file)
632 {
633     const char *x;
634     char buf[HUGE_STRING_LEN];
635
636     x = ap_strrchr_c(file, '/');
637     if (x == NULL) {
638         chdir(file);
639     }
640     else if (x - file < sizeof(buf) - 1) {
641         memcpy(buf, file, x - file);
642         buf[x - file] = '\0';
643         chdir(buf);
644     }
645     /* XXX: well, this is a silly function, no method of reporting an
646      * error... ah well. */
647 }
648
649 AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop)
650 {
651     return ap_getword(atrans, (const char **) line, stop);
652 }
653
654 AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop)
655 {
656     const char *pos = ap_strchr_c(*line, stop);
657     char *res;
658
659     if (!pos) {
660         res = apr_pstrdup(atrans, *line);
661         *line += strlen(*line);
662         return res;
663     }
664
665     res = apr_pstrndup(atrans, *line, pos - *line);
666
667     while (*pos == stop) {
668         ++pos;
669     }
670
671     *line = pos;
672
673     return res;
674 }
675
676 AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
677 {
678     return ap_getword_white(atrans, (const char **) line);
679 }
680
681 AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
682 {
683     int pos = -1, x;
684     char *res;
685
686     for (x = 0; (*line)[x]; x++) {
687         if (apr_isspace((*line)[x])) {
688             pos = x;
689             break;
690         }
691     }
692
693     if (pos == -1) {
694         res = apr_pstrdup(atrans, *line);
695         *line += strlen(*line);
696         return res;
697     }
698
699     res = apr_palloc(atrans, pos + 1);
700     apr_cpystrn(res, *line, pos + 1);
701
702     while (apr_isspace((*line)[pos]))
703         ++pos;
704
705     *line += pos;
706
707     return res;
708 }
709
710 AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line, char stop)
711 {
712     return ap_getword_nulls(atrans, (const char **) line, stop);
713 }
714
715 AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line, char stop)
716 {
717     const char *pos = ap_strchr_c(*line, stop);
718     char *res;
719
720     if (!pos) {
721         res = apr_pstrdup(atrans, *line);
722         *line += strlen(*line);
723         return res;
724     }
725
726     res = apr_pstrndup(atrans, *line, pos - *line);
727
728     ++pos;
729
730     *line = pos;
731
732     return res;
733 }
734
735 /* Get a word, (new) config-file style --- quoted strings and backslashes
736  * all honored
737  */
738
739 static char *substring_conf(apr_pool_t *p, const char *start, int len, char quote)
740 {
741     char *result = apr_palloc(p, len + 2);
742     char *resp = result;
743     int i;
744
745     for (i = 0; i < len; ++i) {
746         if (start[i] == '\\' && (start[i + 1] == '\\'
747                                  || (quote && start[i + 1] == quote)))
748             *resp++ = start[++i];
749         else
750             *resp++ = start[i];
751     }
752
753     *resp++ = '\0';
754 #if RESOLVE_ENV_PER_TOKEN
755     return ap_resolve_env(p,result);
756 #else
757     return result;
758 #endif
759 }
760
761 AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line)
762 {
763     return ap_getword_conf(p, (const char **) line);
764 }
765
766 AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line)
767 {
768     const char *str = *line, *strend;
769     char *res;
770     char quote;
771
772     while (*str && apr_isspace(*str))
773         ++str;
774
775     if (!*str) {
776         *line = str;
777         return "";
778     }
779
780     if ((quote = *str) == '"' || quote == '\'') {
781         strend = str + 1;
782         while (*strend && *strend != quote) {
783             if (*strend == '\\' && strend[1] && strend[1] == quote)
784                 strend += 2;
785             else
786                 ++strend;
787         }
788         res = substring_conf(p, str + 1, strend - str - 1, quote);
789
790         if (*strend == quote)
791             ++strend;
792     }
793     else {
794         strend = str;
795         while (*strend && !apr_isspace(*strend))
796             ++strend;
797
798         res = substring_conf(p, str, strend - str, 0);
799     }
800
801     while (*strend && apr_isspace(*strend))
802         ++strend;
803     *line = strend;
804     return res;
805 }
806
807 /* Check a string for any ${ENV} environment variable
808  * construct and replace each them by the value of
809  * that environment variable, if it exists. If the
810  * environment value does not exist, leave the ${ENV}
811  * construct alone; it means something else.
812  */
813 AP_DECLARE(const char *) ap_resolve_env(apr_pool_t *p, const char * word)
814 {
815        char tmp[ MAX_STRING_LEN ];
816        const char *s, *e;
817        tmp[0] = '\0';
818
819        if (!(s=ap_strchr_c(word,'$')))
820                return word;
821
822        do {
823                /* XXX - relies on strncat() to add '\0'
824                 */
825                strncat(tmp,word,s - word);
826                if ((s[1] == '{') && (e=ap_strchr_c(s,'}'))) {
827                        const char *e2 = e;
828                        word = e + 1;
829                        e = getenv(s+2);
830                        if (e) {
831                            strcat(tmp,e);
832                        } else {
833                            strncat(tmp, s, e2-s);
834                            strcat(tmp,"}");
835                        }
836                } else {
837                        /* ignore invalid strings */
838                        word = s+1;
839                        strcat(tmp,"$");
840                };
841        } while ((s=ap_strchr_c(word,'$')));
842        strcat(tmp,word);
843
844        return apr_pstrdup(p,tmp);
845 }
846 AP_DECLARE(int) ap_cfg_closefile(configfile_t *cfp)
847 {
848 #ifdef DEBUG
849     ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, 
850         "Done with config file %s", cfp->name);
851 #endif
852     return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
853 }
854
855 static apr_status_t cfg_close(void *param)
856 {
857     apr_file_t *cfp = (apr_file_t *) param;
858     return (apr_close(cfp));
859 }
860
861 static int cfg_getch(void *param)
862 {
863     char ch;
864     apr_file_t *cfp = (apr_file_t *) param;
865     if (apr_getc(&ch, cfp) == APR_SUCCESS)
866         return ch;
867     return (int)EOF;
868 }
869
870 static void *cfg_getstr(void *buf, size_t bufsiz, void *param)
871 {
872     apr_file_t *cfp = (apr_file_t *) param;
873     apr_status_t rv;
874     rv = apr_fgets(buf, bufsiz, cfp);
875     if (rv == APR_SUCCESS || (rv == APR_EOF && strcmp(buf, "")))
876         return buf;
877     return NULL;
878 }
879
880 /* Open a configfile_t as FILE, return open configfile_t struct pointer */
881 AP_DECLARE(apr_status_t) ap_pcfg_openfile(configfile_t **ret_cfg, apr_pool_t *p, const char *name)
882 {
883     configfile_t *new_cfg;
884     apr_file_t *file = NULL;
885     apr_finfo_t finfo;
886     apr_status_t status;
887 #ifdef DEBUG
888     char buf[120];
889 #endif
890
891     if (name == NULL) {
892         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL,
893                "Internal error: pcfg_openfile() called with NULL filename");
894         return APR_EBADF;
895     }
896
897     if (!ap_os_is_filename_valid(name)) {
898         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL,
899                     "Access to config file %s denied: not a valid filename",
900                     name);
901         return APR_EACCES;
902     }
903
904     status = apr_open(&file, name, APR_READ | APR_BUFFERED, APR_OS_DEFAULT, p);
905 #ifdef DEBUG
906     ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, NULL,
907                 "Opening config file %s (%s)",
908                 name, (status != APR_SUCCESS) ? 
909                 apr_strerror(status, buf, sizeof(buf)) : "successful");
910 #endif
911     if (status != APR_SUCCESS)
912         return status;
913
914     status = apr_getfileinfo(&finfo, file);
915     if (status != APR_SUCCESS)
916         return status;
917
918     if (finfo.filetype != APR_REG &&
919 #if defined(WIN32) || defined(OS2)
920         !(strcasecmp(name, "nul") == 0 ||
921           (strlen(name) >= 4 &&
922            strcasecmp(name + strlen(name) - 4, "/nul") == 0))) {
923 #else
924         strcmp(name, "/dev/null") != 0) {
925 #endif /* WIN32 || OS2 */
926         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL,
927                     "Access to file %s denied by server: not a regular file",
928                     name);
929         apr_close(file);
930         return APR_EBADF;
931     }
932
933     new_cfg = apr_palloc(p, sizeof(*new_cfg));
934     new_cfg->param = file;
935     new_cfg->name = apr_pstrdup(p, name);
936     new_cfg->getch = (int (*)(void *)) cfg_getch;
937     new_cfg->getstr = (void *(*)(void *, size_t, void *)) cfg_getstr;
938     new_cfg->close = (int (*)(void *)) cfg_close;
939     new_cfg->line_number = 0;
940     *ret_cfg = new_cfg;
941     return APR_SUCCESS;
942 }
943
944
945 /* Allocate a configfile_t handle with user defined functions and params */
946 AP_DECLARE(configfile_t *) ap_pcfg_open_custom(apr_pool_t *p, const char *descr,
947     void *param,
948     int(*getch)(void *param),
949     void *(*getstr) (void *buf, size_t bufsiz, void *param),
950     int(*close_func)(void *param))
951 {
952     configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg));
953 #ifdef DEBUG
954     ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, NULL, "Opening config handler %s", descr);
955 #endif
956     new_cfg->param = param;
957     new_cfg->name = descr;
958     new_cfg->getch = getch;
959     new_cfg->getstr = getstr;
960     new_cfg->close = close_func;
961     new_cfg->line_number = 0;
962     return new_cfg;
963 }
964
965
966 /* Read one character from a configfile_t */
967 AP_DECLARE(int) ap_cfg_getc(configfile_t *cfp)
968 {
969     register int ch = cfp->getch(cfp->param);
970     if (ch == LF) 
971         ++cfp->line_number;
972     return ch;
973 }
974
975
976 /* Read one line from open configfile_t, strip LF, increase line number */
977 /* If custom handler does not define a getstr() function, read char by char */
978 AP_DECLARE(int) ap_cfg_getline(char *buf, size_t bufsize, configfile_t *cfp)
979 {
980     /* If a "get string" function is defined, use it */
981     if (cfp->getstr != NULL) {
982         char *src, *dst;
983         char *cp;
984         char *cbuf = buf;
985         size_t cbufsize = bufsize;
986
987         while (1) {
988             ++cfp->line_number;
989             if (cfp->getstr(cbuf, cbufsize, cfp->param) == NULL)
990                 return 1;
991
992             /*
993              *  check for line continuation,
994              *  i.e. match [^\\]\\[\r]\n only
995              */
996             cp = cbuf;
997             while (cp < cbuf+cbufsize && *cp != '\0')
998                 cp++;
999             if (cp > cbuf && cp[-1] == LF) {
1000                 cp--;
1001                 if (cp > cbuf && cp[-1] == CR)
1002                     cp--;
1003                 if (cp > cbuf && cp[-1] == '\\') {
1004                     cp--;
1005                     if (!(cp > cbuf && cp[-1] == '\\')) {
1006                         /*
1007                          * line continuation requested -
1008                          * then remove backslash and continue
1009                          */
1010                         cbufsize -= (cp-cbuf);
1011                         cbuf = cp;
1012                         continue;
1013                     }
1014                     else {
1015                         /* 
1016                          * no real continuation because escaped -
1017                          * then just remove escape character
1018                          */
1019                         for ( ; cp < cbuf+cbufsize && *cp != '\0'; cp++)
1020                             cp[0] = cp[1];
1021                     }   
1022                 }
1023             }
1024             break;
1025         }
1026
1027         /*
1028          * Leading and trailing white space is eliminated completely
1029          */
1030         src = buf;
1031         while (apr_isspace(*src))
1032             ++src;
1033         /* blast trailing whitespace */
1034         dst = &src[strlen(src)];
1035         while (--dst >= src && apr_isspace(*dst))
1036             *dst = '\0';
1037         /* Zap leading whitespace by shifting */
1038         if (src != buf)
1039             for (dst = buf; (*dst++ = *src++) != '\0'; )
1040                 ;
1041
1042 #ifdef DEBUG_CFG_LINES
1043         ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Read config: %s", buf);
1044 #endif
1045         return 0;
1046     } else {
1047         /* No "get string" function defined; read character by character */
1048         register int c;
1049         register size_t i = 0;
1050
1051         buf[0] = '\0';
1052         /* skip leading whitespace */
1053         do {
1054             c = cfp->getch(cfp->param);
1055         } while (c == '\t' || c == ' ');
1056
1057         if (c == EOF)
1058             return 1;
1059         
1060         if(bufsize < 2) {
1061             /* too small, assume caller is crazy */
1062             return 1;
1063         }
1064
1065         while (1) {
1066             if ((c == '\t') || (c == ' ')) {
1067                 buf[i++] = ' ';
1068                 while ((c == '\t') || (c == ' '))
1069                     c = cfp->getch(cfp->param);
1070             }
1071             if (c == CR) {
1072                 /* silently ignore CR (_assume_ that a LF follows) */
1073                 c = cfp->getch(cfp->param);
1074             }
1075             if (c == LF) {
1076                 /* increase line number and return on LF */
1077                 ++cfp->line_number;
1078             }
1079             if (c == EOF || c == 0x4 || c == LF || i >= (bufsize - 2)) {
1080                 /* 
1081                  *  check for line continuation
1082                  */
1083                 if (i > 0 && buf[i-1] == '\\') {
1084                     i--;
1085                     if (!(i > 0 && buf[i-1] == '\\')) {
1086                         /* line is continued */
1087                         c = cfp->getch(cfp->param);
1088                         continue;
1089                     }
1090                     /* else nothing needs be done because
1091                      * then the backslash is escaped and
1092                      * we just strip to a single one
1093                      */
1094                 }
1095                 /* blast trailing whitespace */
1096                 while (i > 0 && apr_isspace(buf[i - 1]))
1097                     --i;
1098                 buf[i] = '\0';
1099 #ifdef DEBUG_CFG_LINES
1100                 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Read config: %s", buf);
1101 #endif
1102                 return 0;
1103             }
1104             buf[i] = c;
1105             ++i;
1106             c = cfp->getch(cfp->param);
1107         }
1108     }
1109 }
1110
1111 /* Size an HTTP header field list item, as separated by a comma.
1112  * The return value is a pointer to the beginning of the non-empty list item
1113  * within the original string (or NULL if there is none) and the address
1114  * of field is shifted to the next non-comma, non-whitespace character.
1115  * len is the length of the item excluding any beginning whitespace.
1116  */
1117 AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len)
1118 {
1119     const unsigned char *ptr = (const unsigned char *)*field;
1120     const unsigned char *token;
1121     int in_qpair, in_qstr, in_com;
1122
1123     /* Find first non-comma, non-whitespace byte */
1124
1125     while (*ptr == ',' || apr_isspace(*ptr))
1126         ++ptr;
1127
1128     token = ptr;
1129
1130     /* Find the end of this item, skipping over dead bits */
1131
1132     for (in_qpair = in_qstr = in_com = 0;
1133          *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1134          ++ptr) {
1135
1136         if (in_qpair) {
1137             in_qpair = 0;
1138         }
1139         else {
1140             switch (*ptr) {
1141                 case '\\': in_qpair = 1;      /* quoted-pair         */
1142                            break;
1143                 case '"' : if (!in_com)       /* quoted string delim */
1144                                in_qstr = !in_qstr;
1145                            break;
1146                 case '(' : if (!in_qstr)      /* comment (may nest)  */
1147                                ++in_com;
1148                            break;
1149                 case ')' : if (in_com)        /* end comment         */
1150                                --in_com;
1151                            break;
1152                 default  : break;
1153             }
1154         }
1155     }
1156
1157     if ((*len = (ptr - token)) == 0) {
1158         *field = (const char *)ptr;
1159         return NULL;
1160     }
1161
1162     /* Advance field pointer to the next non-comma, non-white byte */
1163
1164     while (*ptr == ',' || apr_isspace(*ptr))
1165         ++ptr;
1166
1167     *field = (const char *)ptr;
1168     return (const char *)token;
1169 }
1170
1171 /* Retrieve an HTTP header field list item, as separated by a comma,
1172  * while stripping insignificant whitespace and lowercasing anything not in
1173  * a quoted string or comment.  The return value is a new string containing
1174  * the converted list item (or NULL if none) and the address pointed to by
1175  * field is shifted to the next non-comma, non-whitespace.
1176  */
1177 AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field)
1178 {
1179     const char *tok_start;
1180     const unsigned char *ptr;
1181     unsigned char *pos;
1182     char *token;
1183     int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
1184
1185     /* Find the beginning and maximum length of the list item so that
1186      * we can allocate a buffer for the new string and reset the field.
1187      */
1188     if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
1189         return NULL;
1190     }
1191     token = apr_palloc(p, tok_len + 1);
1192
1193     /* Scan the token again, but this time copy only the good bytes.
1194      * We skip extra whitespace and any whitespace around a '=', '/',
1195      * or ';' and lowercase normal characters not within a comment,
1196      * quoted-string or quoted-pair.
1197      */
1198     for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
1199          *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1200          ++ptr) {
1201
1202         if (in_qpair) {
1203             in_qpair = 0;
1204             *pos++ = *ptr;
1205         }
1206         else {
1207             switch (*ptr) {
1208                 case '\\': in_qpair = 1;
1209                            if (addspace == 1)
1210                                *pos++ = ' ';
1211                            *pos++ = *ptr;
1212                            addspace = 0;
1213                            break;
1214                 case '"' : if (!in_com)
1215                                in_qstr = !in_qstr;
1216                            if (addspace == 1)
1217                                *pos++ = ' ';
1218                            *pos++ = *ptr;
1219                            addspace = 0;
1220                            break;
1221                 case '(' : if (!in_qstr)
1222                                ++in_com;
1223                            if (addspace == 1)
1224                                *pos++ = ' ';
1225                            *pos++ = *ptr;
1226                            addspace = 0;
1227                            break;
1228                 case ')' : if (in_com)
1229                                --in_com;
1230                            *pos++ = *ptr;
1231                            addspace = 0;
1232                            break;
1233                 case ' ' :
1234                 case '\t': if (addspace)
1235                                break;
1236                            if (in_com || in_qstr)
1237                                *pos++ = *ptr;
1238                            else
1239                                addspace = 1;
1240                            break;
1241                 case '=' :
1242                 case '/' :
1243                 case ';' : if (!(in_com || in_qstr))
1244                                addspace = -1;
1245                            *pos++ = *ptr;
1246                            break;
1247                 default  : if (addspace == 1)
1248                                *pos++ = ' ';
1249                            *pos++ = (in_com || in_qstr) ? *ptr
1250                                                         : apr_tolower(*ptr);
1251                            addspace = 0;
1252                            break;
1253             }
1254         }
1255     }
1256     *pos = '\0';
1257
1258     return token;
1259 }
1260
1261 /* Find an item in canonical form (lowercase, no extra spaces) within
1262  * an HTTP field value list.  Returns 1 if found, 0 if not found.
1263  * This would be much more efficient if we stored header fields as
1264  * an array of list items as they are received instead of a plain string.
1265  */
1266 AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line, const char *tok)
1267 {
1268     const unsigned char *pos;
1269     const unsigned char *ptr = (const unsigned char *)line;
1270     int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
1271
1272     if (!line || !tok)
1273         return 0;
1274
1275     do {  /* loop for each item in line's list */
1276
1277         /* Find first non-comma, non-whitespace byte */
1278
1279         while (*ptr == ',' || apr_isspace(*ptr))
1280             ++ptr;
1281
1282         if (*ptr)
1283             good = 1;  /* until proven otherwise for this item */
1284         else
1285             break;     /* no items left and nothing good found */
1286
1287         /* We skip extra whitespace and any whitespace around a '=', '/',
1288          * or ';' and lowercase normal characters not within a comment,
1289          * quoted-string or quoted-pair.
1290          */
1291         for (pos = (const unsigned char *)tok;
1292              *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1293              ++ptr) {
1294
1295             if (in_qpair) {
1296                 in_qpair = 0;
1297                 if (good)
1298                     good = (*pos++ == *ptr);
1299             }
1300             else {
1301                 switch (*ptr) {
1302                     case '\\': in_qpair = 1;
1303                                if (addspace == 1)
1304                                    good = good && (*pos++ == ' ');
1305                                good = good && (*pos++ == *ptr);
1306                                addspace = 0;
1307                                break;
1308                     case '"' : if (!in_com)
1309                                    in_qstr = !in_qstr;
1310                                if (addspace == 1)
1311                                    good = good && (*pos++ == ' ');
1312                                good = good && (*pos++ == *ptr);
1313                                addspace = 0;
1314                                break;
1315                     case '(' : if (!in_qstr)
1316                                    ++in_com;
1317                                if (addspace == 1)
1318                                    good = good && (*pos++ == ' ');
1319                                good = good && (*pos++ == *ptr);
1320                                addspace = 0;
1321                                break;
1322                     case ')' : if (in_com)
1323                                    --in_com;
1324                                good = good && (*pos++ == *ptr);
1325                                addspace = 0;
1326                                break;
1327                     case ' ' :
1328                     case '\t': if (addspace || !good)
1329                                    break;
1330                                if (in_com || in_qstr)
1331                                    good = (*pos++ == *ptr);
1332                                else
1333                                    addspace = 1;
1334                                break;
1335                     case '=' :
1336                     case '/' :
1337                     case ';' : if (!(in_com || in_qstr))
1338                                    addspace = -1;
1339                                good = good && (*pos++ == *ptr);
1340                                break;
1341                     default  : if (!good)
1342                                    break;
1343                                if (addspace == 1)
1344                                    good = (*pos++ == ' ');
1345                                if (in_com || in_qstr)
1346                                    good = good && (*pos++ == *ptr);
1347                                else
1348                                    good = good && (*pos++ == apr_tolower(*ptr));
1349                                addspace = 0;
1350                                break;
1351                 }
1352             }
1353         }
1354         if (good && *pos)
1355             good = 0;          /* not good if only a prefix was matched */
1356
1357     } while (*ptr && !good);
1358
1359     return good;
1360 }
1361
1362
1363 /* Retrieve a token, spacing over it and returning a pointer to
1364  * the first non-white byte afterwards.  Note that these tokens
1365  * are delimited by semis and commas; and can also be delimited
1366  * by whitespace at the caller's option.
1367  */
1368
1369 AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line, int accept_white)
1370 {
1371     const char *ptr = *accept_line;
1372     const char *tok_start;
1373     char *token;
1374     int tok_len;
1375
1376     /* Find first non-white byte */
1377
1378     while (*ptr && apr_isspace(*ptr))
1379         ++ptr;
1380
1381     tok_start = ptr;
1382
1383     /* find token end, skipping over quoted strings.
1384      * (comments are already gone).
1385      */
1386
1387     while (*ptr && (accept_white || !apr_isspace(*ptr))
1388            && *ptr != ';' && *ptr != ',') {
1389         if (*ptr++ == '"')
1390             while (*ptr)
1391                 if (*ptr++ == '"')
1392                     break;
1393     }
1394
1395     tok_len = ptr - tok_start;
1396     token = apr_pstrndup(p, tok_start, tok_len);
1397
1398     /* Advance accept_line pointer to the next non-white byte */
1399
1400     while (*ptr && apr_isspace(*ptr))
1401         ++ptr;
1402
1403     *accept_line = ptr;
1404     return token;
1405 }
1406
1407
1408 /* find http tokens, see the definition of token from RFC2068 */
1409 AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1410 {
1411     const unsigned char *start_token;
1412     const unsigned char *s;
1413
1414     if (!line)
1415         return 0;
1416
1417     s = (const unsigned char *)line;
1418     for (;;) {
1419         /* find start of token, skip all stop characters, note NUL
1420          * isn't a token stop, so we don't need to test for it
1421          */
1422         while (TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1423             ++s;
1424         }
1425         if (!*s) {
1426             return 0;
1427         }
1428         start_token = s;
1429         /* find end of the token */
1430         while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1431             ++s;
1432         }
1433         if (!strncasecmp((const char *)start_token, (const char *)tok, s - start_token)) {
1434             return 1;
1435         }
1436         if (!*s) {
1437             return 0;
1438         }
1439     }
1440 }
1441
1442
1443 AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line, const char *tok)
1444 {
1445     int llen, tlen, lidx;
1446
1447     if (!line)
1448         return 0;
1449
1450     llen = strlen(line);
1451     tlen = strlen(tok);
1452     lidx = llen - tlen;
1453
1454     if ((lidx < 0) ||
1455         ((lidx > 0) && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1456         return 0;
1457
1458     return (strncasecmp(&line[lidx], tok, tlen) == 0);
1459 }
1460
1461 AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1462 {
1463     char *cmd;
1464     unsigned char *d;
1465     const unsigned char *s;
1466
1467     cmd = apr_palloc(p, 2 * strlen(str) + 1);   /* Be safe */
1468     d = (unsigned char *)cmd;
1469     s = (const unsigned char *)str;
1470     for (; *s; ++s) {
1471
1472 #if defined(OS2) || defined(WIN32)
1473         /* Don't allow '&' in parameters under OS/2. */
1474         /* This can be used to send commands to the shell. */
1475         if (*s == '&') {
1476             *d++ = ' ';
1477             continue;
1478         }
1479 #endif
1480
1481         if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1482             *d++ = '\\';
1483         }
1484         *d++ = *s;
1485     }
1486     *d = '\0';
1487
1488     return cmd;
1489 }
1490
1491 static char x2c(const char *what)
1492 {
1493     register char digit;
1494
1495 #ifndef CHARSET_EBCDIC
1496     digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
1497     digit *= 16;
1498     digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
1499 #else /*CHARSET_EBCDIC*/
1500     char xstr[5];
1501     xstr[0]='0';
1502     xstr[1]='x';
1503     xstr[2]=what[0];
1504     xstr[3]=what[1];
1505     xstr[4]='\0';
1506     digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFF & strtol(xstr, NULL, 16));
1507 #endif /*CHARSET_EBCDIC*/
1508     return (digit);
1509 }
1510
1511 /*
1512  * Unescapes a URL.
1513  * Returns 0 on success, non-zero on error
1514  * Failure is due to
1515  *   bad % escape       returns HTTP_BAD_REQUEST
1516  *
1517  *   decoding %00 -> \0
1518  *   decoding %2f -> /   (a special character)
1519  *                      returns HTTP_NOT_FOUND
1520  */
1521 AP_DECLARE(int) ap_unescape_url(char *url)
1522 {
1523     register int badesc, badpath;
1524     char *x, *y;
1525
1526     badesc = 0;
1527     badpath = 0;
1528     /* Initial scan for first '%'. Don't bother writing values before
1529      * seeing a '%' */
1530     y = strchr(url, '%');
1531     if (y == NULL) {
1532         return OK;
1533     }
1534     for (x = y; *y; ++x, ++y) {
1535         if (*y != '%')
1536             *x = *y;
1537         else {
1538             if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1539                 badesc = 1;
1540                 *x = '%';
1541             }
1542             else {
1543                 *x = x2c(y + 1);
1544                 y += 2;
1545                 if (*x == '/' || *x == '\0')
1546                     badpath = 1;
1547             }
1548         }
1549     }
1550     *x = '\0';
1551     if (badesc)
1552         return HTTP_BAD_REQUEST;
1553     else if (badpath)
1554         return HTTP_NOT_FOUND;
1555     else
1556         return OK;
1557 }
1558
1559 AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
1560                                     apr_port_t port, const request_rec *r)
1561 {
1562     if (ap_is_default_port(port, r))
1563         return apr_pstrdup(p, hostname);
1564     else {
1565         return apr_psprintf(p, "%s:%u", hostname, port);
1566     }
1567 }
1568
1569 /* c2x takes an unsigned, and expects the caller has guaranteed that
1570  * 0 <= what < 256... which usually means that you have to cast to
1571  * unsigned char first, because (unsigned)(char)(x) first goes through
1572  * signed extension to an int before the unsigned cast.
1573  *
1574  * The reason for this assumption is to assist gcc code generation --
1575  * the unsigned char -> unsigned extension is already done earlier in
1576  * both uses of this code, so there's no need to waste time doing it
1577  * again.
1578  */
1579 static const char c2x_table[] = "0123456789abcdef";
1580
1581 static apr_inline unsigned char *c2x(unsigned what, unsigned char *where)
1582 {
1583 #ifdef CHARSET_EBCDIC
1584     what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
1585 #endif /*CHARSET_EBCDIC*/
1586     *where++ = '%';
1587     *where++ = c2x_table[what >> 4];
1588     *where++ = c2x_table[what & 0xf];
1589     return where;
1590 }
1591
1592 /*
1593  * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
1594  * routine is (should be) OS independent.
1595  *
1596  * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
1597  * cases if a ':' occurs before the first '/' in the URL, the URL should be
1598  * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
1599  * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
1600  * efficiency reasons, we don't use escape_path_segment(), which is provided for
1601  * reference. Again, RFC 1808 is where this stuff is defined.
1602  *
1603  * If partial is set, os_escape_path() assumes that the path will be appended to
1604  * something with a '/' in it (and thus does not prefix "./").
1605  */
1606
1607 AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
1608 {
1609     char *copy = apr_palloc(p, 3 * strlen(segment) + 1);
1610     const unsigned char *s = (const unsigned char *)segment;
1611     unsigned char *d = (unsigned char *)copy;
1612     unsigned c;
1613
1614     while ((c = *s)) {
1615         if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
1616             d = c2x(c, d);
1617         }
1618         else {
1619             *d++ = c;
1620         }
1621         ++s;
1622     }
1623     *d = '\0';
1624     return copy;
1625 }
1626
1627 AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
1628 {
1629     char *copy = apr_palloc(p, 3 * strlen(path) + 3);
1630     const unsigned char *s = (const unsigned char *)path;
1631     unsigned char *d = (unsigned char *)copy;
1632     unsigned c;
1633
1634     if (!partial) {
1635         const char *colon = ap_strchr_c(path, ':');
1636         const char *slash = ap_strchr_c(path, '/');
1637
1638         if (colon && (!slash || colon < slash)) {
1639             *d++ = '.';
1640             *d++ = '/';
1641         }
1642     }
1643     while ((c = *s)) {
1644         if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
1645             d = c2x(c, d);
1646         }
1647         else {
1648             *d++ = c;
1649         }
1650         ++s;
1651     }
1652     *d = '\0';
1653     return copy;
1654 }
1655
1656 /* ap_escape_uri is now a macro for os_escape_path */
1657
1658 AP_DECLARE(char *) ap_escape_html(apr_pool_t *p, const char *s)
1659 {
1660     int i, j;
1661     char *x;
1662
1663     /* first, count the number of extra characters */
1664     for (i = 0, j = 0; s[i] != '\0'; i++)
1665         if (s[i] == '<' || s[i] == '>')
1666             j += 3;
1667         else if (s[i] == '&')
1668             j += 4;
1669
1670     if (j == 0)
1671         return apr_pstrndup(p, s, i);
1672
1673     x = apr_palloc(p, i + j + 1);
1674     for (i = 0, j = 0; s[i] != '\0'; i++, j++)
1675         if (s[i] == '<') {
1676             memcpy(&x[j], "&lt;", 4);
1677             j += 3;
1678         }
1679         else if (s[i] == '>') {
1680             memcpy(&x[j], "&gt;", 4);
1681             j += 3;
1682         }
1683         else if (s[i] == '&') {
1684             memcpy(&x[j], "&amp;", 5);
1685             j += 4;
1686         }
1687         else
1688             x[j] = s[i];
1689
1690     x[j] = '\0';
1691     return x;
1692 }
1693
1694 AP_DECLARE(int) ap_is_directory(const char *path)
1695 {
1696     apr_finfo_t finfo;
1697
1698     if (apr_stat(&finfo, path, NULL) == -1)
1699         return 0;               /* in error condition, just return no */
1700
1701     return (finfo.filetype == APR_DIR);
1702 }
1703
1704 AP_DECLARE(int) ap_is_rdirectory(const char *path)
1705 {
1706     apr_finfo_t finfo;
1707
1708     if (apr_lstat(&finfo, path, NULL) == -1)
1709         return 0;               /* in error condition, just return no */
1710
1711     return (finfo.filetype == APR_DIR);
1712 }
1713
1714 AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
1715                                   const char *src2)
1716 {
1717     register int x;
1718
1719     x = strlen(src1);
1720     if (x == 0)
1721         return apr_pstrcat(a, "/", src2, NULL);
1722
1723     if (src1[x - 1] != '/')
1724         return apr_pstrcat(a, src1, "/", src2, NULL);
1725     else
1726         return apr_pstrcat(a, src1, src2, NULL);
1727 }
1728
1729 /*
1730  * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
1731  */
1732 AP_DECLARE(int) ap_is_url(const char *u)
1733 {
1734     register int x;
1735
1736     for (x = 0; u[x] != ':'; x++) {
1737         if ((!u[x]) ||
1738             ((!apr_isalpha(u[x])) && (!apr_isdigit(u[x])) &&
1739              (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
1740             return 0;
1741         }
1742     }
1743
1744     return (x ? 1 : 0);         /* If the first character is ':', it's broken, too */
1745 }
1746
1747 #ifndef HAVE_INITGROUPS
1748 int initgroups(const char *name, gid_t basegid)
1749 {
1750 #if defined(QNX) || defined(MPE) || defined(BEOS) || defined(_OSD_POSIX) || defined(TPF) || defined(__TANDEM) || defined(OS2) || defined(WIN32)
1751 /* QNX, MPE and BeOS do not appear to support supplementary groups. */
1752     return 0;
1753 #else /* ndef QNX */
1754     gid_t groups[NGROUPS_MAX];
1755     struct group *g;
1756     int index = 0;
1757
1758     setgrent();
1759
1760     groups[index++] = basegid;
1761
1762     while (index < NGROUPS_MAX && ((g = getgrent()) != NULL))
1763         if (g->gr_gid != basegid) {
1764             char **names;
1765
1766             for (names = g->gr_mem; *names != NULL; ++names)
1767                 if (!strcmp(*names, name))
1768                     groups[index++] = g->gr_gid;
1769         }
1770
1771     endgrent();
1772
1773     return setgroups(index, groups);
1774 #endif /* def QNX */
1775 }
1776 #endif /* def NEED_INITGROUPS */
1777
1778 AP_DECLARE(int) ap_ind(const char *s, char c)
1779 {
1780     register int x;
1781
1782     for (x = 0; s[x]; x++)
1783         if (s[x] == c)
1784             return x;
1785
1786     return -1;
1787 }
1788
1789 AP_DECLARE(int) ap_rind(const char *s, char c)
1790 {
1791     register int x;
1792
1793     for (x = strlen(s) - 1; x != -1; x--)
1794         if (s[x] == c)
1795             return x;
1796
1797     return -1;
1798 }
1799
1800 AP_DECLARE(void) ap_str_tolower(char *str)
1801 {
1802     while (*str) {
1803         *str = apr_tolower(*str);
1804         ++str;
1805     }
1806 }
1807
1808 AP_DECLARE(uid_t) ap_uname2id(const char *name)
1809 {
1810 #ifdef WIN32
1811     return (1);
1812 #else
1813     struct passwd *ent;
1814
1815     if (name[0] == '#')
1816         return (atoi(&name[1]));
1817
1818     if (!(ent = getpwnam(name))) {
1819         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "%s: bad user name %s", ap_server_argv0, name);
1820         exit(1);
1821     }
1822     return (ent->pw_uid);
1823 #endif
1824 }
1825
1826 AP_DECLARE(gid_t) ap_gname2id(const char *name)
1827 {
1828 #ifdef WIN32
1829     return (1);
1830 #else
1831     struct group *ent;
1832
1833     if (name[0] == '#')
1834         return (atoi(&name[1]));
1835
1836     if (!(ent = getgrnam(name))) {
1837         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "%s: bad group name %s", ap_server_argv0, name);
1838         exit(1);
1839     }
1840     return (ent->gr_gid);
1841 #endif
1842 }
1843
1844
1845 /*
1846  * Parses a host of the form <address>[:port]
1847  * :port is permitted if 'port' is not NULL
1848  */
1849 unsigned long ap_get_virthost_addr(char *w, apr_port_t *ports)
1850 {
1851     struct hostent *hep;
1852     unsigned long my_addr;
1853     char *p;
1854
1855     p = strchr(w, ':');
1856     if (ports != NULL) {
1857         *ports = 0;
1858         if (p != NULL && strcmp(p + 1, "*") != 0)
1859             *ports = atoi(p + 1);
1860     }
1861
1862     if (p != NULL)
1863         *p = '\0';
1864     if (strcmp(w, "*") == 0) {
1865         if (p != NULL)
1866             *p = ':';
1867         return htonl(INADDR_ANY);
1868     }
1869
1870     my_addr = apr_inet_addr((char *)w);
1871     if (my_addr != INADDR_NONE) {
1872         if (p != NULL)
1873             *p = ':';
1874         return my_addr;
1875     }
1876
1877     hep = gethostbyname(w);
1878
1879     if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
1880         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Cannot resolve host name %s --- exiting!", w);
1881         exit(1);
1882     }
1883
1884     if (hep->h_addr_list[1]) {
1885         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Host %s has multiple addresses ---", w);
1886         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "you must choose one explicitly for use as");
1887         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "a virtual host.  Exiting!!!");
1888         exit(1);
1889     }
1890
1891     if (p != NULL)
1892         *p = ':';
1893
1894     return ((struct in_addr *) (hep->h_addr))->s_addr;
1895 }
1896
1897
1898 static char *find_fqdn(apr_pool_t *a, struct hostent *p)
1899 {
1900     int x;
1901
1902     if (!strchr(p->h_name, '.')) {
1903         for (x = 0; p->h_aliases[x]; ++x) {
1904             if (strchr(p->h_aliases[x], '.') &&
1905                 (!strncasecmp(p->h_aliases[x], p->h_name, strlen(p->h_name))))
1906                 return apr_pstrdup(a, p->h_aliases[x]);
1907         }
1908         return NULL;
1909     }
1910     return apr_pstrdup(a, (void *) p->h_name);
1911 }
1912
1913 char *ap_get_local_host(apr_pool_t *a)
1914 {
1915 #ifndef MAXHOSTNAMELEN
1916 #define MAXHOSTNAMELEN 256
1917 #endif
1918     char str[MAXHOSTNAMELEN + 1];
1919     char *server_hostname = NULL;
1920     struct hostent *p;
1921
1922 #ifdef BEOS
1923     if (gethostname(str, sizeof(str) - 1) == 0)
1924 #else
1925     if (gethostname(str, sizeof(str) - 1) != 0)
1926 #endif
1927     {
1928         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, NULL,
1929                      "%s: gethostname() failed to detemine ServerName",
1930                      ap_server_argv0);
1931     }
1932     else 
1933     {
1934         str[sizeof(str) - 1] = '\0';
1935         if ((!(p = gethostbyname(str))) 
1936             || (!(server_hostname = find_fqdn(a, p)))) {
1937             /* Recovery - return the default servername by IP: */
1938             if (!str && p->h_addr_list[0]) {
1939                 apr_snprintf(str, sizeof(str), "%pA", p->h_addr_list[0]);
1940                 server_hostname = apr_pstrdup(a, str);
1941                 /* We will drop through to report the IP-named server */
1942             }
1943         }
1944         else {
1945             /* Since we found a fdqn, return it with no logged message. */
1946             return server_hostname;
1947         }
1948     }
1949
1950     if (!server_hostname) 
1951         server_hostname = apr_pstrdup(a, "127.0.0.1");
1952
1953     ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO|APLOG_STARTUP, 0, NULL,
1954                  "%s: Could not find determine the server's fully qualified "
1955                  "domain name, using %s for ServerName",
1956                  ap_server_argv0, server_hostname);
1957              
1958     return server_hostname;
1959 }
1960
1961 /* simple 'pool' alloc()ing glue to ap_base64.c
1962  */
1963 AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
1964 {
1965     char *decoded;
1966     int l;
1967
1968     decoded = (char *) apr_palloc(p, 1 + ap_base64decode_len(bufcoded));
1969     l = ap_base64decode(decoded, bufcoded);
1970     decoded[l] = '\0'; /* make binary sequence into string */
1971
1972     return decoded;
1973 }
1974
1975 AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string) 
1976
1977     char *encoded;
1978     int l = strlen(string);
1979
1980     encoded = (char *) apr_palloc(p, 1 + ap_base64encode_len(l));
1981     l = ap_base64encode(encoded, string, l);
1982     encoded[l] = '\0'; /* make binary sequence into string */
1983
1984     return encoded;
1985 }
1986
1987 /* we want to downcase the type/subtype for comparison purposes
1988  * but nothing else because ;parameter=foo values are case sensitive.
1989  * XXX: in truth we want to downcase parameter names... but really,
1990  * apache has never handled parameters and such correctly.  You
1991  * also need to compress spaces and such to be able to compare
1992  * properly. -djg
1993  */
1994 AP_DECLARE(void) ap_content_type_tolower(char *str)
1995 {
1996     char *semi;
1997
1998     semi = strchr(str, ';');
1999     if (semi) {
2000         *semi = '\0';
2001     }
2002     while (*str) {
2003         *str = apr_tolower(*str);
2004         ++str;
2005     }
2006     if (semi) {
2007         *semi = ';';
2008     }
2009 }
2010
2011 /*
2012  * Given a string, replace any bare " with \" .
2013  */
2014 AP_DECLARE(char *) ap_escape_quotes (apr_pool_t *p, const char *instring)
2015 {
2016     int newlen = 0;
2017     const char *inchr = instring;
2018     char *outchr, *outstring;
2019
2020     /*
2021      * Look through the input string, jogging the length of the output
2022      * string up by an extra byte each time we find an unescaped ".
2023      */
2024     while (*inchr != '\0') {
2025         newlen++;
2026         if (*inchr == '"') {
2027             newlen++;
2028         }
2029         /*
2030          * If we find a slosh, and it's not the last byte in the string,
2031          * it's escaping something - advance past both bytes.
2032          */
2033         if ((*inchr == '\\') && (inchr[1] != '\0')) {
2034             inchr++;
2035             newlen++;
2036         }
2037         inchr++;
2038     }
2039     outstring = apr_palloc(p, newlen + 1);
2040     inchr = instring;
2041     outchr = outstring;
2042     /*
2043      * Now copy the input string to the output string, inserting a slosh
2044      * in front of every " that doesn't already have one.
2045      */
2046     while (*inchr != '\0') {
2047         if ((*inchr == '\\') && (inchr[1] != '\0')) {
2048             *outchr++ = *inchr++;
2049             *outchr++ = *inchr++;
2050         }
2051         if (*inchr == '"') {
2052             *outchr++ = '\\';
2053         }
2054         if (*inchr != '\0') {
2055             *outchr++ = *inchr++;
2056         }
2057     }
2058     *outchr = '\0';
2059     return outstring;
2060 }