]> granicus.if.org Git - apache/blob - server/util.c
Description of terms used to describe modules in the new (not yet
[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 API_EXPORT(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 API_EXPORT(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 API_EXPORT(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 API_EXPORT(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 API_EXPORT(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 API_EXPORT(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 API_EXPORT(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 API_EXPORT(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  * Apache stub function for the regex libraries regexec() to make sure the
338  * whole regex(3) API is available through the Apache (exported) namespace.
339  * This is especially important for the DSO situations of modules.
340  * DO NOT MAKE A MACRO OUT OF THIS FUNCTION!
341  */
342 API_EXPORT(int) ap_regexec(regex_t *preg, const char *string,
343                            size_t nmatch, regmatch_t pmatch[], int eflags)
344 {
345     return regexec(preg, string, nmatch, pmatch, eflags);
346 }
347
348 API_EXPORT(size_t) ap_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
349 {
350     return regerror(errcode, preg, errbuf, errbuf_size);
351 }
352
353
354 /* This function substitutes for $0-$9, filling in regular expression
355  * submatches. Pass it the same nmatch and pmatch arguments that you
356  * passed ap_regexec(). pmatch should not be greater than the maximum number
357  * of subexpressions - i.e. one more than the re_nsub member of regex_t.
358  *
359  * input should be the string with the $-expressions, source should be the
360  * string that was matched against.
361  *
362  * It returns the substituted string, or NULL on error.
363  *
364  * Parts of this code are based on Henry Spencer's regsub(), from his
365  * AT&T V8 regexp package.
366  */
367
368 API_EXPORT(char *) ap_pregsub(apr_pool_t *p, const char *input, const char *source,
369                            size_t nmatch, regmatch_t pmatch[])
370 {
371     const char *src = input;
372     char *dest, *dst;
373     char c;
374     size_t no;
375     int len;
376
377     if (!source)
378         return NULL;
379     if (!nmatch)
380         return apr_pstrdup(p, src);
381
382     /* First pass, find the size */
383
384     len = 0;
385
386     while ((c = *src++) != '\0') {
387         if (c == '&')
388             no = 0;
389         else if (c == '$' && apr_isdigit(*src))
390             no = *src++ - '0';
391         else
392             no = 10;
393
394         if (no > 9) {           /* Ordinary character. */
395             if (c == '\\' && (*src == '$' || *src == '&'))
396                 c = *src++;
397             len++;
398         }
399         else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
400             len += pmatch[no].rm_eo - pmatch[no].rm_so;
401         }
402
403     }
404
405     dest = dst = apr_pcalloc(p, len + 1);
406
407     /* Now actually fill in the string */
408
409     src = input;
410
411     while ((c = *src++) != '\0') {
412         if (c == '&')
413             no = 0;
414         else if (c == '$' && apr_isdigit(*src))
415             no = *src++ - '0';
416         else
417             no = 10;
418
419         if (no > 9) {           /* Ordinary character. */
420             if (c == '\\' && (*src == '$' || *src == '&'))
421                 c = *src++;
422             *dst++ = c;
423         }
424         else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
425             len = pmatch[no].rm_eo - pmatch[no].rm_so;
426             memcpy(dst, source + pmatch[no].rm_so, len);
427             dst += len;
428         }
429
430     }
431     *dst = '\0';
432
433     return dest;
434 }
435
436 /*
437  * Parse .. so we don't compromise security
438  */
439 API_EXPORT(void) ap_getparents(char *name)
440 {
441     int l, w;
442
443     /* Four paseses, as per RFC 1808 */
444     /* a) remove ./ path segments */
445
446     for (l = 0, w = 0; name[l] != '\0';) {
447         if (name[l] == '.' && name[l + 1] == '/' && (l == 0 || name[l - 1] == '/'))
448             l += 2;
449         else
450             name[w++] = name[l++];
451     }
452
453     /* b) remove trailing . path, segment */
454     if (w == 1 && name[0] == '.')
455         w--;
456     else if (w > 1 && name[w - 1] == '.' && name[w - 2] == '/')
457         w--;
458     name[w] = '\0';
459
460     /* c) remove all xx/../ segments. (including leading ../ and /../) */
461     l = 0;
462
463     while (name[l] != '\0') {
464         if (name[l] == '.' && name[l + 1] == '.' && name[l + 2] == '/' &&
465             (l == 0 || name[l - 1] == '/')) {
466             register int m = l + 3, n;
467
468             l = l - 2;
469             if (l >= 0) {
470                 while (l >= 0 && name[l] != '/')
471                     l--;
472                 l++;
473             }
474             else
475                 l = 0;
476             n = l;
477             while ((name[n] = name[m]))
478                 (++n, ++m);
479         }
480         else
481             ++l;
482     }
483
484     /* d) remove trailing xx/.. segment. */
485     if (l == 2 && name[0] == '.' && name[1] == '.')
486         name[0] = '\0';
487     else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.' && name[l - 3] == '/') {
488         l = l - 4;
489         if (l >= 0) {
490             while (l >= 0 && name[l] != '/')
491                 l--;
492             l++;
493         }
494         else
495             l = 0;
496         name[l] = '\0';
497     }
498 }
499
500 API_EXPORT(void) ap_no2slash(char *name)
501 {
502     char *d, *s;
503
504     s = d = name;
505
506 #ifdef WIN32
507     /* Check for UNC names.  Leave leading two slashes. */
508     if (s[0] == '/' && s[1] == '/')
509         *d++ = *s++;
510 #endif
511
512     while (*s) {
513         if ((*d++ = *s) == '/') {
514             do {
515                 ++s;
516             } while (*s == '/');
517         }
518         else {
519             ++s;
520         }
521     }
522     *d = '\0';
523 }
524
525
526 /*
527  * copy at most n leading directories of s into d
528  * d should be at least as large as s plus 1 extra byte
529  * assumes n > 0
530  * the return value is the ever useful pointer to the trailing \0 of d
531  *
532  * examples:
533  *    /a/b, 1  ==> /
534  *    /a/b, 2  ==> /a/
535  *    /a/b, 3  ==> /a/b/
536  *    /a/b, 4  ==> /a/b/
537  */
538 API_EXPORT(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
539 {
540     for (;;) {
541         if (*s == '\0' || (*s == '/' && (--n) == 0)) {
542             *d = '/';
543             break;
544         }
545         *d++ = *s++;
546     }
547     *++d = 0;
548     return (d);
549 }
550
551
552 /*
553  * return the parent directory name including trailing / of the file s
554  */
555 API_EXPORT(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s)
556 {
557     const char *last_slash = ap_strrchr_c(s, '/');
558     char *d;
559     int l;
560
561     if (last_slash == NULL) {
562         /* XXX: well this is really broken if this happens */
563         return (apr_pstrdup(p, "/"));
564     }
565     l = (last_slash - s) + 1;
566     d = apr_palloc(p, l + 1);
567     memcpy(d, s, l);
568     d[l] = 0;
569     return (d);
570 }
571
572
573 API_EXPORT(int) ap_count_dirs(const char *path)
574 {
575     register int x, n;
576
577     for (x = 0, n = 0; path[x]; x++)
578         if (path[x] == '/')
579             n++;
580     return n;
581 }
582
583
584 API_EXPORT(void) ap_chdir_file(const char *file)
585 {
586     const char *x;
587     char buf[HUGE_STRING_LEN];
588
589     x = ap_strrchr_c(file, '/');
590     if (x == NULL) {
591         chdir(file);
592     }
593     else if (x - file < sizeof(buf) - 1) {
594         memcpy(buf, file, x - file);
595         buf[x - file] = '\0';
596         chdir(buf);
597     }
598     /* XXX: well, this is a silly function, no method of reporting an
599      * error... ah well. */
600 }
601
602 API_EXPORT(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop)
603 {
604     return ap_getword(atrans, (const char **) line, stop);
605 }
606
607 API_EXPORT(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop)
608 {
609     const char *pos = ap_strchr_c(*line, stop);
610     char *res;
611
612     if (!pos) {
613         res = apr_pstrdup(atrans, *line);
614         *line += strlen(*line);
615         return res;
616     }
617
618     res = apr_pstrndup(atrans, *line, pos - *line);
619
620     while (*pos == stop) {
621         ++pos;
622     }
623
624     *line = pos;
625
626     return res;
627 }
628
629 API_EXPORT(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
630 {
631     return ap_getword_white(atrans, (const char **) line);
632 }
633
634 API_EXPORT(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
635 {
636     int pos = -1, x;
637     char *res;
638
639     for (x = 0; (*line)[x]; x++) {
640         if (apr_isspace((*line)[x])) {
641             pos = x;
642             break;
643         }
644     }
645
646     if (pos == -1) {
647         res = apr_pstrdup(atrans, *line);
648         *line += strlen(*line);
649         return res;
650     }
651
652     res = apr_palloc(atrans, pos + 1);
653     apr_cpystrn(res, *line, pos + 1);
654
655     while (apr_isspace((*line)[pos]))
656         ++pos;
657
658     *line += pos;
659
660     return res;
661 }
662
663 API_EXPORT(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line, char stop)
664 {
665     return ap_getword_nulls(atrans, (const char **) line, stop);
666 }
667
668 API_EXPORT(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line, char stop)
669 {
670     const char *pos = ap_strchr_c(*line, stop);
671     char *res;
672
673     if (!pos) {
674         res = apr_pstrdup(atrans, *line);
675         *line += strlen(*line);
676         return res;
677     }
678
679     res = apr_pstrndup(atrans, *line, pos - *line);
680
681     ++pos;
682
683     *line = pos;
684
685     return res;
686 }
687
688 /* Get a word, (new) config-file style --- quoted strings and backslashes
689  * all honored
690  */
691
692 static char *substring_conf(apr_pool_t *p, const char *start, int len, char quote)
693 {
694     char *result = apr_palloc(p, len + 2);
695     char *resp = result;
696     int i;
697
698     for (i = 0; i < len; ++i) {
699         if (start[i] == '\\' && (start[i + 1] == '\\'
700                                  || (quote && start[i + 1] == quote)))
701             *resp++ = start[++i];
702         else
703             *resp++ = start[i];
704     }
705
706     *resp++ = '\0';
707 #if RESOLVE_ENV_PER_TOKEN
708     return ap_resolve_env(p,result);
709 #else
710     return result;
711 #endif
712 }
713
714 API_EXPORT(char *) ap_getword_conf_nc(apr_pool_t *p, char **line)
715 {
716     return ap_getword_conf(p, (const char **) line);
717 }
718
719 API_EXPORT(char *) ap_getword_conf(apr_pool_t *p, const char **line)
720 {
721     const char *str = *line, *strend;
722     char *res;
723     char quote;
724
725     while (*str && apr_isspace(*str))
726         ++str;
727
728     if (!*str) {
729         *line = str;
730         return "";
731     }
732
733     if ((quote = *str) == '"' || quote == '\'') {
734         strend = str + 1;
735         while (*strend && *strend != quote) {
736             if (*strend == '\\' && strend[1] && strend[1] == quote)
737                 strend += 2;
738             else
739                 ++strend;
740         }
741         res = substring_conf(p, str + 1, strend - str - 1, quote);
742
743         if (*strend == quote)
744             ++strend;
745     }
746     else {
747         strend = str;
748         while (*strend && !apr_isspace(*strend))
749             ++strend;
750
751         res = substring_conf(p, str, strend - str, 0);
752     }
753
754     while (*strend && apr_isspace(*strend))
755         ++strend;
756     *line = strend;
757     return res;
758 }
759
760 /* Check a string for any ${ENV} environment variable
761  * construct and replace each them by the value of
762  * that environment variable, if it exists. If the
763  * environment value does not exist, leave the ${ENV}
764  * construct alone; it means something else.
765  */
766 API_EXPORT(const char *) ap_resolve_env(apr_pool_t *p, const char * word)
767 {
768        char tmp[ MAX_STRING_LEN ];
769        const char *s, *e;
770        tmp[0] = '\0';
771
772        if (!(s=ap_strchr_c(word,'$')))
773                return word;
774
775        do {
776                /* XXX - relies on strncat() to add '\0'
777                 */
778                strncat(tmp,word,s - word);
779                if ((s[1] == '{') && (e=ap_strchr_c(s,'}'))) {
780                        const char *e2 = e;
781                        word = e + 1;
782                        e = getenv(s+2);
783                        if (e) {
784                            strcat(tmp,e);
785                        } else {
786                            strncat(tmp, s, e2-s);
787                            strcat(tmp,"}");
788                        }
789                } else {
790                        /* ignore invalid strings */
791                        word = s+1;
792                        strcat(tmp,"$");
793                };
794        } while ((s=ap_strchr_c(word,'$')));
795        strcat(tmp,word);
796
797        return apr_pstrdup(p,tmp);
798 }
799 API_EXPORT(int) ap_cfg_closefile(configfile_t *cfp)
800 {
801 #ifdef DEBUG
802     ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, 
803         "Done with config file %s", cfp->name);
804 #endif
805     return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
806 }
807
808 static apr_status_t cfg_close(void *param)
809 {
810     apr_file_t *cfp = (apr_file_t *) param;
811     return (apr_close(cfp));
812 }
813
814 static int cfg_getch(void *param)
815 {
816     char ch;
817     apr_file_t *cfp = (apr_file_t *) param;
818     if (apr_getc(&ch, cfp) == APR_SUCCESS)
819         return ch;
820     return (int)EOF;
821 }
822
823 static void *cfg_getstr(void *buf, size_t bufsiz, void *param)
824 {
825     apr_file_t *cfp = (apr_file_t *) param;
826     if (apr_fgets(buf, bufsiz, cfp) == APR_SUCCESS)
827         return buf;
828     return NULL;
829 }
830
831 /* Open a configfile_t as FILE, return open configfile_t struct pointer */
832 API_EXPORT(apr_status_t) ap_pcfg_openfile(configfile_t **ret_cfg, apr_pool_t *p, const char *name)
833 {
834     configfile_t *new_cfg;
835     apr_file_t *file = NULL;
836     apr_finfo_t finfo;
837     apr_status_t status;
838 #ifdef DEBUG
839     char buf[120];
840 #endif
841
842     if (name == NULL) {
843         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL,
844                "Internal error: pcfg_openfile() called with NULL filename");
845         return APR_EBADF;
846     }
847
848     if (!ap_os_is_filename_valid(name)) {
849         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL,
850                     "Access to config file %s denied: not a valid filename",
851                     name);
852         return APR_EACCES;
853     }
854
855     status = apr_open(&file, name, APR_READ | APR_BUFFERED, APR_OS_DEFAULT, p);
856 #ifdef DEBUG
857     ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, NULL,
858                 "Opening config file %s (%s)",
859                 name, (status != APR_SUCCESS) ? 
860                 apr_strerror(status, buf, sizeof(buf)) : "successful");
861 #endif
862     if (status != APR_SUCCESS)
863         return status;
864
865     status = apr_getfileinfo(&finfo, file);
866     if (status != APR_SUCCESS)
867         return status;
868
869     if (finfo.filetype != APR_REG &&
870 #if defined(WIN32) || defined(OS2)
871         !(strcasecmp(name, "nul") == 0 ||
872           (strlen(name) >= 4 &&
873            strcasecmp(name + strlen(name) - 4, "/nul") == 0))) {
874 #else
875         strcmp(name, "/dev/null") != 0) {
876 #endif /* WIN32 || OS2 */
877         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL,
878                     "Access to file %s denied by server: not a regular file",
879                     name);
880         apr_close(file);
881         return APR_EBADF;
882     }
883
884     new_cfg = apr_palloc(p, sizeof(*new_cfg));
885     new_cfg->param = file;
886     new_cfg->name = apr_pstrdup(p, name);
887     new_cfg->getch = (int (*)(void *)) cfg_getch;
888     new_cfg->getstr = (void *(*)(void *, size_t, void *)) cfg_getstr;
889     new_cfg->close = (int (*)(void *)) cfg_close;
890     new_cfg->line_number = 0;
891     *ret_cfg = new_cfg;
892     return APR_SUCCESS;
893 }
894
895
896 /* Allocate a configfile_t handle with user defined functions and params */
897 API_EXPORT(configfile_t *) ap_pcfg_open_custom(apr_pool_t *p, const char *descr,
898     void *param,
899     int(*getch)(void *param),
900     void *(*getstr) (void *buf, size_t bufsiz, void *param),
901     int(*close_func)(void *param))
902 {
903     configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg));
904 #ifdef DEBUG
905     ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, NULL, "Opening config handler %s", descr);
906 #endif
907     new_cfg->param = param;
908     new_cfg->name = descr;
909     new_cfg->getch = getch;
910     new_cfg->getstr = getstr;
911     new_cfg->close = close_func;
912     new_cfg->line_number = 0;
913     return new_cfg;
914 }
915
916
917 /* Read one character from a configfile_t */
918 API_EXPORT(int) ap_cfg_getc(configfile_t *cfp)
919 {
920     register int ch = cfp->getch(cfp->param);
921     if (ch == LF) 
922         ++cfp->line_number;
923     return ch;
924 }
925
926
927 /* Read one line from open configfile_t, strip LF, increase line number */
928 /* If custom handler does not define a getstr() function, read char by char */
929 API_EXPORT(int) ap_cfg_getline(char *buf, size_t bufsize, configfile_t *cfp)
930 {
931     /* If a "get string" function is defined, use it */
932     if (cfp->getstr != NULL) {
933         char *src, *dst;
934         char *cp;
935         char *cbuf = buf;
936         size_t cbufsize = bufsize;
937
938         while (1) {
939             ++cfp->line_number;
940             if (cfp->getstr(cbuf, cbufsize, cfp->param) == NULL)
941                 return 1;
942
943             /*
944              *  check for line continuation,
945              *  i.e. match [^\\]\\[\r]\n only
946              */
947             cp = cbuf;
948             while (cp < cbuf+cbufsize && *cp != '\0')
949                 cp++;
950             if (cp > cbuf && cp[-1] == LF) {
951                 cp--;
952                 if (cp > cbuf && cp[-1] == CR)
953                     cp--;
954                 if (cp > cbuf && cp[-1] == '\\') {
955                     cp--;
956                     if (!(cp > cbuf && cp[-1] == '\\')) {
957                         /*
958                          * line continuation requested -
959                          * then remove backslash and continue
960                          */
961                         cbufsize -= (cp-cbuf);
962                         cbuf = cp;
963                         continue;
964                     }
965                     else {
966                         /* 
967                          * no real continuation because escaped -
968                          * then just remove escape character
969                          */
970                         for ( ; cp < cbuf+cbufsize && *cp != '\0'; cp++)
971                             cp[0] = cp[1];
972                     }   
973                 }
974             }
975             break;
976         }
977
978         /*
979          * Leading and trailing white space is eliminated completely
980          */
981         src = buf;
982         while (apr_isspace(*src))
983             ++src;
984         /* blast trailing whitespace */
985         dst = &src[strlen(src)];
986         while (--dst >= src && apr_isspace(*dst))
987             *dst = '\0';
988         /* Zap leading whitespace by shifting */
989         if (src != buf)
990             for (dst = buf; (*dst++ = *src++) != '\0'; )
991                 ;
992
993 #ifdef DEBUG_CFG_LINES
994         ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Read config: %s", buf);
995 #endif
996         return 0;
997     } else {
998         /* No "get string" function defined; read character by character */
999         register int c;
1000         register size_t i = 0;
1001
1002         buf[0] = '\0';
1003         /* skip leading whitespace */
1004         do {
1005             c = cfp->getch(cfp->param);
1006         } while (c == '\t' || c == ' ');
1007
1008         if (c == EOF)
1009             return 1;
1010         
1011         if(bufsize < 2) {
1012             /* too small, assume caller is crazy */
1013             return 1;
1014         }
1015
1016         while (1) {
1017             if ((c == '\t') || (c == ' ')) {
1018                 buf[i++] = ' ';
1019                 while ((c == '\t') || (c == ' '))
1020                     c = cfp->getch(cfp->param);
1021             }
1022             if (c == CR) {
1023                 /* silently ignore CR (_assume_ that a LF follows) */
1024                 c = cfp->getch(cfp->param);
1025             }
1026             if (c == LF) {
1027                 /* increase line number and return on LF */
1028                 ++cfp->line_number;
1029             }
1030             if (c == EOF || c == 0x4 || c == LF || i >= (bufsize - 2)) {
1031                 /* 
1032                  *  check for line continuation
1033                  */
1034                 if (i > 0 && buf[i-1] == '\\') {
1035                     i--;
1036                     if (!(i > 0 && buf[i-1] == '\\')) {
1037                         /* line is continued */
1038                         c = cfp->getch(cfp->param);
1039                         continue;
1040                     }
1041                     /* else nothing needs be done because
1042                      * then the backslash is escaped and
1043                      * we just strip to a single one
1044                      */
1045                 }
1046                 /* blast trailing whitespace */
1047                 while (i > 0 && apr_isspace(buf[i - 1]))
1048                     --i;
1049                 buf[i] = '\0';
1050 #ifdef DEBUG_CFG_LINES
1051                 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Read config: %s", buf);
1052 #endif
1053                 return 0;
1054             }
1055             buf[i] = c;
1056             ++i;
1057             c = cfp->getch(cfp->param);
1058         }
1059     }
1060 }
1061
1062 /* Size an HTTP header field list item, as separated by a comma.
1063  * The return value is a pointer to the beginning of the non-empty list item
1064  * within the original string (or NULL if there is none) and the address
1065  * of field is shifted to the next non-comma, non-whitespace character.
1066  * len is the length of the item excluding any beginning whitespace.
1067  */
1068 API_EXPORT(const char *) ap_size_list_item(const char **field, int *len)
1069 {
1070     const unsigned char *ptr = (const unsigned char *)*field;
1071     const unsigned char *token;
1072     int in_qpair, in_qstr, in_com;
1073
1074     /* Find first non-comma, non-whitespace byte */
1075
1076     while (*ptr == ',' || apr_isspace(*ptr))
1077         ++ptr;
1078
1079     token = ptr;
1080
1081     /* Find the end of this item, skipping over dead bits */
1082
1083     for (in_qpair = in_qstr = in_com = 0;
1084          *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1085          ++ptr) {
1086
1087         if (in_qpair) {
1088             in_qpair = 0;
1089         }
1090         else {
1091             switch (*ptr) {
1092                 case '\\': in_qpair = 1;      /* quoted-pair         */
1093                            break;
1094                 case '"' : if (!in_com)       /* quoted string delim */
1095                                in_qstr = !in_qstr;
1096                            break;
1097                 case '(' : if (!in_qstr)      /* comment (may nest)  */
1098                                ++in_com;
1099                            break;
1100                 case ')' : if (in_com)        /* end comment         */
1101                                --in_com;
1102                            break;
1103                 default  : break;
1104             }
1105         }
1106     }
1107
1108     if ((*len = (ptr - token)) == 0) {
1109         *field = (const char *)ptr;
1110         return NULL;
1111     }
1112
1113     /* Advance field pointer to the next non-comma, non-white byte */
1114
1115     while (*ptr == ',' || apr_isspace(*ptr))
1116         ++ptr;
1117
1118     *field = (const char *)ptr;
1119     return (const char *)token;
1120 }
1121
1122 /* Retrieve an HTTP header field list item, as separated by a comma,
1123  * while stripping insignificant whitespace and lowercasing anything not in
1124  * a quoted string or comment.  The return value is a new string containing
1125  * the converted list item (or NULL if none) and the address pointed to by
1126  * field is shifted to the next non-comma, non-whitespace.
1127  */
1128 API_EXPORT(char *) ap_get_list_item(apr_pool_t *p, const char **field)
1129 {
1130     const char *tok_start;
1131     const unsigned char *ptr;
1132     unsigned char *pos;
1133     char *token;
1134     int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
1135
1136     /* Find the beginning and maximum length of the list item so that
1137      * we can allocate a buffer for the new string and reset the field.
1138      */
1139     if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
1140         return NULL;
1141     }
1142     token = apr_palloc(p, tok_len + 1);
1143
1144     /* Scan the token again, but this time copy only the good bytes.
1145      * We skip extra whitespace and any whitespace around a '=', '/',
1146      * or ';' and lowercase normal characters not within a comment,
1147      * quoted-string or quoted-pair.
1148      */
1149     for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
1150          *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1151          ++ptr) {
1152
1153         if (in_qpair) {
1154             in_qpair = 0;
1155             *pos++ = *ptr;
1156         }
1157         else {
1158             switch (*ptr) {
1159                 case '\\': in_qpair = 1;
1160                            if (addspace == 1)
1161                                *pos++ = ' ';
1162                            *pos++ = *ptr;
1163                            addspace = 0;
1164                            break;
1165                 case '"' : if (!in_com)
1166                                in_qstr = !in_qstr;
1167                            if (addspace == 1)
1168                                *pos++ = ' ';
1169                            *pos++ = *ptr;
1170                            addspace = 0;
1171                            break;
1172                 case '(' : if (!in_qstr)
1173                                ++in_com;
1174                            if (addspace == 1)
1175                                *pos++ = ' ';
1176                            *pos++ = *ptr;
1177                            addspace = 0;
1178                            break;
1179                 case ')' : if (in_com)
1180                                --in_com;
1181                            *pos++ = *ptr;
1182                            addspace = 0;
1183                            break;
1184                 case ' ' :
1185                 case '\t': if (addspace)
1186                                break;
1187                            if (in_com || in_qstr)
1188                                *pos++ = *ptr;
1189                            else
1190                                addspace = 1;
1191                            break;
1192                 case '=' :
1193                 case '/' :
1194                 case ';' : if (!(in_com || in_qstr))
1195                                addspace = -1;
1196                            *pos++ = *ptr;
1197                            break;
1198                 default  : if (addspace == 1)
1199                                *pos++ = ' ';
1200                            *pos++ = (in_com || in_qstr) ? *ptr
1201                                                         : apr_tolower(*ptr);
1202                            addspace = 0;
1203                            break;
1204             }
1205         }
1206     }
1207     *pos = '\0';
1208
1209     return token;
1210 }
1211
1212 /* Find an item in canonical form (lowercase, no extra spaces) within
1213  * an HTTP field value list.  Returns 1 if found, 0 if not found.
1214  * This would be much more efficient if we stored header fields as
1215  * an array of list items as they are received instead of a plain string.
1216  */
1217 API_EXPORT(int) ap_find_list_item(apr_pool_t *p, const char *line, const char *tok)
1218 {
1219     const unsigned char *pos;
1220     const unsigned char *ptr = (const unsigned char *)line;
1221     int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
1222
1223     if (!line || !tok)
1224         return 0;
1225
1226     do {  /* loop for each item in line's list */
1227
1228         /* Find first non-comma, non-whitespace byte */
1229
1230         while (*ptr == ',' || apr_isspace(*ptr))
1231             ++ptr;
1232
1233         if (*ptr)
1234             good = 1;  /* until proven otherwise for this item */
1235         else
1236             break;     /* no items left and nothing good found */
1237
1238         /* We skip extra whitespace and any whitespace around a '=', '/',
1239          * or ';' and lowercase normal characters not within a comment,
1240          * quoted-string or quoted-pair.
1241          */
1242         for (pos = (const unsigned char *)tok;
1243              *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1244              ++ptr) {
1245
1246             if (in_qpair) {
1247                 in_qpair = 0;
1248                 if (good)
1249                     good = (*pos++ == *ptr);
1250             }
1251             else {
1252                 switch (*ptr) {
1253                     case '\\': in_qpair = 1;
1254                                if (addspace == 1)
1255                                    good = good && (*pos++ == ' ');
1256                                good = good && (*pos++ == *ptr);
1257                                addspace = 0;
1258                                break;
1259                     case '"' : if (!in_com)
1260                                    in_qstr = !in_qstr;
1261                                if (addspace == 1)
1262                                    good = good && (*pos++ == ' ');
1263                                good = good && (*pos++ == *ptr);
1264                                addspace = 0;
1265                                break;
1266                     case '(' : if (!in_qstr)
1267                                    ++in_com;
1268                                if (addspace == 1)
1269                                    good = good && (*pos++ == ' ');
1270                                good = good && (*pos++ == *ptr);
1271                                addspace = 0;
1272                                break;
1273                     case ')' : if (in_com)
1274                                    --in_com;
1275                                good = good && (*pos++ == *ptr);
1276                                addspace = 0;
1277                                break;
1278                     case ' ' :
1279                     case '\t': if (addspace || !good)
1280                                    break;
1281                                if (in_com || in_qstr)
1282                                    good = (*pos++ == *ptr);
1283                                else
1284                                    addspace = 1;
1285                                break;
1286                     case '=' :
1287                     case '/' :
1288                     case ';' : if (!(in_com || in_qstr))
1289                                    addspace = -1;
1290                                good = good && (*pos++ == *ptr);
1291                                break;
1292                     default  : if (!good)
1293                                    break;
1294                                if (addspace == 1)
1295                                    good = (*pos++ == ' ');
1296                                if (in_com || in_qstr)
1297                                    good = good && (*pos++ == *ptr);
1298                                else
1299                                    good = good && (*pos++ == apr_tolower(*ptr));
1300                                addspace = 0;
1301                                break;
1302                 }
1303             }
1304         }
1305         if (good && *pos)
1306             good = 0;          /* not good if only a prefix was matched */
1307
1308     } while (*ptr && !good);
1309
1310     return good;
1311 }
1312
1313
1314 /* Retrieve a token, spacing over it and returning a pointer to
1315  * the first non-white byte afterwards.  Note that these tokens
1316  * are delimited by semis and commas; and can also be delimited
1317  * by whitespace at the caller's option.
1318  */
1319
1320 API_EXPORT(char *) ap_get_token(apr_pool_t *p, const char **accept_line, int accept_white)
1321 {
1322     const char *ptr = *accept_line;
1323     const char *tok_start;
1324     char *token;
1325     int tok_len;
1326
1327     /* Find first non-white byte */
1328
1329     while (*ptr && apr_isspace(*ptr))
1330         ++ptr;
1331
1332     tok_start = ptr;
1333
1334     /* find token end, skipping over quoted strings.
1335      * (comments are already gone).
1336      */
1337
1338     while (*ptr && (accept_white || !apr_isspace(*ptr))
1339            && *ptr != ';' && *ptr != ',') {
1340         if (*ptr++ == '"')
1341             while (*ptr)
1342                 if (*ptr++ == '"')
1343                     break;
1344     }
1345
1346     tok_len = ptr - tok_start;
1347     token = apr_pstrndup(p, tok_start, tok_len);
1348
1349     /* Advance accept_line pointer to the next non-white byte */
1350
1351     while (*ptr && apr_isspace(*ptr))
1352         ++ptr;
1353
1354     *accept_line = ptr;
1355     return token;
1356 }
1357
1358
1359 /* find http tokens, see the definition of token from RFC2068 */
1360 API_EXPORT(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1361 {
1362     const unsigned char *start_token;
1363     const unsigned char *s;
1364
1365     if (!line)
1366         return 0;
1367
1368     s = (const unsigned char *)line;
1369     for (;;) {
1370         /* find start of token, skip all stop characters, note NUL
1371          * isn't a token stop, so we don't need to test for it
1372          */
1373         while (TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1374             ++s;
1375         }
1376         if (!*s) {
1377             return 0;
1378         }
1379         start_token = s;
1380         /* find end of the token */
1381         while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1382             ++s;
1383         }
1384         if (!strncasecmp((const char *)start_token, (const char *)tok, s - start_token)) {
1385             return 1;
1386         }
1387         if (!*s) {
1388             return 0;
1389         }
1390     }
1391 }
1392
1393
1394 API_EXPORT(int) ap_find_last_token(apr_pool_t *p, const char *line, const char *tok)
1395 {
1396     int llen, tlen, lidx;
1397
1398     if (!line)
1399         return 0;
1400
1401     llen = strlen(line);
1402     tlen = strlen(tok);
1403     lidx = llen - tlen;
1404
1405     if ((lidx < 0) ||
1406         ((lidx > 0) && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1407         return 0;
1408
1409     return (strncasecmp(&line[lidx], tok, tlen) == 0);
1410 }
1411
1412 API_EXPORT(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1413 {
1414     char *cmd;
1415     unsigned char *d;
1416     const unsigned char *s;
1417
1418     cmd = apr_palloc(p, 2 * strlen(str) + 1);   /* Be safe */
1419     d = (unsigned char *)cmd;
1420     s = (const unsigned char *)str;
1421     for (; *s; ++s) {
1422
1423 #if defined(OS2) || defined(WIN32)
1424         /* Don't allow '&' in parameters under OS/2. */
1425         /* This can be used to send commands to the shell. */
1426         if (*s == '&') {
1427             *d++ = ' ';
1428             continue;
1429         }
1430 #endif
1431
1432         if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1433             *d++ = '\\';
1434         }
1435         *d++ = *s;
1436     }
1437     *d = '\0';
1438
1439     return cmd;
1440 }
1441
1442 static char x2c(const char *what)
1443 {
1444     register char digit;
1445
1446 #ifndef CHARSET_EBCDIC
1447     digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
1448     digit *= 16;
1449     digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
1450 #else /*CHARSET_EBCDIC*/
1451     char xstr[5];
1452     xstr[0]='0';
1453     xstr[1]='x';
1454     xstr[2]=what[0];
1455     xstr[3]=what[1];
1456     xstr[4]='\0';
1457     digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFF & strtol(xstr, NULL, 16));
1458 #endif /*CHARSET_EBCDIC*/
1459     return (digit);
1460 }
1461
1462 /*
1463  * Unescapes a URL.
1464  * Returns 0 on success, non-zero on error
1465  * Failure is due to
1466  *   bad % escape       returns HTTP_BAD_REQUEST
1467  *
1468  *   decoding %00 -> \0
1469  *   decoding %2f -> /   (a special character)
1470  *                      returns HTTP_NOT_FOUND
1471  */
1472 API_EXPORT(int) ap_unescape_url(char *url)
1473 {
1474     register int badesc, badpath;
1475     char *x, *y;
1476
1477     badesc = 0;
1478     badpath = 0;
1479     /* Initial scan for first '%'. Don't bother writing values before
1480      * seeing a '%' */
1481     y = strchr(url, '%');
1482     if (y == NULL) {
1483         return OK;
1484     }
1485     for (x = y; *y; ++x, ++y) {
1486         if (*y != '%')
1487             *x = *y;
1488         else {
1489             if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1490                 badesc = 1;
1491                 *x = '%';
1492             }
1493             else {
1494                 *x = x2c(y + 1);
1495                 y += 2;
1496                 if (*x == '/' || *x == '\0')
1497                     badpath = 1;
1498             }
1499         }
1500     }
1501     *x = '\0';
1502     if (badesc)
1503         return HTTP_BAD_REQUEST;
1504     else if (badpath)
1505         return HTTP_NOT_FOUND;
1506     else
1507         return OK;
1508 }
1509
1510 API_EXPORT(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
1511                                     unsigned port, const request_rec *r)
1512 {
1513     if (ap_is_default_port(port, r))
1514         return apr_pstrdup(p, hostname);
1515     else {
1516         return apr_psprintf(p, "%s:%u", hostname, port);
1517     }
1518 }
1519
1520 /* c2x takes an unsigned, and expects the caller has guaranteed that
1521  * 0 <= what < 256... which usually means that you have to cast to
1522  * unsigned char first, because (unsigned)(char)(x) first goes through
1523  * signed extension to an int before the unsigned cast.
1524  *
1525  * The reason for this assumption is to assist gcc code generation --
1526  * the unsigned char -> unsigned extension is already done earlier in
1527  * both uses of this code, so there's no need to waste time doing it
1528  * again.
1529  */
1530 static const char c2x_table[] = "0123456789abcdef";
1531
1532 static apr_inline unsigned char *c2x(unsigned what, unsigned char *where)
1533 {
1534 #ifdef CHARSET_EBCDIC
1535     what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
1536 #endif /*CHARSET_EBCDIC*/
1537     *where++ = '%';
1538     *where++ = c2x_table[what >> 4];
1539     *where++ = c2x_table[what & 0xf];
1540     return where;
1541 }
1542
1543 /*
1544  * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
1545  * routine is (should be) OS independent.
1546  *
1547  * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
1548  * cases if a ':' occurs before the first '/' in the URL, the URL should be
1549  * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
1550  * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
1551  * efficiency reasons, we don't use escape_path_segment(), which is provided for
1552  * reference. Again, RFC 1808 is where this stuff is defined.
1553  *
1554  * If partial is set, os_escape_path() assumes that the path will be appended to
1555  * something with a '/' in it (and thus does not prefix "./").
1556  */
1557
1558 API_EXPORT(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
1559 {
1560     char *copy = apr_palloc(p, 3 * strlen(segment) + 1);
1561     const unsigned char *s = (const unsigned char *)segment;
1562     unsigned char *d = (unsigned char *)copy;
1563     unsigned c;
1564
1565     while ((c = *s)) {
1566         if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
1567             d = c2x(c, d);
1568         }
1569         else {
1570             *d++ = c;
1571         }
1572         ++s;
1573     }
1574     *d = '\0';
1575     return copy;
1576 }
1577
1578 API_EXPORT(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
1579 {
1580     char *copy = apr_palloc(p, 3 * strlen(path) + 3);
1581     const unsigned char *s = (const unsigned char *)path;
1582     unsigned char *d = (unsigned char *)copy;
1583     unsigned c;
1584
1585     if (!partial) {
1586         const char *colon = ap_strchr_c(path, ':');
1587         const char *slash = ap_strchr_c(path, '/');
1588
1589         if (colon && (!slash || colon < slash)) {
1590             *d++ = '.';
1591             *d++ = '/';
1592         }
1593     }
1594     while ((c = *s)) {
1595         if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
1596             d = c2x(c, d);
1597         }
1598         else {
1599             *d++ = c;
1600         }
1601         ++s;
1602     }
1603     *d = '\0';
1604     return copy;
1605 }
1606
1607 /* ap_escape_uri is now a macro for os_escape_path */
1608
1609 API_EXPORT(char *) ap_escape_html(apr_pool_t *p, const char *s)
1610 {
1611     int i, j;
1612     char *x;
1613
1614     /* first, count the number of extra characters */
1615     for (i = 0, j = 0; s[i] != '\0'; i++)
1616         if (s[i] == '<' || s[i] == '>')
1617             j += 3;
1618         else if (s[i] == '&')
1619             j += 4;
1620
1621     if (j == 0)
1622         return apr_pstrndup(p, s, i);
1623
1624     x = apr_palloc(p, i + j + 1);
1625     for (i = 0, j = 0; s[i] != '\0'; i++, j++)
1626         if (s[i] == '<') {
1627             memcpy(&x[j], "&lt;", 4);
1628             j += 3;
1629         }
1630         else if (s[i] == '>') {
1631             memcpy(&x[j], "&gt;", 4);
1632             j += 3;
1633         }
1634         else if (s[i] == '&') {
1635             memcpy(&x[j], "&amp;", 5);
1636             j += 4;
1637         }
1638         else
1639             x[j] = s[i];
1640
1641     x[j] = '\0';
1642     return x;
1643 }
1644
1645 API_EXPORT(int) ap_is_directory(const char *path)
1646 {
1647     apr_finfo_t finfo;
1648
1649     if (apr_stat(&finfo, path, NULL) == -1)
1650         return 0;               /* in error condition, just return no */
1651
1652     return (finfo.filetype == APR_DIR);
1653 }
1654
1655 API_EXPORT(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
1656                                   const char *src2)
1657 {
1658     register int x;
1659
1660     x = strlen(src1);
1661     if (x == 0)
1662         return apr_pstrcat(a, "/", src2, NULL);
1663
1664     if (src1[x - 1] != '/')
1665         return apr_pstrcat(a, src1, "/", src2, NULL);
1666     else
1667         return apr_pstrcat(a, src1, src2, NULL);
1668 }
1669
1670 /*
1671  * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
1672  */
1673 API_EXPORT(int) ap_is_url(const char *u)
1674 {
1675     register int x;
1676
1677     for (x = 0; u[x] != ':'; x++) {
1678         if ((!u[x]) ||
1679             ((!apr_isalpha(u[x])) && (!apr_isdigit(u[x])) &&
1680              (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
1681             return 0;
1682         }
1683     }
1684
1685     return (x ? 1 : 0);         /* If the first character is ':', it's broken, too */
1686 }
1687
1688 #ifndef HAVE_INITGROUPS
1689 int initgroups(const char *name, gid_t basegid)
1690 {
1691 #if defined(QNX) || defined(MPE) || defined(BEOS) || defined(_OSD_POSIX) || defined(TPF) || defined(__TANDEM) || defined(OS2) || defined(WIN32)
1692 /* QNX, MPE and BeOS do not appear to support supplementary groups. */
1693     return 0;
1694 #else /* ndef QNX */
1695     gid_t groups[NGROUPS_MAX];
1696     struct group *g;
1697     int index = 0;
1698
1699     setgrent();
1700
1701     groups[index++] = basegid;
1702
1703     while (index < NGROUPS_MAX && ((g = getgrent()) != NULL))
1704         if (g->gr_gid != basegid) {
1705             char **names;
1706
1707             for (names = g->gr_mem; *names != NULL; ++names)
1708                 if (!strcmp(*names, name))
1709                     groups[index++] = g->gr_gid;
1710         }
1711
1712     endgrent();
1713
1714     return setgroups(index, groups);
1715 #endif /* def QNX */
1716 }
1717 #endif /* def NEED_INITGROUPS */
1718
1719 API_EXPORT(int) ap_ind(const char *s, char c)
1720 {
1721     register int x;
1722
1723     for (x = 0; s[x]; x++)
1724         if (s[x] == c)
1725             return x;
1726
1727     return -1;
1728 }
1729
1730 API_EXPORT(int) ap_rind(const char *s, char c)
1731 {
1732     register int x;
1733
1734     for (x = strlen(s) - 1; x != -1; x--)
1735         if (s[x] == c)
1736             return x;
1737
1738     return -1;
1739 }
1740
1741 API_EXPORT(void) ap_str_tolower(char *str)
1742 {
1743     while (*str) {
1744         *str = apr_tolower(*str);
1745         ++str;
1746     }
1747 }
1748
1749 API_EXPORT(uid_t) ap_uname2id(const char *name)
1750 {
1751 #ifdef WIN32
1752     return (1);
1753 #else
1754     struct passwd *ent;
1755
1756     if (name[0] == '#')
1757         return (atoi(&name[1]));
1758
1759     if (!(ent = getpwnam(name))) {
1760         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "%s: bad user name %s", ap_server_argv0, name);
1761         exit(1);
1762     }
1763     return (ent->pw_uid);
1764 #endif
1765 }
1766
1767 API_EXPORT(gid_t) ap_gname2id(const char *name)
1768 {
1769 #ifdef WIN32
1770     return (1);
1771 #else
1772     struct group *ent;
1773
1774     if (name[0] == '#')
1775         return (atoi(&name[1]));
1776
1777     if (!(ent = getgrnam(name))) {
1778         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "%s: bad group name %s", ap_server_argv0, name);
1779         exit(1);
1780     }
1781     return (ent->gr_gid);
1782 #endif
1783 }
1784
1785
1786 /*
1787  * Parses a host of the form <address>[:port]
1788  * :port is permitted if 'port' is not NULL
1789  */
1790 unsigned long ap_get_virthost_addr(char *w, unsigned short *ports)
1791 {
1792     struct hostent *hep;
1793     unsigned long my_addr;
1794     char *p;
1795
1796     p = strchr(w, ':');
1797     if (ports != NULL) {
1798         *ports = 0;
1799         if (p != NULL && strcmp(p + 1, "*") != 0)
1800             *ports = atoi(p + 1);
1801     }
1802
1803     if (p != NULL)
1804         *p = '\0';
1805     if (strcmp(w, "*") == 0) {
1806         if (p != NULL)
1807             *p = ':';
1808         return htonl(INADDR_ANY);
1809     }
1810
1811     my_addr = apr_inet_addr((char *)w);
1812     if (my_addr != INADDR_NONE) {
1813         if (p != NULL)
1814             *p = ':';
1815         return my_addr;
1816     }
1817
1818     hep = gethostbyname(w);
1819
1820     if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
1821         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Cannot resolve host name %s --- exiting!", w);
1822         exit(1);
1823     }
1824
1825     if (hep->h_addr_list[1]) {
1826         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Host %s has multiple addresses ---", w);
1827         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "you must choose one explicitly for use as");
1828         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "a virtual host.  Exiting!!!");
1829         exit(1);
1830     }
1831
1832     if (p != NULL)
1833         *p = ':';
1834
1835     return ((struct in_addr *) (hep->h_addr))->s_addr;
1836 }
1837
1838
1839 static char *find_fqdn(apr_pool_t *a, struct hostent *p)
1840 {
1841     int x;
1842
1843     if (!strchr(p->h_name, '.')) {
1844         for (x = 0; p->h_aliases[x]; ++x) {
1845             if (strchr(p->h_aliases[x], '.') &&
1846                 (!strncasecmp(p->h_aliases[x], p->h_name, strlen(p->h_name))))
1847                 return apr_pstrdup(a, p->h_aliases[x]);
1848         }
1849         return NULL;
1850     }
1851     return apr_pstrdup(a, (void *) p->h_name);
1852 }
1853
1854 char *ap_get_local_host(apr_pool_t *a)
1855 {
1856 #ifndef MAXHOSTNAMELEN
1857 #define MAXHOSTNAMELEN 256
1858 #endif
1859     char str[MAXHOSTNAMELEN + 1];
1860     char *server_hostname = NULL;
1861     struct hostent *p;
1862
1863 #ifdef BEOS
1864     if (gethostname(str, sizeof(str) - 1) == 0)
1865 #else
1866     if (gethostname(str, sizeof(str) - 1) != 0)
1867 #endif
1868     {
1869         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, NULL,
1870                      "%s: gethostname() failed to detemine ServerName",
1871                      ap_server_argv0);
1872     }
1873     else 
1874     {
1875         str[sizeof(str) - 1] = '\0';
1876         if ((!(p = gethostbyname(str))) 
1877             || (!(server_hostname = find_fqdn(a, p)))) {
1878             /* Recovery - return the default servername by IP: */
1879             if (!str && p->h_addr_list[0]) {
1880                 apr_snprintf(str, sizeof(str), "%pA", p->h_addr_list[0]);
1881                 server_hostname = apr_pstrdup(a, str);
1882                 /* We will drop through to report the IP-named server */
1883             }
1884         }
1885         else {
1886             /* Since we found a fdqn, return it with no logged message. */
1887             return server_hostname;
1888         }
1889     }
1890
1891     if (!server_hostname) 
1892         server_hostname = apr_pstrdup(a, "127.0.0.1");
1893
1894     ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, NULL,
1895                  "%s: Could not find determine the server's fully qualified "
1896                  "domain name, using %s for ServerName",
1897                  ap_server_argv0, server_hostname);
1898              
1899     return server_hostname;
1900 }
1901
1902 /* simple 'pool' alloc()ing glue to ap_base64.c
1903  */
1904 API_EXPORT(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
1905 {
1906     char *decoded;
1907     int l;
1908
1909     decoded = (char *) apr_palloc(p, 1 + ap_base64decode_len(bufcoded));
1910     l = ap_base64decode(decoded, bufcoded);
1911     decoded[l] = '\0'; /* make binary sequence into string */
1912
1913     return decoded;
1914 }
1915
1916 API_EXPORT(char *) ap_pbase64encode(apr_pool_t *p, char *string) 
1917
1918     char *encoded;
1919     int l = strlen(string);
1920
1921     encoded = (char *) apr_palloc(p, 1 + ap_base64encode_len(l));
1922     l = ap_base64encode(encoded, string, l);
1923     encoded[l] = '\0'; /* make binary sequence into string */
1924
1925     return encoded;
1926 }
1927
1928 /* deprecated names for the above two functions, here for compatibility
1929  */
1930 API_EXPORT(char *) ap_uudecode(apr_pool_t *p, const char *bufcoded)
1931 {
1932     return ap_pbase64decode(p, bufcoded);
1933 }
1934
1935 API_EXPORT(char *) ap_uuencode(apr_pool_t *p, char *string) 
1936
1937     return ap_pbase64encode(p, string);
1938 }
1939
1940 /* we want to downcase the type/subtype for comparison purposes
1941  * but nothing else because ;parameter=foo values are case sensitive.
1942  * XXX: in truth we want to downcase parameter names... but really,
1943  * apache has never handled parameters and such correctly.  You
1944  * also need to compress spaces and such to be able to compare
1945  * properly. -djg
1946  */
1947 API_EXPORT(void) ap_content_type_tolower(char *str)
1948 {
1949     char *semi;
1950
1951     semi = strchr(str, ';');
1952     if (semi) {
1953         *semi = '\0';
1954     }
1955     while (*str) {
1956         *str = apr_tolower(*str);
1957         ++str;
1958     }
1959     if (semi) {
1960         *semi = ';';
1961     }
1962 }
1963
1964 /*
1965  * Given a string, replace any bare " with \" .
1966  */
1967 API_EXPORT(char *) ap_escape_quotes (apr_pool_t *p, const char *instring)
1968 {
1969     int newlen = 0;
1970     const char *inchr = instring;
1971     char *outchr, *outstring;
1972
1973     /*
1974      * Look through the input string, jogging the length of the output
1975      * string up by an extra byte each time we find an unescaped ".
1976      */
1977     while (*inchr != '\0') {
1978         newlen++;
1979         if (*inchr == '"') {
1980             newlen++;
1981         }
1982         /*
1983          * If we find a slosh, and it's not the last byte in the string,
1984          * it's escaping something - advance past both bytes.
1985          */
1986         if ((*inchr == '\\') && (inchr[1] != '\0')) {
1987             inchr++;
1988             newlen++;
1989         }
1990         inchr++;
1991     }
1992     outstring = apr_palloc(p, newlen + 1);
1993     inchr = instring;
1994     outchr = outstring;
1995     /*
1996      * Now copy the input string to the output string, inserting a slosh
1997      * in front of every " that doesn't already have one.
1998      */
1999     while (*inchr != '\0') {
2000         if ((*inchr == '\\') && (inchr[1] != '\0')) {
2001             *outchr++ = *inchr++;
2002             *outchr++ = *inchr++;
2003         }
2004         if (*inchr == '"') {
2005             *outchr++ = '\\';
2006         }
2007         if (*inchr != '\0') {
2008             *outchr++ = *inchr++;
2009         }
2010     }
2011     *outchr = '\0';
2012     return outstring;
2013 }