1 /* $MirOS: src/usr.sbin/httpd/src/main/http_core.c,v 1.7 2008/12/03 11:22:59 tg Exp $ */
2 /* $OpenBSD: http_core.c,v 1.22 2007/08/24 11:31:29 mbalmer Exp $ */
3 
4 /* ====================================================================
5  * The Apache Software License, Version 1.1
6  *
7  * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
8  * reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  *
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in
19  *    the documentation and/or other materials provided with the
20  *    distribution.
21  *
22  * 3. The end-user documentation included with the redistribution,
23  *    if any, must include the following acknowledgment:
24  *       "This product includes software developed by the
25  *        Apache Software Foundation (http://www.apache.org/)."
26  *    Alternately, this acknowledgment may appear in the software itself,
27  *    if and wherever such third-party acknowledgments normally appear.
28  *
29  * 4. The names "Apache" and "Apache Software Foundation" must
30  *    not be used to endorse or promote products derived from this
31  *    software without prior written permission. For written
32  *    permission, please contact apache@apache.org.
33  *
34  * 5. Products derived from this software may not be called "Apache",
35  *    nor may "Apache" appear in their name, without prior written
36  *    permission of the Apache Software Foundation.
37  *
38  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
39  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
40  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
42  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
44  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
45  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
46  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
47  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
48  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49  * SUCH DAMAGE.
50  * ====================================================================
51  *
52  * This software consists of voluntary contributions made by many
53  * individuals on behalf of the Apache Software Foundation.  For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  *
57  * Portions of this software are based upon public domain software
58  * originally written at the National Center for Supercomputing Applications,
59  * University of Illinois, Urbana-Champaign.
60  */
61 
62 #define CORE_PRIVATE
63 #include "httpd.h"
64 #include "http_config.h"
65 #include "http_core.h"
66 #include "http_protocol.h"	/* For index_of_response().  Grump. */
67 #include "http_request.h"
68 #include "http_conf_globals.h"
69 #include "http_vhost.h"
70 #include "http_main.h"		/* For the default_handler below... */
71 #include "http_log.h"
72 #include "rfc1413.h"
73 #include "util_md5.h"
74 #include "scoreboard.h"
75 #include "fnmatch.h"
76 #include "sa_len.h"
77 
78 #include <sys/mman.h>
79 
80 __RCSID("$MirOS: src/usr.sbin/httpd/src/main/http_core.c,v 1.7 2008/12/03 11:22:59 tg Exp $");
81 
82 /* mmap support for static files based on ideas from John Heidemann's
83  * patch against 1.0.5.  See
84  * <http://www.isi.edu/~johnh/SOFTWARE/APACHE/index.html>.
85  */
86 
87 /* Files have to be at least this big before they're mmap()d.  This is to deal
88  * with systems where the expense of doing an mmap() and an munmap() outweighs
89  * the benefit for small files.  It shouldn't be set lower than 1.
90  */
91 #ifndef MMAP_THRESHOLD
92 #define MMAP_THRESHOLD		1
93 #endif
94 #ifndef MMAP_LIMIT
95 #define MMAP_LIMIT              (4*1024*1024)
96 #endif
97 
98 /* Server core module... This module provides support for really basic
99  * server operations, including options and commands which control the
100  * operation of other modules.  Consider this the bureaucracy module.
101  *
102  * The core module also defines handlers, etc., do handle just enough
103  * to allow a server with the core module ONLY to actually serve documents
104  * (though it slaps DefaultType on all of 'em); this was useful in testing,
105  * but may not be worth preserving.
106  *
107  * This file could almost be mod_core.c, except for the stuff which affects
108  * the http_conf_globals.
109  */
110 
create_core_dir_config(pool * a,char * dir)111 static void *create_core_dir_config(pool *a, char *dir)
112 {
113     core_dir_config *conf;
114 
115     conf = (core_dir_config *)ap_pcalloc(a, sizeof(core_dir_config));
116     if (!dir || dir[strlen(dir) - 1] == '/') {
117         conf->d = dir;
118     }
119     else if (strncmp(dir, "proxy:", 6) == 0) {
120         conf->d = ap_pstrdup(a, dir);
121     }
122     else {
123         conf->d = ap_pstrcat(a, dir, "/", NULL);
124     }
125     conf->d_is_fnmatch = conf->d ? (ap_is_fnmatch(conf->d) != 0) : 0;
126     conf->d_components = conf->d ? ap_count_dirs(conf->d) : 0;
127 
128     conf->opts = dir ? OPT_UNSET : OPT_UNSET|OPT_ALL;
129     conf->opts_add = conf->opts_remove = OPT_NONE;
130     conf->override = dir ? OR_UNSET : OR_UNSET|OR_ALL;
131 
132     conf->content_md5 = 2;
133 
134     conf->use_canonical_name = USE_CANONICAL_NAME_UNSET;
135 
136     conf->hostname_lookups = HOSTNAME_LOOKUP_UNSET;
137     conf->do_rfc1413 = DEFAULT_RFC1413 | 2; /* set bit 1 to indicate default */
138     conf->satisfy = SATISFY_NOSPEC;
139 
140     conf->limit_cpu = NULL;
141 #ifdef RLIMIT_TIME
142     conf->limit_time = NULL;
143 #endif
144     conf->limit_mem = NULL;
145     conf->limit_nproc = NULL;
146     conf->limit_nofile = NULL;
147 
148     conf->limit_req_body = 0;
149     conf->sec = ap_make_array(a, 2, sizeof(void *));
150 
151     conf->server_signature = srv_sig_unset;
152 
153     conf->add_default_charset = ADD_DEFAULT_CHARSET_UNSET;
154     conf->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
155 
156     /*
157      * Flag for use of inodes in ETags.
158      */
159     conf->etag_bits = ETAG_UNSET;
160     conf->etag_add = ETAG_UNSET;
161     conf->etag_remove = ETAG_UNSET;
162 
163     return (void *)conf;
164 }
165 
merge_core_dir_configs(pool * a,void * basev,void * newv)166 static void *merge_core_dir_configs(pool *a, void *basev, void *newv)
167 {
168     core_dir_config *base = (core_dir_config *)basev;
169     core_dir_config *new = (core_dir_config *)newv;
170     core_dir_config *conf;
171     int i;
172 
173     conf = (core_dir_config *)ap_palloc(a, sizeof(core_dir_config));
174     memcpy((char *)conf, (const char *)base, sizeof(core_dir_config));
175     if (base->response_code_strings) {
176 	conf->response_code_strings =
177 	    ap_palloc(a, sizeof(*conf->response_code_strings)
178 		      * RESPONSE_CODES);
179 	memcpy(conf->response_code_strings, base->response_code_strings,
180 	       sizeof(*conf->response_code_strings) * RESPONSE_CODES);
181     }
182 
183     conf->d = new->d;
184     conf->d_is_fnmatch = new->d_is_fnmatch;
185     conf->d_components = new->d_components;
186     conf->r = new->r;
187 
188     if (new->opts & OPT_UNSET) {
189 	/* there was no explicit setting of new->opts, so we merge
190 	 * preserve the invariant (opts_add & opts_remove) == 0
191 	 */
192 	conf->opts_add = (conf->opts_add & ~new->opts_remove) | new->opts_add;
193 	conf->opts_remove = (conf->opts_remove & ~new->opts_add)
194 	                    | new->opts_remove;
195 	conf->opts = (conf->opts & ~conf->opts_remove) | conf->opts_add;
196         if ((base->opts & OPT_INCNOEXEC) && (new->opts & OPT_INCLUDES)) {
197             conf->opts = (conf->opts & ~OPT_INCNOEXEC) | OPT_INCLUDES;
198 	}
199     }
200     else {
201 	/* otherwise we just copy, because an explicit opts setting
202 	 * overrides all earlier +/- modifiers
203 	 */
204 	conf->opts = new->opts;
205 	conf->opts_add = new->opts_add;
206 	conf->opts_remove = new->opts_remove;
207     }
208 
209     if (!(new->override & OR_UNSET)) {
210         conf->override = new->override;
211     }
212     if (new->ap_default_type) {
213         conf->ap_default_type = new->ap_default_type;
214     }
215 
216     if (new->ap_auth_type) {
217         conf->ap_auth_type = new->ap_auth_type;
218     }
219     if (new->ap_auth_name) {
220         conf->ap_auth_name = new->ap_auth_name;
221     }
222     if (new->ap_auth_nonce) {
223         conf->ap_auth_nonce = new->ap_auth_nonce;
224     }
225     if (new->ap_requires) {
226         conf->ap_requires = new->ap_requires;
227     }
228 
229     if (new->response_code_strings) {
230 	if (conf->response_code_strings == NULL) {
231 	    conf->response_code_strings = ap_palloc(a,
232 		sizeof(*conf->response_code_strings) * RESPONSE_CODES);
233 	    memcpy(conf->response_code_strings, new->response_code_strings,
234 		   sizeof(*conf->response_code_strings) * RESPONSE_CODES);
235 	}
236 	else {
237 	    for (i = 0; i < RESPONSE_CODES; ++i) {
238 	        if (new->response_code_strings[i] != NULL) {
239 		    conf->response_code_strings[i]
240 		        = new->response_code_strings[i];
241 		}
242 	    }
243 	}
244     }
245     if (new->hostname_lookups != HOSTNAME_LOOKUP_UNSET) {
246 	conf->hostname_lookups = new->hostname_lookups;
247     }
248     if ((new->do_rfc1413 & 2) == 0) {
249         conf->do_rfc1413 = new->do_rfc1413;
250     }
251     if ((new->content_md5 & 2) == 0) {
252         conf->content_md5 = new->content_md5;
253     }
254     if (new->use_canonical_name != USE_CANONICAL_NAME_UNSET) {
255 	conf->use_canonical_name = new->use_canonical_name;
256     }
257 
258     if (new->limit_cpu) {
259         conf->limit_cpu = new->limit_cpu;
260     }
261 #ifdef RLIMIT_TIME
262     if (new->limit_time) {
263         conf->limit_time = new->limit_time;
264     }
265 #endif
266     if (new->limit_mem) {
267         conf->limit_mem = new->limit_mem;
268     }
269     if (new->limit_nproc) {
270         conf->limit_nproc = new->limit_nproc;
271     }
272     if (new->limit_nofile) {
273         conf->limit_nofile = new->limit_nofile;
274     }
275 
276     if (new->limit_req_body) {
277         conf->limit_req_body = new->limit_req_body;
278     }
279     conf->sec = ap_append_arrays(a, base->sec, new->sec);
280 
281     if (new->satisfy != SATISFY_NOSPEC) {
282         conf->satisfy = new->satisfy;
283     }
284 
285 
286     if (new->server_signature != srv_sig_unset) {
287 	conf->server_signature = new->server_signature;
288     }
289 
290     if (new->add_default_charset != ADD_DEFAULT_CHARSET_UNSET) {
291 	conf->add_default_charset = new->add_default_charset;
292 	if (new->add_default_charset_name) {
293 	    conf->add_default_charset_name = new->add_default_charset_name;
294 	}
295     }
296 
297     /*
298      * Now merge the setting of the FileETag directive.
299      */
300     if (new->etag_bits == ETAG_UNSET) {
301         conf->etag_add =
302             (conf->etag_add & (~ new->etag_remove)) | new->etag_add;
303         conf->etag_remove =
304             (conf->opts_remove & (~ new->etag_add)) | new->etag_remove;
305         conf->etag_bits =
306             (conf->etag_bits & (~ conf->etag_remove)) | conf->etag_add;
307     }
308     else {
309         conf->etag_bits = new->etag_bits;
310         conf->etag_add = new->etag_add;
311         conf->etag_remove = new->etag_remove;
312     }
313     if (conf->etag_bits != ETAG_NONE) {
314         conf->etag_bits &= (~ ETAG_NONE);
315     }
316 
317     if (new->cgi_command_args != AP_FLAG_UNSET) {
318         conf->cgi_command_args = new->cgi_command_args;
319     }
320     ap_server_strip_chroot(conf->d, 0);
321 
322     return (void*)conf;
323 }
324 
create_core_server_config(pool * a,server_rec * s)325 static void *create_core_server_config(pool *a, server_rec *s)
326 {
327     core_server_config *conf;
328     int is_virtual = s->is_virtual;
329 
330     conf = (core_server_config *)ap_pcalloc(a, sizeof(core_server_config));
331 #ifdef GPROF
332     conf->gprof_dir = NULL;
333 #endif
334     conf->access_name = is_virtual ? NULL : DEFAULT_ACCESS_FNAME;
335     conf->ap_document_root = is_virtual ? NULL : DOCUMENT_LOCATION;
336     conf->sec = ap_make_array(a, 40, sizeof(void *));
337     conf->sec_url = ap_make_array(a, 40, sizeof(void *));
338 
339     /* recursion stopper */
340     conf->redirect_limit = 0;
341     conf->subreq_limit = 0;
342     conf->recursion_limit_set = 0;
343 
344     return (void *)conf;
345 }
346 
merge_core_server_configs(pool * p,void * basev,void * virtv)347 static void *merge_core_server_configs(pool *p, void *basev, void *virtv)
348 {
349     core_server_config *base = (core_server_config *)basev;
350     core_server_config *virt = (core_server_config *)virtv;
351     core_server_config *conf;
352 
353     conf = (core_server_config *)ap_pcalloc(p, sizeof(core_server_config));
354     *conf = *virt;
355     if (!conf->access_name) {
356         conf->access_name = base->access_name;
357     }
358     if (!conf->ap_document_root) {
359         conf->ap_document_root = base->ap_document_root;
360     }
361     conf->sec = ap_append_arrays(p, base->sec, virt->sec);
362     conf->sec_url = ap_append_arrays(p, base->sec_url, virt->sec_url);
363 
364     conf->redirect_limit = virt->recursion_limit_set
365                            ? virt->redirect_limit
366                            : base->redirect_limit;
367 
368     conf->subreq_limit = virt->recursion_limit_set
369                          ? virt->subreq_limit
370                          : base->subreq_limit;
371 
372     return conf;
373 }
374 
375 /* Add per-directory configuration entry (for <directory> section);
376  * these are part of the core server config.
377  */
378 
ap_add_per_dir_conf(server_rec * s,void * dir_config)379 CORE_EXPORT(void) ap_add_per_dir_conf(server_rec *s, void *dir_config)
380 {
381     core_server_config *sconf = ap_get_module_config(s->module_config,
382 						     &core_module);
383     void **new_space = (void **)ap_push_array(sconf->sec);
384 
385     *new_space = dir_config;
386 }
387 
ap_add_per_url_conf(server_rec * s,void * url_config)388 CORE_EXPORT(void) ap_add_per_url_conf(server_rec *s, void *url_config)
389 {
390     core_server_config *sconf = ap_get_module_config(s->module_config,
391 						     &core_module);
392     void **new_space = (void **)ap_push_array(sconf->sec_url);
393 
394     *new_space = url_config;
395 }
396 
ap_add_file_conf(core_dir_config * conf,void * url_config)397 CORE_EXPORT(void) ap_add_file_conf(core_dir_config *conf, void *url_config)
398 {
399     void **new_space = (void **)ap_push_array(conf->sec);
400 
401     *new_space = url_config;
402 }
403 
404 /* core_reorder_directories reorders the directory sections such that the
405  * 1-component sections come first, then the 2-component, and so on, finally
406  * followed by the "special" sections.  A section is "special" if it's a regex,
407  * or if it doesn't start with / -- consider proxy: matching.  All movements
408  * are in-order to preserve the ordering of the sections from the config files.
409  * See directory_walk().
410  */
411 
412 #define IS_SPECIAL(entry_core)	\
413     ((entry_core)->r != NULL || (entry_core)->d[0] != '/')
414 
415 /* We need to do a stable sort, qsort isn't stable.  So to make it stable
416  * we'll be maintaining the original index into the list, and using it
417  * as the minor key during sorting.  The major key is the number of
418  * components (where a "special" section has infinite components).
419  */
420 struct reorder_sort_rec {
421     void *elt;
422     int orig_index;
423 };
424 
reorder_sorter(const void * va,const void * vb)425 static int reorder_sorter(const void *va, const void *vb)
426 {
427     const struct reorder_sort_rec *a = va;
428     const struct reorder_sort_rec *b = vb;
429     core_dir_config *core_a;
430     core_dir_config *core_b;
431 
432     core_a = (core_dir_config *)ap_get_module_config(a->elt, &core_module);
433     core_b = (core_dir_config *)ap_get_module_config(b->elt, &core_module);
434     if (IS_SPECIAL(core_a)) {
435 	if (!IS_SPECIAL(core_b)) {
436 	    return 1;
437 	}
438     }
439     else if (IS_SPECIAL(core_b)) {
440 	return -1;
441     }
442     else {
443 	/* we know they're both not special */
444 	if (core_a->d_components < core_b->d_components) {
445 	    return -1;
446 	}
447 	else if (core_a->d_components > core_b->d_components) {
448 	    return 1;
449 	}
450     }
451     /* Either they're both special, or they're both not special and have the
452      * same number of components.  In any event, we now have to compare
453      * the minor key. */
454     return a->orig_index - b->orig_index;
455 }
456 
ap_core_reorder_directories(pool * p,server_rec * s)457 CORE_EXPORT(void) ap_core_reorder_directories(pool *p, server_rec *s)
458 {
459     core_server_config *sconf;
460     array_header *sec;
461     struct reorder_sort_rec *sortbin;
462     int nelts;
463     void **elts;
464     int i;
465     pool *tmp;
466 
467     sconf = ap_get_module_config(s->module_config, &core_module);
468     sec = sconf->sec;
469     nelts = sec->nelts;
470     elts = (void **)sec->elts;
471 
472     /* we have to allocate tmp space to do a stable sort */
473     tmp = ap_make_sub_pool(p);
474     sortbin = ap_palloc(tmp, sec->nelts * sizeof(*sortbin));
475     for (i = 0; i < nelts; ++i) {
476 	sortbin[i].orig_index = i;
477 	sortbin[i].elt = elts[i];
478     }
479 
480     qsort(sortbin, nelts, sizeof(*sortbin), reorder_sorter);
481 
482     /* and now copy back to the original array */
483     for (i = 0; i < nelts; ++i) {
484       elts[i] = sortbin[i].elt;
485     }
486 
487     ap_destroy_pool(tmp);
488 }
489 
490 /*****************************************************************
491  *
492  * There are some elements of the core config structures in which
493  * other modules have a legitimate interest (this is ugly, but necessary
494  * to preserve NCSA back-compatibility).  So, we have a bunch of accessors
495  * here...
496  */
497 
ap_allow_options(request_rec * r)498 API_EXPORT(int) ap_allow_options(request_rec *r)
499 {
500     core_dir_config *conf =
501       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
502 
503     return conf->opts;
504 }
505 
ap_allow_overrides(request_rec * r)506 API_EXPORT(int) ap_allow_overrides(request_rec *r)
507 {
508     core_dir_config *conf;
509     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
510 						   &core_module);
511 
512     return conf->override;
513 }
514 
ap_auth_type(request_rec * r)515 API_EXPORT(const char *) ap_auth_type(request_rec *r)
516 {
517     core_dir_config *conf;
518 
519     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
520 						   &core_module);
521     return conf->ap_auth_type;
522 }
523 
ap_auth_name(request_rec * r)524 API_EXPORT(const char *) ap_auth_name(request_rec *r)
525 {
526     core_dir_config *conf;
527 
528     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
529 						   &core_module);
530     return conf->ap_auth_name;
531 }
532 
ap_auth_nonce(request_rec * r)533 API_EXPORT(const char *) ap_auth_nonce(request_rec *r)
534 {
535     core_dir_config *conf;
536     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
537                                                    &core_module);
538     if (conf->ap_auth_nonce)
539        return conf->ap_auth_nonce;
540 
541     /* Ideally we'd want to mix in some per-directory style
542      * information; as we are likely to want to detect replay
543      * across those boundaries and some randomness. But that
544      * is harder due to the adhoc nature of .htaccess memory
545      * structures, restarts and forks.
546      *
547      * But then again - you should use AuthDigestRealmSeed in your config
548      * file if you care. So the adhoc value should do.
549      */
550     return ap_psprintf(r->pool,"%pp%pp%pp%pp%pp",
551 	   (void *)&(((struct sockaddr_in *)&r->connection->local_addr)->sin_addr ),
552            (void *)ap_user_name,
553            (void *)ap_listeners,
554            (void *)ap_server_argv0,
555            (void *)ap_pid_fname);
556 }
557 
ap_default_type(request_rec * r)558 API_EXPORT(const char *) ap_default_type(request_rec *r)
559 {
560     core_dir_config *conf;
561 
562     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
563 						   &core_module);
564     return conf->ap_default_type
565                ? conf->ap_default_type
566                : DEFAULT_CONTENT_TYPE;
567 }
568 
ap_document_root(request_rec * r)569 API_EXPORT(const char *) ap_document_root(request_rec *r) /* Don't use this! */
570 {
571     core_server_config *conf;
572 
573     conf = (core_server_config *)ap_get_module_config(r->server->module_config,
574 						      &core_module);
575     return conf->ap_document_root;
576 }
577 
ap_requires(request_rec * r)578 API_EXPORT(const array_header *) ap_requires(request_rec *r)
579 {
580     core_dir_config *conf;
581 
582     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
583 						   &core_module);
584     return conf->ap_requires;
585 }
586 
ap_satisfies(request_rec * r)587 API_EXPORT(int) ap_satisfies(request_rec *r)
588 {
589     core_dir_config *conf;
590 
591     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
592 						   &core_module);
593 
594     return conf->satisfy;
595 }
596 
597 /* Should probably just get rid of this... the only code that cares is
598  * part of the core anyway (and in fact, it isn't publicised to other
599  * modules).
600  */
601 
ap_response_code_string(request_rec * r,int error_index)602 API_EXPORT(char *) ap_response_code_string(request_rec *r, int error_index)
603 {
604     core_dir_config *conf;
605 
606     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
607 						   &core_module);
608 
609     if (conf->response_code_strings == NULL) {
610 	return NULL;
611     }
612     return conf->response_code_strings[error_index];
613 }
614 
615 
616 /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
617 /* Note: the function returns its result in conn->double_reverse:
618  *       +1: forward lookup of the previously reverse-looked-up
619  *           hostname in conn->remote_host succeeded, and at
620  *           least one of its IP addresses matches the client.
621  *       -1: forward lookup of conn->remote_host failed, or
622  *           none of the addresses found matches the client connection
623  *           (possible DNS spoof in the reverse zone!)
624  *       If do_double_reverse() returns -1, then it also invalidates
625  *       conn->remote_host to prevent an invalid name from appearing
626  *       in the log files. Conn->remote_host is set to "", because
627  *       a setting of NULL would allow another reverse lookup,
628  *       depending on the flags given to ap_get_remote_host().
629  */
do_double_reverse(conn_rec * conn)630 static ap_inline void do_double_reverse (conn_rec *conn)
631 {
632     struct addrinfo hints, *res, *res0;
633     char hostbuf1[128], hostbuf2[128]; /* INET6_ADDRSTRLEN(=46) is enough */
634     int ok = 0;
635 
636     if (conn->double_reverse) {
637 	/* already done */
638 	return;
639     }
640     if (conn->remote_host == NULL || conn->remote_host[0] == '\0') {
641 	/* single reverse failed, so don't bother */
642 	conn->double_reverse = -1;
643         conn->remote_host = ""; /* prevent another lookup */
644 	return;
645     }
646     memset(&hints, 0, sizeof(hints));
647     hints.ai_family = PF_UNSPEC;
648     hints.ai_socktype = SOCK_STREAM;
649     if (getaddrinfo(conn->remote_host, NULL, &hints, &res0)) {
650 	conn->double_reverse = -1;
651 	return;
652     }
653     for (res = res0; res; res = res->ai_next) {
654 	if (res->ai_addr->sa_family != conn->remote_addr.ss_family ||
655 	    !(res->ai_family == AF_INET
656 #ifdef INET6
657 	      || res->ai_family == AF_INET6
658 #endif
659 	      )
660 	    )
661 	    continue;
662 #ifndef HAVE_SOCKADDR_LEN
663 	if (res->ai_addrlen != SA_LEN((struct sockaddr *)&conn->remote_addr))
664 #else
665 	if (res->ai_addr->sa_len != conn->remote_addr.ss_len)
666 #endif
667 	    continue;
668 	if (getnameinfo(res->ai_addr, res->ai_addrlen,
669             hostbuf1, sizeof(hostbuf1), NULL, 0,
670             NI_NUMERICHOST))
671 	    continue;
672 	if (getnameinfo(((struct sockaddr *)&conn->remote_addr), res->ai_addrlen,
673             hostbuf2, sizeof(hostbuf2), NULL, 0,
674             NI_NUMERICHOST))
675 	    continue;
676 	if (strcmp(hostbuf1, hostbuf2) == 0){
677 	    ok = 1;
678 	    break;
679 	}
680     }
681     conn->double_reverse = ok ? 1 : -1;
682     freeaddrinfo(res0);
683 }
684 
ap_get_remote_host(conn_rec * conn,void * dir_config,int type)685 API_EXPORT(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
686 					    int type)
687 {
688     int hostname_lookups;
689     int old_stat = SERVER_DEAD;	/* we shouldn't ever be in this state */
690     char hostnamebuf[MAXHOSTNAMELEN];
691 
692     /* If we haven't checked the host name, and we want to */
693     if (dir_config) {
694 	hostname_lookups =
695 	    ((core_dir_config *)ap_get_module_config(dir_config, &core_module))
696 		->hostname_lookups;
697 	if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) {
698 	    hostname_lookups = HOSTNAME_LOOKUP_OFF;
699 	}
700     }
701     else {
702 	/* the default */
703 	hostname_lookups = HOSTNAME_LOOKUP_OFF;
704     }
705 
706     if (type != REMOTE_NOLOOKUP
707 	&& conn->remote_host == NULL
708 	&& (type == REMOTE_DOUBLE_REV
709 	    || hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
710 	old_stat = ap_update_child_status(conn->child_num, SERVER_BUSY_DNS,
711 					  (request_rec*)NULL);
712 	if (!getnameinfo((struct sockaddr *)&conn->remote_addr,
713 #ifndef SIN6_LEN
714 		SA_LEN((struct sockaddr *)&conn->remote_addr),
715 #else
716 		conn->remote_addr.ss_len,
717 #endif
718 		hostnamebuf, sizeof(hostnamebuf), NULL, 0, 0)) {
719 	    conn->remote_host = ap_pstrdup(conn->pool, (void *)hostnamebuf);
720 	    ap_str_tolower(conn->remote_host);
721 
722 	    if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
723 		do_double_reverse(conn);
724 	    }
725 	}
726 	/* if failed, set it to the NULL string to indicate error */
727 	if (conn->remote_host == NULL) {
728 	    conn->remote_host = "";
729 	}
730     }
731     if (type == REMOTE_DOUBLE_REV) {
732 	do_double_reverse(conn);
733 	if (conn->double_reverse == -1) {
734 	    return NULL;
735 	}
736     }
737     if (old_stat != SERVER_DEAD) {
738 	(void)ap_update_child_status(conn->child_num, old_stat,
739 				     (request_rec*)NULL);
740     }
741 
742 /*
743  * Return the desired information; either the remote DNS name, if found,
744  * or either NULL (if the hostname was requested) or the IP address
745  * (if any identifier was requested).
746  */
747     if (conn->remote_host != NULL && conn->remote_host[0] != '\0') {
748 	return conn->remote_host;
749     }
750     else {
751 	if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) {
752 	    return NULL;
753 	}
754 	else {
755 	    return conn->remote_ip;
756 	}
757     }
758 }
759 
ap_get_remote_logname(request_rec * r)760 API_EXPORT(const char *) ap_get_remote_logname(request_rec *r)
761 {
762     core_dir_config *dir_conf;
763 
764     if (r->connection->remote_logname != NULL) {
765 	return r->connection->remote_logname;
766     }
767 
768 /* If we haven't checked the identity, and we want to */
769     dir_conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
770 						       &core_module);
771 
772     if (dir_conf->do_rfc1413 & 1) {
773 	return ap_rfc1413(r->connection, r->server);
774     }
775     else {
776 	return NULL;
777     }
778 }
779 
780 /* There are two options regarding what the "name" of a server is.  The
781  * "canonical" name as defined by ServerName and Port, or the "client's
782  * name" as supplied by a possible Host: header or full URI.  We never
783  * trust the port passed in the client's headers, we always use the
784  * port of the actual socket.
785  *
786  * The DNS option to UseCanonicalName causes this routine to do a
787  * reverse lookup on the local IP address of the connectiona and use
788  * that for the ServerName. This makes its value more reliable while
789  * at the same time allowing Demon's magic virtual hosting to work.
790  * The assumption is that DNS lookups are sufficiently quick...
791  * -- fanf 1998-10-03
792  */
ap_get_server_name(request_rec * r)793 API_EXPORT(const char *) ap_get_server_name(request_rec *r)
794 {
795     conn_rec *conn = r->connection;
796     core_dir_config *d;
797     char hbuf[MAXHOSTNAMELEN];
798 
799     d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
800 						&core_module);
801 
802     if (d->use_canonical_name == USE_CANONICAL_NAME_OFF) {
803         return r->hostname ? r->hostname : r->server->server_hostname;
804     }
805     if (d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
806         if (conn->local_host == NULL) {
807             int old_stat;
808 	    old_stat = ap_update_child_status(conn->child_num,
809 					      SERVER_BUSY_DNS, r);
810 	    if (getnameinfo((struct sockaddr *)&conn->local_addr,
811 #ifndef SIN6_LEN
812 		    SA_LEN((struct sockaddr *)&conn->local_addr),
813 #else
814 		    conn->local_addr.ss_len,
815 #endif
816 		    hbuf, sizeof(hbuf), NULL, 0, 0) == 0) {
817 		conn->local_host = ap_pstrdup(conn->pool, hbuf);
818 	    } else {
819 		conn->local_host = ap_pstrdup(conn->pool,
820 		    r->server->server_hostname);
821 	    }
822 	    ap_str_tolower(conn->local_host);
823 	    (void) ap_update_child_status(conn->child_num, old_stat, r);
824 	}
825 	return conn->local_host;
826     }
827     /* default */
828     return r->server->server_hostname;
829 }
830 
ap_get_server_port(const request_rec * r)831 API_EXPORT(unsigned) ap_get_server_port(const request_rec *r)
832 {
833     unsigned port;
834     unsigned cport = ntohs(((struct sockaddr_in *)&r->connection->local_addr)->sin_port);
835     core_dir_config *d =
836       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
837 
838     if (d->use_canonical_name == USE_CANONICAL_NAME_OFF
839         || d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
840 
841         /* With UseCanonicalName Off Apache will form self-referential
842          * URLs using the hostname and port supplied by the client if
843          * any are supplied (otherwise it will use the canonical name).
844          */
845         port = r->parsed_uri.port_str ? r->parsed_uri.port :
846           cport ? cport :
847             r->server->port ? r->server->port :
848               ap_default_port(r);
849     } else { /* d->use_canonical_name == USE_CANONICAL_NAME_ON */
850         port = r->server->port ? r->server->port :
851           cport ? cport :
852             ap_default_port(r);
853     }
854 
855     /* default */
856     return port;
857 }
858 
ap_construct_url(pool * p,const char * uri,request_rec * r)859 API_EXPORT(char *) ap_construct_url(pool *p, const char *uri,
860 				    request_rec *r)
861 {
862     unsigned port = ap_get_server_port(r);
863     const char *host = ap_get_server_name(r);
864 
865     if (ap_is_default_port(port, r)) {
866 	return ap_pstrcat(p, ap_http_method(r), "://", host, uri, NULL);
867     }
868     return ap_psprintf(p, "%s://%s:%u%s", ap_http_method(r), host, port, uri);
869 }
870 
ap_get_limit_req_body(const request_rec * r)871 API_EXPORT(unsigned long) ap_get_limit_req_body(const request_rec *r)
872 {
873     core_dir_config *d =
874       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
875 
876     return d->limit_req_body;
877 }
878 
879 
880 /*****************************************************************
881  *
882  * Commands... this module handles almost all of the NCSA httpd.conf
883  * commands, but most of the old srm.conf is in the the modules.
884  */
885 
886 static const char end_directory_section[] = "</Directory>";
887 static const char end_directorymatch_section[] = "</DirectoryMatch>";
888 static const char end_location_section[] = "</Location>";
889 static const char end_locationmatch_section[] = "</LocationMatch>";
890 static const char end_files_section[] = "</Files>";
891 static const char end_filesmatch_section[] = "</FilesMatch>";
892 static const char end_virtualhost_section[] = "</VirtualHost>";
893 static const char end_ifmodule_section[] = "</IfModule>";
894 static const char end_ifdefine_section[] = "</IfDefine>";
895 
896 
ap_check_cmd_context(cmd_parms * cmd,unsigned forbidden)897 API_EXPORT(const char *) ap_check_cmd_context(cmd_parms *cmd,
898 					      unsigned forbidden)
899 {
900     const char *gt = (cmd->cmd->name[0] == '<'
901 		      && cmd->cmd->name[strlen(cmd->cmd->name)-1] != '>')
902                          ? ">" : "";
903 
904     if ((forbidden & NOT_IN_VIRTUALHOST) && cmd->server->is_virtual) {
905 	return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
906 			  " cannot occur within <VirtualHost> section", NULL);
907     }
908 
909     if ((forbidden & NOT_IN_LIMIT) && cmd->limited != -1) {
910 	return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
911 			  " cannot occur within <Limit> section", NULL);
912     }
913 
914     if ((forbidden & NOT_IN_DIR_LOC_FILE) == NOT_IN_DIR_LOC_FILE
915 	&& cmd->path != NULL) {
916 	return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
917 			  " cannot occur within <Directory/Location/Files> "
918 			  "section", NULL);
919     }
920 
921     if (((forbidden & NOT_IN_DIRECTORY)
922 	 && (cmd->end_token == end_directory_section
923 	     || cmd->end_token == end_directorymatch_section))
924 	|| ((forbidden & NOT_IN_LOCATION)
925 	    && (cmd->end_token == end_location_section
926 		|| cmd->end_token == end_locationmatch_section))
927 	|| ((forbidden & NOT_IN_FILES)
928 	    && (cmd->end_token == end_files_section
929 		|| cmd->end_token == end_filesmatch_section))) {
930 	return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
931 			  " cannot occur within <", cmd->end_token+2,
932 			  " section", NULL);
933     }
934 
935     return NULL;
936 }
937 
set_access_name(cmd_parms * cmd,void * dummy,char * arg)938 static const char *set_access_name(cmd_parms *cmd, void *dummy, char *arg)
939 {
940     void *sconf = cmd->server->module_config;
941     core_server_config *conf = ap_get_module_config(sconf, &core_module);
942 
943     const char *err = ap_check_cmd_context(cmd,
944 					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
945     if (err != NULL) {
946         return err;
947     }
948 
949     conf->access_name = ap_pstrdup(cmd->pool, arg);
950     return NULL;
951 }
952 
953 #ifdef GPROF
set_gprof_dir(cmd_parms * cmd,void * dummy,char * arg)954 static const char *set_gprof_dir(cmd_parms *cmd, void *dummy, char *arg)
955 {
956     void *sconf = cmd->server->module_config;
957     core_server_config *conf = ap_get_module_config(sconf, &core_module);
958 
959     const char *err = ap_check_cmd_context(cmd,
960 					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
961     if (err != NULL) {
962         return err;
963     }
964 
965     conf->gprof_dir = ap_pstrdup(cmd->pool, arg);
966     return NULL;
967 }
968 #endif /*GPROF*/
969 
set_add_default_charset(cmd_parms * cmd,core_dir_config * d,char * arg)970 static const char *set_add_default_charset(cmd_parms *cmd,
971 	core_dir_config *d, char *arg)
972 {
973     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
974     if (err != NULL) {
975         return err;
976     }
977     if (!strcasecmp(arg, "Off")) {
978        d->add_default_charset = ADD_DEFAULT_CHARSET_OFF;
979     }
980     else if (!strcasecmp(arg, "On")) {
981        d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
982        d->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
983     }
984     else {
985        d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
986        d->add_default_charset_name = arg;
987     }
988     return NULL;
989 }
set_accept_mutex(cmd_parms * cmd,void * dummy,char * arg)990 static const char *set_accept_mutex(cmd_parms *cmd, void *dummy, char *arg)
991 {
992 	return ap_init_mutex_method(arg);
993 }
994 
set_document_root(cmd_parms * cmd,void * dummy,char * arg)995 static const char *set_document_root(cmd_parms *cmd, void *dummy, char *arg)
996 {
997     void *sconf = cmd->server->module_config;
998     core_server_config *conf = ap_get_module_config(sconf, &core_module);
999 
1000     const char *err = ap_check_cmd_context(cmd,
1001 					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1002     if (err != NULL) {
1003         return err;
1004     }
1005 
1006     arg = ap_os_canonical_filename(cmd->pool, arg);
1007     if (ap_configtestonly && ap_docrootcheck && !ap_is_directory(arg)) {
1008 	if (cmd->server->is_virtual) {
1009 	    fprintf(stderr, "Warning: DocumentRoot [%s] does not exist\n",
1010 		    arg);
1011 	}
1012 	else {
1013 	    return "DocumentRoot must be a directory";
1014 	}
1015     }
1016     ap_server_strip_chroot(arg, 1);
1017     conf->ap_document_root = arg;
1018     return NULL;
1019 }
1020 
ap_custom_response(request_rec * r,int status,char * string)1021 API_EXPORT(void) ap_custom_response(request_rec *r, int status, char *string)
1022 {
1023     core_dir_config *conf =
1024 	ap_get_module_config(r->per_dir_config, &core_module);
1025     int idx;
1026 
1027     ap_server_strip_chroot(conf->d, 0);
1028     if(conf->response_code_strings == NULL) {
1029         conf->response_code_strings =
1030 	    ap_pcalloc(r->pool,
1031 		    sizeof(*conf->response_code_strings) *
1032                        RESPONSE_CODES);
1033     }
1034 
1035     idx = ap_index_of_response(status);
1036 
1037     conf->response_code_strings[idx] =
1038        ((ap_is_url(string) || (*string == '/')) && (*string != '"')) ?
1039        ap_pstrdup(r->pool, string) : ap_pstrcat(r->pool, "\"", string, NULL);
1040 }
1041 
set_error_document(cmd_parms * cmd,core_dir_config * conf,char * line)1042 static const char *set_error_document(cmd_parms *cmd, core_dir_config *conf,
1043 				      char *line)
1044 {
1045     int error_number, index_number, idx500;
1046     char *w;
1047 
1048     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1049     if (err != NULL) {
1050         return err;
1051     }
1052 
1053     /* 1st parameter should be a 3 digit number, which we recognize;
1054      * convert it into an array index
1055      */
1056 
1057     w = ap_getword_conf_nc(cmd->pool, &line);
1058     error_number = atoi(w);
1059 
1060     idx500 = ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);
1061 
1062     if (error_number == HTTP_INTERNAL_SERVER_ERROR) {
1063         index_number = idx500;
1064     }
1065     else if ((index_number = ap_index_of_response(error_number)) == idx500) {
1066         return ap_pstrcat(cmd->pool, "Unsupported HTTP response code ",
1067 			  w, NULL);
1068     }
1069 
1070     /* The entry should be ignored if it is a full URL for a 401 error */
1071 
1072     if (error_number == 401 &&
1073 	line[0] != '/' && line[0] != '"') { /* Ignore it... */
1074 	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, cmd->server,
1075 		     "cannot use a full URL in a 401 ErrorDocument "
1076 		     "directive --- ignoring!");
1077     }
1078     else { /* Store it... */
1079     	if (conf->response_code_strings == NULL) {
1080 	    conf->response_code_strings =
1081 		ap_pcalloc(cmd->pool,
1082 			   sizeof(*conf->response_code_strings) * RESPONSE_CODES);
1083         }
1084         conf->response_code_strings[index_number] = ap_pstrdup(cmd->pool, line);
1085     }
1086 
1087     return NULL;
1088 }
1089 
1090 /* access.conf commands...
1091  *
1092  * The *only* thing that can appear in access.conf at top level is a
1093  * <Directory> section.  NB we need to have a way to cut the srm_command_loop
1094  * invoked by dirsection (i.e., <Directory>) short when </Directory> is seen.
1095  * We do that by returning an error, which dirsection itself recognizes and
1096  * discards as harmless.  Cheesy, but it works.
1097  */
1098 
set_override(cmd_parms * cmd,core_dir_config * d,const char * l)1099 static const char *set_override(cmd_parms *cmd, core_dir_config *d,
1100 				const char *l)
1101 {
1102     char *w;
1103 
1104     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1105     if (err != NULL) {
1106         return err;
1107     }
1108 
1109     d->override = OR_NONE;
1110     while (l[0]) {
1111         w = ap_getword_conf(cmd->pool, &l);
1112 	if (!strcasecmp(w, "Limit")) {
1113 	    d->override |= OR_LIMIT;
1114 	}
1115 	else if (!strcasecmp(w, "Options")) {
1116 	    d->override |= OR_OPTIONS;
1117 	}
1118 	else if (!strcasecmp(w, "FileInfo")) {
1119             d->override |= OR_FILEINFO;
1120 	}
1121 	else if (!strcasecmp(w, "AuthConfig")) {
1122 	    d->override |= OR_AUTHCFG;
1123 	}
1124 	else if (!strcasecmp(w, "Indexes")) {
1125             d->override |= OR_INDEXES;
1126 	}
1127 	else if (!strcasecmp(w, "None")) {
1128 	    d->override = OR_NONE;
1129 	}
1130 	else if (!strcasecmp(w, "All")) {
1131 	    d->override = OR_ALL;
1132 	}
1133 	else {
1134 	    return ap_pstrcat(cmd->pool, "Illegal override option ", w, NULL);
1135 	}
1136 	d->override &= ~OR_UNSET;
1137     }
1138 
1139     return NULL;
1140 }
1141 
set_options(cmd_parms * cmd,core_dir_config * d,const char * l)1142 static const char *set_options(cmd_parms *cmd, core_dir_config *d,
1143 			       const char *l)
1144 {
1145     allow_options_t opt;
1146     int first = 1;
1147     char action;
1148 
1149     while (l[0]) {
1150         char *w = ap_getword_conf(cmd->pool, &l);
1151 	action = '\0';
1152 
1153 	if (*w == '+' || *w == '-') {
1154 	    action = *(w++);
1155 	}
1156 	else if (first) {
1157   	    d->opts = OPT_NONE;
1158             first = 0;
1159         }
1160 
1161 	if (!strcasecmp(w, "Indexes")) {
1162 	    opt = OPT_INDEXES;
1163 	}
1164 	else if (!strcasecmp(w, "Includes")) {
1165 	    opt = OPT_INCLUDES;
1166 	}
1167 	else if (!strcasecmp(w, "IncludesNOEXEC")) {
1168 	    opt = (OPT_INCLUDES | OPT_INCNOEXEC);
1169 	}
1170 	else if (!strcasecmp(w, "FollowSymLinks")) {
1171 	    opt = OPT_SYM_LINKS;
1172 	}
1173 	else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
1174 	    opt = OPT_SYM_OWNER;
1175 	}
1176 	else if (!strcasecmp(w, "execCGI")) {
1177 	    opt = OPT_EXECCGI;
1178 	}
1179 	else if (!strcasecmp(w, "MultiViews")) {
1180 	    opt = OPT_MULTI;
1181 	}
1182 	else if (!strcasecmp(w, "RunScripts")) { /* AI backcompat. Yuck */
1183 	    opt = OPT_MULTI|OPT_EXECCGI;
1184 	}
1185 	else if (!strcasecmp(w, "None")) {
1186 	    opt = OPT_NONE;
1187 	}
1188 	else if (!strcasecmp(w, "All")) {
1189 	    opt = OPT_ALL;
1190 	}
1191 	else {
1192 	    return ap_pstrcat(cmd->pool, "Illegal option ", w, NULL);
1193 	}
1194 
1195 	/* we ensure the invariant (d->opts_add & d->opts_remove) == 0 */
1196 	if (action == '-') {
1197 	    d->opts_remove |= opt;
1198 	    d->opts_add &= ~opt;
1199 	    d->opts &= ~opt;
1200 	}
1201 	else if (action == '+') {
1202 	    d->opts_add |= opt;
1203 	    d->opts_remove &= ~opt;
1204 	    d->opts |= opt;
1205 	}
1206 	else {
1207 	    d->opts |= opt;
1208 	}
1209     }
1210 
1211     return NULL;
1212 }
1213 
satisfy(cmd_parms * cmd,core_dir_config * c,char * arg)1214 static const char *satisfy(cmd_parms *cmd, core_dir_config *c, char *arg)
1215 {
1216     if (!strcasecmp(arg, "all")) {
1217         c->satisfy = SATISFY_ALL;
1218     }
1219     else if (!strcasecmp(arg, "any")) {
1220         c->satisfy = SATISFY_ANY;
1221     }
1222     else {
1223         return "Satisfy either 'any' or 'all'.";
1224     }
1225     return NULL;
1226 }
1227 
require(cmd_parms * cmd,core_dir_config * c,char * arg)1228 static const char *require(cmd_parms *cmd, core_dir_config *c, char *arg)
1229 {
1230     require_line *r;
1231 
1232     if (!c->ap_requires) {
1233         c->ap_requires = ap_make_array(cmd->pool, 2, sizeof(require_line));
1234     }
1235     r = (require_line *)ap_push_array(c->ap_requires);
1236     r->requirement = ap_pstrdup(cmd->pool, arg);
1237     r->method_mask = cmd->limited;
1238     return NULL;
1239 }
1240 
ap_limit_section(cmd_parms * cmd,void * dummy,const char * arg)1241 CORE_EXPORT_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, void *dummy,
1242 						  const char *arg)
1243 {
1244     const char *limited_methods = ap_getword(cmd->pool, &arg, '>');
1245     void *tog = cmd->cmd->cmd_data;
1246     int limited = 0;
1247 
1248     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1249     if (err != NULL) {
1250         return err;
1251     }
1252 
1253     /* XXX: NB: Currently, we have no way of checking
1254      * whether <Limit> or <LimitExcept> sections are closed properly.
1255      * (If we would add a srm_command_loop() here we might...)
1256      */
1257 
1258     while (limited_methods[0]) {
1259         char *method = ap_getword_conf(cmd->pool, &limited_methods);
1260         int  methnum = ap_method_number_of(method);
1261 
1262         if (methnum == M_TRACE && !tog) {
1263             return "TRACE cannot be controlled by <Limit>";
1264         }
1265         else if (methnum == M_INVALID) {
1266             return ap_pstrcat(cmd->pool, "unknown method \"", method,
1267                               "\" in <Limit", tog ? "Except>" : ">", NULL);
1268         }
1269         else {
1270             limited |= (1 << methnum);
1271         }
1272     }
1273 
1274     /* Killing two features with one function,
1275      * if (tog == NULL) <Limit>, else <LimitExcept>
1276      */
1277     cmd->limited = tog ? ~limited : limited;
1278     return NULL;
1279 }
1280 
endlimit_section(cmd_parms * cmd,void * dummy,void * dummy2)1281 static const char *endlimit_section(cmd_parms *cmd, void *dummy, void *dummy2)
1282 {
1283     void *tog = cmd->cmd->cmd_data;
1284 
1285     if (cmd->limited == -1) {
1286         return tog ? "</LimitExcept> unexpected" : "</Limit> unexpected";
1287     }
1288 
1289     cmd->limited = -1;
1290     return NULL;
1291 }
1292 
1293 /*
1294  * When a section is not closed properly when end-of-file is reached,
1295  * then an error message should be printed:
1296  */
missing_endsection(cmd_parms * cmd,int nest)1297 static const char *missing_endsection(cmd_parms *cmd, int nest)
1298 {
1299     if (nest < 2) {
1300 	return ap_psprintf(cmd->pool, "Missing %s directive at end-of-file",
1301 			   cmd->end_token);
1302     }
1303     return ap_psprintf(cmd->pool, "%d missing %s directives at end-of-file",
1304 		       nest, cmd->end_token);
1305 }
1306 
1307 /* We use this in <DirectoryMatch> and <FilesMatch>, to ensure that
1308  * people don't get bitten by wrong-cased regex matches
1309  */
1310 
1311 #define USE_ICASE 0
1312 
end_nested_section(cmd_parms * cmd,void * dummy)1313 static const char *end_nested_section(cmd_parms *cmd, void *dummy)
1314 {
1315     if (cmd->end_token == NULL) {
1316         return ap_pstrcat(cmd->pool, cmd->cmd->name,
1317 			  " without matching <", cmd->cmd->name + 2,
1318 			  " section", NULL);
1319     }
1320     /*
1321      * This '!=' may look weird on a string comparison, but it's correct --
1322      * it's been set up so that checking for two pointers to the same datum
1323      * is valid here.  And faster.
1324      */
1325     if (cmd->cmd->name != cmd->end_token) {
1326 	return ap_pstrcat(cmd->pool, "Expected ", cmd->end_token, " but saw ",
1327 			  cmd->cmd->name, NULL);
1328     }
1329     return cmd->end_token;
1330 }
1331 
1332 /*
1333  * Report a missing-'>' syntax error.
1334  */
unclosed_directive(cmd_parms * cmd)1335 static char *unclosed_directive(cmd_parms *cmd)
1336 {
1337     return ap_pstrcat(cmd->pool, cmd->cmd->name,
1338 		      "> directive missing closing '>'", NULL);
1339 }
1340 
dirsection(cmd_parms * cmd,void * dummy,const char * arg)1341 static const char *dirsection(cmd_parms *cmd, void *dummy, const char *arg)
1342 {
1343     const char *errmsg;
1344     char *endp = strrchr(arg, '>');
1345     int old_overrides = cmd->override;
1346     char *old_path = cmd->path;
1347     core_dir_config *conf;
1348     void *new_dir_conf = ap_create_per_dir_config(cmd->pool);
1349     regex_t *r = NULL;
1350     const char *old_end_token;
1351     const command_rec *thiscmd = cmd->cmd;
1352 
1353     const char *err = ap_check_cmd_context(cmd,
1354 					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1355     if (err != NULL) {
1356         return err;
1357     }
1358 
1359     if (endp == NULL) {
1360 	return unclosed_directive(cmd);
1361     }
1362 
1363     *endp = '\0';
1364 
1365     cmd->path = ap_getword_conf(cmd->pool, &arg);
1366     ap_server_strip_chroot(cmd->path, 1);
1367     cmd->override = OR_ALL|ACCESS_CONF;
1368 
1369     if (thiscmd->cmd_data) { /* <DirectoryMatch> */
1370 	r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1371     }
1372     else if (!strcmp(cmd->path, "~")) {
1373 	cmd->path = ap_getword_conf(cmd->pool, &arg);
1374 	ap_server_strip_chroot(cmd->path, 1);
1375 	r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1376     }
1377     else {
1378 	/* Ensure that the pathname is canonical */
1379 	cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path);
1380     }
1381 
1382     old_end_token = cmd->end_token;
1383     cmd->end_token = thiscmd->cmd_data ? end_directorymatch_section : end_directory_section;
1384     errmsg = ap_srm_command_loop(cmd, new_dir_conf);
1385     if (errmsg == NULL) {
1386 	errmsg = missing_endsection(cmd, 1);
1387     }
1388     cmd->end_token = old_end_token;
1389     if (errmsg != (thiscmd->cmd_data
1390 		       ? end_directorymatch_section
1391 		   : end_directory_section)) {
1392 	return errmsg;
1393     }
1394 
1395     conf = (core_dir_config *)ap_get_module_config(new_dir_conf, &core_module);
1396     conf->r = r;
1397 
1398     ap_add_per_dir_conf(cmd->server, new_dir_conf);
1399 
1400     if (*arg != '\0') {
1401 	return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1402 			  "> arguments not (yet) supported.", NULL);
1403     }
1404 
1405     cmd->path = old_path;
1406     cmd->override = old_overrides;
1407 
1408     return NULL;
1409 }
1410 
urlsection(cmd_parms * cmd,void * dummy,const char * arg)1411 static const char *urlsection(cmd_parms *cmd, void *dummy, const char *arg)
1412 {
1413     const char *errmsg;
1414     char *endp = strrchr(arg, '>');
1415     int old_overrides = cmd->override;
1416     char *old_path = cmd->path;
1417     core_dir_config *conf;
1418     regex_t *r = NULL;
1419     const char *old_end_token;
1420     const command_rec *thiscmd = cmd->cmd;
1421 
1422     void *new_url_conf = ap_create_per_dir_config(cmd->pool);
1423 
1424     const char *err = ap_check_cmd_context(cmd,
1425 					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1426     if (err != NULL) {
1427         return err;
1428     }
1429 
1430     if (endp == NULL) {
1431 	return unclosed_directive(cmd);
1432     }
1433 
1434     *endp = '\0';
1435 
1436     cmd->path = ap_getword_conf(cmd->pool, &arg);
1437     ap_server_strip_chroot(cmd->path, 0);
1438     cmd->override = OR_ALL|ACCESS_CONF;
1439 
1440     if (thiscmd->cmd_data) { /* <LocationMatch> */
1441 	r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
1442     }
1443     else if (!strcmp(cmd->path, "~")) {
1444 	cmd->path = ap_getword_conf(cmd->pool, &arg);
1445 	ap_server_strip_chroot(cmd->path, 0);
1446 	r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
1447     }
1448 
1449     old_end_token = cmd->end_token;
1450     cmd->end_token = thiscmd->cmd_data ? end_locationmatch_section
1451                                        : end_location_section;
1452     errmsg = ap_srm_command_loop(cmd, new_url_conf);
1453     if (errmsg == NULL) {
1454 	errmsg = missing_endsection(cmd, 1);
1455     }
1456     cmd->end_token = old_end_token;
1457     if (errmsg != (thiscmd->cmd_data
1458 		       ? end_locationmatch_section
1459 		       : end_location_section)) {
1460 	return errmsg;
1461     }
1462 
1463     conf = (core_dir_config *)ap_get_module_config(new_url_conf, &core_module);
1464     conf->d = ap_pstrdup(cmd->pool, cmd->path);	/* No mangling, please */
1465     conf->d_is_fnmatch = ap_is_fnmatch(conf->d) != 0;
1466     conf->r = r;
1467 
1468     ap_add_per_url_conf(cmd->server, new_url_conf);
1469 
1470     if (*arg != '\0') {
1471 	return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1472 			  "> arguments not (yet) supported.", NULL);
1473     }
1474 
1475     cmd->path = old_path;
1476     cmd->override = old_overrides;
1477 
1478     return NULL;
1479 }
1480 
filesection(cmd_parms * cmd,core_dir_config * c,const char * arg)1481 static const char *filesection(cmd_parms *cmd, core_dir_config *c,
1482 			       const char *arg)
1483 {
1484     const char *errmsg;
1485     char *endp = strrchr(arg, '>');
1486     int old_overrides = cmd->override;
1487     char *old_path = cmd->path;
1488     core_dir_config *conf;
1489     regex_t *r = NULL;
1490     const char *old_end_token;
1491     const command_rec *thiscmd = cmd->cmd;
1492 
1493     void *new_file_conf = ap_create_per_dir_config(cmd->pool);
1494 
1495     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_LOCATION);
1496     if (err != NULL) {
1497         return err;
1498     }
1499 
1500     if (endp == NULL) {
1501 	return unclosed_directive(cmd);
1502     }
1503 
1504     *endp = '\0';
1505 
1506     cmd->path = ap_getword_conf(cmd->pool, &arg);
1507     ap_server_strip_chroot(cmd->path, 1);
1508     /* Only if not an .htaccess file */
1509     if (!old_path) {
1510 	cmd->override = OR_ALL|ACCESS_CONF;
1511     }
1512 
1513     if (thiscmd->cmd_data) { /* <FilesMatch> */
1514         r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1515     }
1516     else if (!strcmp(cmd->path, "~")) {
1517 	cmd->path = ap_getword_conf(cmd->pool, &arg);
1518 	ap_server_strip_chroot(cmd->path, 1);
1519 	r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1520     }
1521     else {
1522 	/* Ensure that the pathname is canonical */
1523 	cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path);
1524     }
1525 
1526     old_end_token = cmd->end_token;
1527     cmd->end_token = thiscmd->cmd_data ? end_filesmatch_section : end_files_section;
1528     errmsg = ap_srm_command_loop(cmd, new_file_conf);
1529     if (errmsg == NULL) {
1530 	errmsg = missing_endsection(cmd, 1);
1531     }
1532     cmd->end_token = old_end_token;
1533     if (errmsg != (thiscmd->cmd_data
1534 		       ? end_filesmatch_section
1535 		   : end_files_section)) {
1536 	return errmsg;
1537     }
1538 
1539     conf = (core_dir_config *)ap_get_module_config(new_file_conf,
1540 						   &core_module);
1541     conf->d = cmd->path;
1542     conf->d_is_fnmatch = ap_is_fnmatch(conf->d) != 0;
1543     conf->r = r;
1544 
1545     ap_add_file_conf(c, new_file_conf);
1546 
1547     if (*arg != '\0') {
1548 	return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1549 			  "> arguments not (yet) supported.", NULL);
1550     }
1551 
1552     cmd->path = old_path;
1553     cmd->override = old_overrides;
1554 
1555     return NULL;
1556 }
1557 
1558 /* XXX: NB: Currently, we have no way of checking
1559  * whether <IfModule> sections are closed properly.
1560  * Extra (redundant, unpaired) </IfModule> directives are
1561  * simply silently ignored.
1562  */
end_ifmod(cmd_parms * cmd,void * dummy)1563 static const char *end_ifmod(cmd_parms *cmd, void *dummy)
1564 {
1565     return NULL;
1566 }
1567 
start_ifmod(cmd_parms * cmd,void * dummy,char * arg)1568 static const char *start_ifmod(cmd_parms *cmd, void *dummy, char *arg)
1569 {
1570     char *endp = strrchr(arg, '>');
1571     char l[MAX_STRING_LEN];
1572     int not = (arg[0] == '!');
1573     module *found;
1574     int nest = 1;
1575 
1576     if (endp == NULL) {
1577 	return unclosed_directive(cmd);
1578     }
1579 
1580     *endp = '\0';
1581 
1582     if (not) {
1583         arg++;
1584     }
1585 
1586     found = ap_find_linked_module(arg);
1587 
1588     if ((!not && found) || (not && !found)) {
1589         return NULL;
1590     }
1591 
1592     while (nest && !(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) {
1593         if (!strncasecmp(l, "<IfModule", 9)) {
1594 	    nest++;
1595 	}
1596 	if (!strcasecmp(l, "</IfModule>")) {
1597 	  nest--;
1598 	}
1599     }
1600 
1601     if (nest) {
1602 	cmd->end_token = end_ifmodule_section;
1603 	return missing_endsection(cmd, nest);
1604     }
1605     return NULL;
1606 }
1607 
ap_exists_config_define(char * name)1608 API_EXPORT(int) ap_exists_config_define(char *name)
1609 {
1610     char **defines;
1611     int i;
1612 
1613     defines = (char **)ap_server_config_defines->elts;
1614     for (i = 0; i < ap_server_config_defines->nelts; i++) {
1615         if (strcmp(defines[i], name) == 0) {
1616             return 1;
1617 	}
1618     }
1619     return 0;
1620 }
1621 
end_ifdefine(cmd_parms * cmd,void * dummy)1622 static const char *end_ifdefine(cmd_parms *cmd, void *dummy)
1623 {
1624     return NULL;
1625 }
1626 
start_ifdefine(cmd_parms * cmd,void * dummy,char * arg)1627 static const char *start_ifdefine(cmd_parms *cmd, void *dummy, char *arg)
1628 {
1629     char *endp;
1630     char l[MAX_STRING_LEN];
1631     int defined;
1632     int not = 0;
1633     int nest = 1;
1634 
1635     endp = strrchr(arg, '>');
1636     if (endp == NULL) {
1637 	return unclosed_directive(cmd);
1638     }
1639 
1640     *endp = '\0';
1641 
1642     if (arg[0] == '!') {
1643         not = 1;
1644 	arg++;
1645     }
1646 
1647     defined = ap_exists_config_define(arg);
1648 
1649     if ((!not && defined) || (not && !defined)) {
1650 	return NULL;
1651     }
1652 
1653     while (nest && !(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) {
1654         if (!strncasecmp(l, "<IfDefine", 9)) {
1655 	    nest++;
1656 	}
1657 	if (!strcasecmp(l, "</IfDefine>")) {
1658 	    nest--;
1659 	}
1660     }
1661     if (nest) {
1662 	cmd->end_token = end_ifdefine_section;
1663 	return missing_endsection(cmd, nest);
1664     }
1665     return NULL;
1666 }
1667 
1668 /* httpd.conf commands... beginning with the <VirtualHost> business */
1669 
virtualhost_section(cmd_parms * cmd,void * dummy,char * arg)1670 static const char *virtualhost_section(cmd_parms *cmd, void *dummy, char *arg)
1671 {
1672     server_rec *main_server = cmd->server, *s;
1673     const char *errmsg;
1674     char *endp = strrchr(arg, '>');
1675     pool *p = cmd->pool, *ptemp = cmd->temp_pool;
1676     const char *old_end_token;
1677 
1678     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1679     if (err != NULL) {
1680         return err;
1681     }
1682 
1683     if (endp == NULL) {
1684 	return unclosed_directive(cmd);
1685     }
1686 
1687     *endp = '\0';
1688 
1689     /* FIXME: There's another feature waiting to happen here -- since you
1690 	can now put multiple addresses/names on a single <VirtualHost>
1691 	you might want to use it to group common definitions and then
1692 	define other "subhosts" with their individual differences.  But
1693 	personally I'd rather just do it with a macro preprocessor. -djg */
1694     if (main_server->is_virtual) {
1695 	return "<VirtualHost> doesn't nest!";
1696     }
1697 
1698     errmsg = ap_init_virtual_host(p, arg, main_server, &s);
1699     if (errmsg) {
1700 	return errmsg;
1701     }
1702 
1703     s->next = main_server->next;
1704     main_server->next = s;
1705 
1706     s->defn_name = cmd->config_file->name;
1707     s->defn_line_number = cmd->config_file->line_number;
1708 
1709     old_end_token = cmd->end_token;
1710     cmd->end_token = end_virtualhost_section;
1711     cmd->server = s;
1712     errmsg = ap_srm_command_loop(cmd, s->lookup_defaults);
1713     cmd->server = main_server;
1714     if (errmsg == NULL) {
1715 	errmsg = missing_endsection(cmd, 1);
1716     }
1717     cmd->end_token = old_end_token;
1718 
1719     if (s->srm_confname) {
1720 	ap_process_resource_config(s, s->srm_confname, p, ptemp);
1721     }
1722 
1723     if (s->access_confname) {
1724 	ap_process_resource_config(s, s->access_confname, p, ptemp);
1725     }
1726 
1727     if (errmsg == end_virtualhost_section) {
1728 	return NULL;
1729     }
1730     return errmsg;
1731 }
1732 
set_server_alias(cmd_parms * cmd,void * dummy,const char * arg)1733 static const char *set_server_alias(cmd_parms *cmd, void *dummy,
1734 				    const char *arg)
1735 {
1736     if (!cmd->server->names) {
1737 	return "ServerAlias only used in <VirtualHost>";
1738     }
1739     while (*arg) {
1740 	char **item, *name = ap_getword_conf(cmd->pool, &arg);
1741 	if (ap_is_matchexp(name)) {
1742 	    item = (char **)ap_push_array(cmd->server->wild_names);
1743 	}
1744 	else {
1745 	    item = (char **)ap_push_array(cmd->server->names);
1746 	}
1747 	*item = name;
1748     }
1749     return NULL;
1750 }
1751 
add_module_command(cmd_parms * cmd,void * dummy,char * arg)1752 static const char *add_module_command(cmd_parms *cmd, void *dummy, char *arg)
1753 {
1754     module *modp;
1755     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1756     if (err != NULL) {
1757         return err;
1758     }
1759 
1760     for (modp = top_module; modp; modp = modp->next) {
1761         if (modp->name != NULL && strcmp(modp->name, arg) == 0) {
1762             ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, cmd->server,
1763                           "module %s is already added, skipping", arg);
1764             return NULL;
1765         }
1766     }
1767 
1768     if (!ap_add_named_module(arg)) {
1769 	return ap_pstrcat(cmd->pool, "Cannot add module via name '", arg,
1770 			  "': not in list of loaded modules", NULL);
1771     }
1772     return NULL;
1773 }
1774 
clear_module_list_command(cmd_parms * cmd,void * dummy)1775 static const char *clear_module_list_command(cmd_parms *cmd, void *dummy)
1776 {
1777     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1778     if (err != NULL) {
1779         return err;
1780     }
1781 
1782     ap_clear_module_list();
1783     return NULL;
1784 }
1785 
set_server_string_slot(cmd_parms * cmd,void * dummy,char * arg)1786 static const char *set_server_string_slot(cmd_parms *cmd, void *dummy,
1787 					  char *arg)
1788 {
1789     /* This one's pretty generic... */
1790 
1791     int offset = (int)(long)cmd->info;
1792     char *struct_ptr = (char *)cmd->server;
1793 
1794     const char *err = ap_check_cmd_context(cmd,
1795 					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1796     if (err != NULL) {
1797         return err;
1798     }
1799 
1800     *(char **)(struct_ptr + offset) = arg;
1801     return NULL;
1802 }
1803 
server_type(cmd_parms * cmd,void * dummy,char * arg)1804 static const char *server_type(cmd_parms *cmd, void *dummy, char *arg)
1805 {
1806     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1807     if (err != NULL) {
1808         return err;
1809     }
1810 
1811     if (!strcasecmp(arg, "inetd")) {
1812         ap_standalone = 0;
1813     }
1814     else if (!strcasecmp(arg, "standalone")) {
1815         ap_standalone = 1;
1816     }
1817     else {
1818         return "ServerType must be either 'inetd' or 'standalone'";
1819     }
1820 
1821     return NULL;
1822 }
1823 
server_port(cmd_parms * cmd,void * dummy,char * arg)1824 static const char *server_port(cmd_parms *cmd, void *dummy, char *arg)
1825 {
1826     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1827     int port;
1828 
1829     if (err != NULL) {
1830 	return err;
1831     }
1832     port = atoi(arg);
1833     if (port <= 0 || port >= 65536) { /* 65536 == 1<<16 */
1834 	return ap_pstrcat(cmd->temp_pool, "The port number \"", arg,
1835 			  "\" is outside the appropriate range "
1836 			  "(i.e., 1..65535).", NULL);
1837     }
1838     cmd->server->port = port;
1839     return NULL;
1840 }
1841 
set_signature_flag(cmd_parms * cmd,core_dir_config * d,char * arg)1842 static const char *set_signature_flag(cmd_parms *cmd, core_dir_config *d,
1843 				      char *arg)
1844 {
1845     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1846     if (err != NULL) {
1847         return err;
1848     }
1849 
1850     if (strcasecmp(arg, "On") == 0) {
1851 	d->server_signature = srv_sig_on;
1852     }
1853     else if (strcasecmp(arg, "Off") == 0) {
1854         d->server_signature = srv_sig_off;
1855     }
1856     else if (strcasecmp(arg, "EMail") == 0) {
1857 	d->server_signature = srv_sig_withmail;
1858     }
1859     else {
1860 	return "ServerSignature: use one of: off | on | email";
1861     }
1862     return NULL;
1863 }
1864 
set_send_buffer_size(cmd_parms * cmd,void * dummy,char * arg)1865 static const char *set_send_buffer_size(cmd_parms *cmd, void *dummy, char *arg)
1866 {
1867     int s = atoi(arg);
1868     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1869     if (err != NULL) {
1870         return err;
1871     }
1872 
1873     if (s < 512 && s != 0) {
1874         return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
1875     }
1876     cmd->server->send_buffer_size = s;
1877     return NULL;
1878 }
1879 
set_user(cmd_parms * cmd,void * dummy,char * arg)1880 static const char *set_user(cmd_parms *cmd, void *dummy, char *arg)
1881 {
1882     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1883     if (err != NULL) {
1884         return err;
1885     }
1886 
1887     /*
1888      * This is, again, tricky. on restarts, we cannot use uname2id.
1889      * keep the old settings for the main server.
1890      * barf out on user directives in <VirtualHost> sections.
1891      */
1892 
1893     if (!cmd->server->is_virtual) {
1894 	if (!ap_server_is_chrooted()) {
1895 	    ap_user_name = arg;
1896 	    ap_user_id = ap_uname2id(arg);
1897 	}
1898 	cmd->server->server_uid = ap_user_id;
1899     }
1900     else {
1901         if (ap_suexec_enabled) {
1902 	    if (ap_server_is_chrooted()) {
1903 		fprintf(stderr, "cannot look up uids once chrooted. Thus, User "
1904 		    "directives inside <VirtualHost> and restarts aren't "
1905 		    "possible together. Please stop httpd and start a new "
1906 		    "one\n");
1907 		exit(1);
1908 	    } else
1909 		cmd->server->server_uid = ap_uname2id(arg);
1910 	}
1911 	else {
1912 	    cmd->server->server_uid = ap_user_id;
1913 	    fprintf(stderr,
1914 		    "Warning: User directive in <VirtualHost> "
1915 		    "requires SUEXEC wrapper.\n");
1916 	}
1917     }
1918 #if !defined (BIG_SECURITY_HOLE)
1919     if (cmd->server->server_uid == 0) {
1920 	fprintf(stderr,
1921 		"Error:\tApache has not been designed to serve pages while\n"
1922 		"\trunning as root.  There are known race conditions that\n"
1923 		"\twill allow any local user to read any file on the system.\n"
1924 		"\tIf you still desire to serve pages as root then\n"
1925 		"\tadd -DBIG_SECURITY_HOLE to the EXTRA_CFLAGS line in your\n"
1926 		"\tsrc/Configuration file and rebuild the server.  It is\n"
1927 		"\tstrongly suggested that you instead modify the User\n"
1928 		"\tdirective in your httpd.conf file to list a non-root\n"
1929 		"\tuser.\n");
1930 	exit (1);
1931     }
1932 #endif
1933 
1934     return NULL;
1935 }
1936 
set_group(cmd_parms * cmd,void * dummy,char * arg)1937 static const char *set_group(cmd_parms *cmd, void *dummy, char *arg)
1938 {
1939     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1940     if (err != NULL) {
1941         return err;
1942     }
1943 
1944     if (!cmd->server->is_virtual) {
1945 	if (!ap_server_is_chrooted()) {
1946 	    ap_group_id = ap_gname2id(arg);
1947 	}
1948 	cmd->server->server_gid = ap_group_id;
1949     }
1950     else {
1951         if (ap_suexec_enabled) {
1952 	    if (ap_server_is_chrooted()) {
1953 		fprintf(stderr, "cannot look up gids once chrooted. Thus, Group"
1954 		    " directives inside <VirtualHost> and restarts aren't "
1955 		    "possible together. Please stop httpd and start a new "
1956 		    "one\n");
1957 		exit(1);
1958 	    } else
1959 		cmd->server->server_gid = ap_gname2id(arg);
1960 	}
1961 	else {
1962 	    cmd->server->server_gid = ap_group_id;
1963 	    fprintf(stderr,
1964 		    "Warning: Group directive in <VirtualHost> requires "
1965 		    "SUEXEC wrapper.\n");
1966 	}
1967     }
1968 
1969     return NULL;
1970 }
1971 
set_server_root(cmd_parms * cmd,void * dummy,char * arg)1972 static const char *set_server_root(cmd_parms *cmd, void *dummy, char *arg)
1973 {
1974     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1975 
1976     if (err != NULL) {
1977         return err;
1978     }
1979 
1980     arg = ap_os_canonical_filename(cmd->pool, arg);
1981 
1982     /*
1983      * This is a bit tricky. On startup we are not chrooted here.
1984      * On restarts (graceful or not) we are (unless we're in unsecure mode).
1985      * if we would strip off the chroot prefix, nothing (not even "/")
1986      * would last.
1987      * it's pointless to test wether ServerRoot is a directory if we are
1988      * already chrooted into that.
1989      * Of course it's impossible to change ServerRoot without a full restart.
1990      * should we abort with an error if ap_server_root != arg?
1991      */
1992 
1993     if (!ap_server_is_chrooted()) {
1994 	if (!ap_is_directory(arg)) {
1995 	    return "ServerRoot must be a valid directory";
1996 	}
1997 	/* ServerRoot is never '/' terminated */
1998 	while (strlen(ap_server_root) > 1 && ap_server_root[strlen(ap_server_root)-1] == '/')
1999 	    ap_server_root[strlen(ap_server_root)-1] = '\0';
2000 	ap_cpystrn(ap_server_root, arg, sizeof(ap_server_root));
2001     }
2002     return NULL;
2003 }
2004 
set_timeout(cmd_parms * cmd,void * dummy,char * arg)2005 static const char *set_timeout(cmd_parms *cmd, void *dummy, char *arg)
2006 {
2007     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2008     if (err != NULL) {
2009         return err;
2010     }
2011 
2012     cmd->server->timeout = atoi(arg);
2013     return NULL;
2014 }
2015 
set_keep_alive_timeout(cmd_parms * cmd,void * dummy,char * arg)2016 static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy,
2017 					  char *arg)
2018 {
2019     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2020     if (err != NULL) {
2021         return err;
2022     }
2023 
2024     cmd->server->keep_alive_timeout = atoi(arg);
2025     return NULL;
2026 }
2027 
set_keep_alive(cmd_parms * cmd,void * dummy,char * arg)2028 static const char *set_keep_alive(cmd_parms *cmd, void *dummy, char *arg)
2029 {
2030     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2031     if (err != NULL) {
2032         return err;
2033     }
2034 
2035     /* We've changed it to On/Off, but used to use numbers
2036      * so we accept anything but "Off" or "0" as "On"
2037      */
2038     if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) {
2039 	cmd->server->keep_alive = 0;
2040     }
2041     else {
2042 	cmd->server->keep_alive = 1;
2043     }
2044     return NULL;
2045 }
2046 
set_keep_alive_max(cmd_parms * cmd,void * dummy,char * arg)2047 static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy, char *arg)
2048 {
2049     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2050     if (err != NULL) {
2051         return err;
2052     }
2053 
2054     cmd->server->keep_alive_max = atoi(arg);
2055     return NULL;
2056 }
2057 
set_pidfile(cmd_parms * cmd,void * dummy,char * arg)2058 static const char *set_pidfile(cmd_parms *cmd, void *dummy, char *arg)
2059 {
2060     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2061     if (err != NULL) {
2062         return err;
2063     }
2064 
2065     if (cmd->server->is_virtual) {
2066 	return "PidFile directive not allowed in <VirtualHost>";
2067     }
2068     ap_pid_fname = arg;
2069     return NULL;
2070 }
2071 
set_scoreboard(cmd_parms * cmd,void * dummy,char * arg)2072 static const char *set_scoreboard(cmd_parms *cmd, void *dummy, char *arg)
2073 {
2074     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2075     if (err != NULL) {
2076         return err;
2077     }
2078 
2079     ap_scoreboard_fname = arg;
2080     return NULL;
2081 }
2082 
set_lockfile(cmd_parms * cmd,void * dummy,char * arg)2083 static const char *set_lockfile(cmd_parms *cmd, void *dummy, char *arg)
2084 {
2085     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2086     if (err != NULL) {
2087         return err;
2088     }
2089 
2090     ap_lock_fname = arg;
2091     return NULL;
2092 }
2093 
set_idcheck(cmd_parms * cmd,core_dir_config * d,int arg)2094 static const char *set_idcheck(cmd_parms *cmd, core_dir_config *d, int arg)
2095 {
2096     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2097     if (err != NULL) {
2098         return err;
2099     }
2100 
2101     d->do_rfc1413 = arg != 0;
2102     return NULL;
2103 }
2104 
set_hostname_lookups(cmd_parms * cmd,core_dir_config * d,char * arg)2105 static const char *set_hostname_lookups(cmd_parms *cmd, core_dir_config *d,
2106 					char *arg)
2107 {
2108     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2109     if (err != NULL) {
2110         return err;
2111     }
2112 
2113     if (!strcasecmp(arg, "on")) {
2114 	d->hostname_lookups = HOSTNAME_LOOKUP_ON;
2115     }
2116     else if (!strcasecmp(arg, "off")) {
2117 	d->hostname_lookups = HOSTNAME_LOOKUP_OFF;
2118     }
2119     else if (!strcasecmp(arg, "double")) {
2120 	d->hostname_lookups = HOSTNAME_LOOKUP_DOUBLE;
2121     }
2122     else {
2123 	return "parameter must be 'on', 'off', or 'double'";
2124     }
2125     return NULL;
2126 }
2127 
set_serverpath(cmd_parms * cmd,void * dummy,char * arg)2128 static const char *set_serverpath(cmd_parms *cmd, void *dummy, char *arg)
2129 {
2130     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2131     if (err != NULL) {
2132         return err;
2133     }
2134 
2135     cmd->server->path = arg;
2136     cmd->server->pathlen = strlen(arg);
2137     return NULL;
2138 }
2139 
set_content_md5(cmd_parms * cmd,core_dir_config * d,int arg)2140 static const char *set_content_md5(cmd_parms *cmd, core_dir_config *d, int arg)
2141 {
2142     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2143     if (err != NULL) {
2144         return err;
2145     }
2146 
2147     d->content_md5 = arg != 0;
2148     return NULL;
2149 }
2150 
set_use_canonical_name(cmd_parms * cmd,core_dir_config * d,char * arg)2151 static const char *set_use_canonical_name(cmd_parms *cmd, core_dir_config *d,
2152 					  char *arg)
2153 {
2154     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2155     if (err != NULL) {
2156 	return err;
2157     }
2158 
2159     if (strcasecmp(arg, "on") == 0) {
2160         d->use_canonical_name = USE_CANONICAL_NAME_ON;
2161     }
2162     else if (strcasecmp(arg, "off") == 0) {
2163         d->use_canonical_name = USE_CANONICAL_NAME_OFF;
2164     }
2165     else if (strcasecmp(arg, "dns") == 0) {
2166         d->use_canonical_name = USE_CANONICAL_NAME_DNS;
2167     }
2168     else {
2169         return "parameter must be 'on', 'off', or 'dns'";
2170     }
2171     return NULL;
2172 }
2173 
set_daemons_to_start(cmd_parms * cmd,void * dummy,char * arg)2174 static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, char *arg)
2175 {
2176     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2177     if (err != NULL) {
2178         return err;
2179     }
2180 
2181     ap_daemons_to_start = atoi(arg);
2182     return NULL;
2183 }
2184 
set_min_free_servers(cmd_parms * cmd,void * dummy,char * arg)2185 static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, char *arg)
2186 {
2187     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2188     if (err != NULL) {
2189         return err;
2190     }
2191 
2192     ap_daemons_min_free = atoi(arg);
2193     if (ap_daemons_min_free <= 0) {
2194        fprintf(stderr, "WARNING: detected MinSpareServers set to non-positive.\n");
2195        fprintf(stderr, "Resetting to 1 to avoid almost certain Apache failure.\n");
2196        fprintf(stderr, "Please read the documentation.\n");
2197        ap_daemons_min_free = 1;
2198     }
2199 
2200     return NULL;
2201 }
2202 
set_max_free_servers(cmd_parms * cmd,void * dummy,char * arg)2203 static const char *set_max_free_servers(cmd_parms *cmd, void *dummy, char *arg)
2204 {
2205     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2206     if (err != NULL) {
2207         return err;
2208     }
2209 
2210     ap_daemons_max_free = atoi(arg);
2211     return NULL;
2212 }
2213 
set_server_limit(cmd_parms * cmd,void * dummy,char * arg)2214 static const char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg)
2215 {
2216     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2217     if (err != NULL) {
2218         return err;
2219     }
2220 
2221     ap_daemons_limit = atoi(arg);
2222     if (ap_daemons_limit > HARD_SERVER_LIMIT) {
2223        fprintf(stderr, "WARNING: MaxClients of %d exceeds compile time limit "
2224            "of %d servers,\n", ap_daemons_limit, HARD_SERVER_LIMIT);
2225        fprintf(stderr, " lowering MaxClients to %d.  To increase, please "
2226            "see the\n", HARD_SERVER_LIMIT);
2227        fprintf(stderr, " HARD_SERVER_LIMIT define in src/include/httpd.h.\n");
2228        ap_daemons_limit = HARD_SERVER_LIMIT;
2229     }
2230     else if (ap_daemons_limit < 1) {
2231 	fprintf(stderr, "WARNING: Require MaxClients > 0, setting to 1\n");
2232 	ap_daemons_limit = 1;
2233     }
2234     return NULL;
2235 }
2236 
set_child_rl_cpu(cmd_parms * cmd,void * dummy,char * arg)2237 static const char *set_child_rl_cpu(cmd_parms *cmd, void *dummy, char *arg)
2238 {
2239     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2240     if (err != NULL) {
2241         return err;
2242     }
2243 
2244     ap_max_cpu_per_child = atoi(arg);
2245     return NULL;
2246 }
2247 
set_child_rl_data(cmd_parms * cmd,void * dummy,char * arg)2248 static const char *set_child_rl_data(cmd_parms *cmd, void *dummy, char *arg)
2249 {
2250     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2251     if (err != NULL) {
2252         return err;
2253     }
2254 
2255     ap_max_data_per_child = atoi(arg);
2256     return NULL;
2257 }
2258 
set_child_rl_nofile(cmd_parms * cmd,void * dummy,char * arg)2259 static const char *set_child_rl_nofile(cmd_parms *cmd, void *dummy, char *arg)
2260 {
2261     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2262     if (err != NULL) {
2263         return err;
2264     }
2265 
2266     ap_max_nofile_per_child = atoi(arg);
2267     return NULL;
2268 }
2269 
set_child_rl_rss(cmd_parms * cmd,void * dummy,char * arg)2270 static const char *set_child_rl_rss(cmd_parms *cmd, void *dummy, char *arg)
2271 {
2272     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2273     if (err != NULL) {
2274         return err;
2275     }
2276 
2277     ap_max_rss_per_child = atoi(arg);
2278     return NULL;
2279 }
2280 
set_child_rl_stack(cmd_parms * cmd,void * dummy,char * arg)2281 static const char *set_child_rl_stack(cmd_parms *cmd, void *dummy, char *arg)
2282 {
2283     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2284     if (err != NULL) {
2285         return err;
2286     }
2287 
2288     ap_max_stack_per_child = atoi(arg);
2289     return NULL;
2290 }
2291 
2292 #ifdef RLIMIT_TIME
set_child_rl_time(cmd_parms * cmd,void * dummy,char * arg)2293 static const char *set_child_rl_time(cmd_parms *cmd, void *dummy, char *arg)
2294 {
2295     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2296     if (err != NULL) {
2297         return err;
2298     }
2299 
2300     ap_max_time_per_child = atoi(arg);
2301     return NULL;
2302 }
2303 #endif
2304 
set_max_requests(cmd_parms * cmd,void * dummy,char * arg)2305 static const char *set_max_requests(cmd_parms *cmd, void *dummy, char *arg)
2306 {
2307     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2308     if (err != NULL) {
2309         return err;
2310     }
2311 
2312     ap_max_requests_per_child = atoi(arg);
2313     return NULL;
2314 }
2315 
set_threads(cmd_parms * cmd,void * dummy,char * arg)2316 static const char *set_threads(cmd_parms *cmd, void *dummy, char *arg) {
2317     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2318     if (err != NULL) {
2319         return err;
2320     }
2321 
2322     ap_threads_per_child = atoi(arg);
2323     if (ap_threads_per_child > HARD_SERVER_LIMIT) {
2324         fprintf(stderr, "WARNING: ThreadsPerChild of %d exceeds compile time limit "
2325                 "of %d threads,\n", ap_threads_per_child, HARD_SERVER_LIMIT);
2326         fprintf(stderr, " lowering ThreadsPerChild to %d.  To increase, please "
2327                 "see the\n", HARD_SERVER_LIMIT);
2328         fprintf(stderr, " HARD_SERVER_LIMIT define in src/include/httpd.h.\n");
2329         ap_threads_per_child = HARD_SERVER_LIMIT;
2330     }
2331     else if (ap_threads_per_child < 1) {
2332 	fprintf(stderr, "WARNING: Require ThreadsPerChild > 0, setting to 1\n");
2333 	ap_threads_per_child = 1;
2334     }
2335 
2336     return NULL;
2337 }
2338 
set_excess_requests(cmd_parms * cmd,void * dummy,char * arg)2339 static const char *set_excess_requests(cmd_parms *cmd, void *dummy, char *arg)
2340 {
2341     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2342     if (err != NULL) {
2343         return err;
2344     }
2345 
2346     ap_excess_requests_per_child = atoi(arg);
2347     return NULL;
2348 }
2349 
2350 
set_rlimit(cmd_parms * cmd,struct rlimit ** plimit,const char * arg,const char * arg2,int type)2351 static void set_rlimit(cmd_parms *cmd, struct rlimit **plimit, const char *arg,
2352                        const char * arg2, int type)
2353 {
2354     char *str;
2355     struct rlimit *limit;
2356     /* If your platform doesn't define rlim_t then typedef it in ap_config.h */
2357     rlim_t cur = 0;
2358     rlim_t max = 0;
2359 
2360     *plimit = (struct rlimit *)ap_pcalloc(cmd->pool, sizeof(**plimit));
2361     limit = *plimit;
2362     if ((getrlimit(type, limit)) != 0)	{
2363 	*plimit = NULL;
2364 	ap_log_error(APLOG_MARK, APLOG_ERR, cmd->server,
2365 		     "%s: getrlimit failed", cmd->cmd->name);
2366 	return;
2367     }
2368 
2369     if ((str = ap_getword_conf(cmd->pool, &arg))) {
2370 	if (!strcasecmp(str, "max")) {
2371 	    cur = limit->rlim_max;
2372 	}
2373 	else {
2374 	    cur = atol(str);
2375 	}
2376     }
2377     else {
2378 	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, cmd->server,
2379 		     "Invalid parameters for %s", cmd->cmd->name);
2380 	return;
2381     }
2382 
2383     if (arg2 && (str = ap_getword_conf(cmd->pool, &arg2))) {
2384 	max = atol(str);
2385     }
2386 
2387     /* if we aren't running as root, cannot increase max */
2388     if (geteuid()) {
2389 	limit->rlim_cur = cur;
2390 	if (max) {
2391 	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, cmd->server,
2392 			 "Must be uid 0 to raise maximum %s", cmd->cmd->name);
2393 	}
2394     }
2395     else {
2396         if (cur) {
2397 	    limit->rlim_cur = cur;
2398 	}
2399         if (max) {
2400 	    limit->rlim_max = max;
2401 	}
2402     }
2403 }
2404 
set_limit_cpu(cmd_parms * cmd,core_dir_config * conf,char * arg,char * arg2)2405 static const char *set_limit_cpu(cmd_parms *cmd, core_dir_config *conf,
2406 				 char *arg, char *arg2)
2407 {
2408     set_rlimit(cmd, &conf->limit_cpu, arg, arg2, RLIMIT_CPU);
2409     return NULL;
2410 }
2411 
2412 #ifdef RLIMIT_TIME
set_limit_time(cmd_parms * cmd,core_dir_config * conf,char * arg,char * arg2)2413 static const char *set_limit_time(cmd_parms *cmd, core_dir_config *conf,
2414 				 char *arg, char *arg2)
2415 {
2416     set_rlimit(cmd, &conf->limit_time, arg, arg2, RLIMIT_TIME);
2417     return NULL;
2418 }
2419 #endif
2420 
set_limit_mem(cmd_parms * cmd,core_dir_config * conf,char * arg,char * arg2)2421 static const char *set_limit_mem(cmd_parms *cmd, core_dir_config *conf,
2422 				 char *arg, char * arg2)
2423 {
2424     set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_DATA);
2425     return NULL;
2426 }
2427 
set_limit_nproc(cmd_parms * cmd,core_dir_config * conf,char * arg,char * arg2)2428 static const char *set_limit_nproc(cmd_parms *cmd, core_dir_config *conf,
2429 				   char *arg, char * arg2)
2430 {
2431     set_rlimit(cmd, &conf->limit_nproc, arg, arg2, RLIMIT_NPROC);
2432     return NULL;
2433 }
2434 
set_limit_nofile(cmd_parms * cmd,core_dir_config * conf,char * arg,char * arg2)2435 static const char *set_limit_nofile(cmd_parms *cmd, core_dir_config *conf,
2436 				   char *arg, char * arg2)
2437 {
2438     set_rlimit(cmd, &conf->limit_nofile, arg, arg2, RLIMIT_NOFILE);
2439     return NULL;
2440 }
2441 
set_bind_address(cmd_parms * cmd,void * dummy,char * arg)2442 static const char *set_bind_address(cmd_parms *cmd, void *dummy, char *arg)
2443 {
2444     struct sockaddr *sa;
2445     size_t sa_len;
2446     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2447     if (err != NULL) {
2448         return err;
2449     }
2450 
2451     if (strcmp(arg, "*") == 0)
2452       arg = NULL;
2453 
2454     sa = ap_get_virthost_addr(arg, NULL);
2455 #ifdef HAVE_SOCKADDR_LEN
2456     sa_len = sa->sa_len;
2457 #else
2458     sa_len = SA_LEN(sa);
2459 #endif
2460     memcpy(&ap_bind_address, &sa, sa_len);
2461     return NULL;
2462 }
2463 
2464 /* Though the AcceptFilter functionality is not available across
2465  * all platforms - we still allow the config directive to appear
2466  * on all platforms and do intentionally not tie it to the compile
2467  * time flag SO_ACCEPTFILTER. This makes configuration files significantly
2468  * more portable; especially as an <IfModule http_core.c> or some
2469  * other construct is not possible.
2470  */
set_acceptfilter(cmd_parms * cmd,void * dummy,int flag)2471 static const char *set_acceptfilter(cmd_parms *cmd, void *dummy, int flag)
2472 {
2473     return NULL;
2474 }
2475 
set_listener(cmd_parms * cmd,void * dummy,char * h,char * p)2476 static const char *set_listener(cmd_parms *cmd, void *dummy, char *h, char *p)
2477 {
2478     listen_rec *new;
2479     char *host, *port;
2480     struct addrinfo hints, *res;
2481     int error;
2482 
2483     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2484     if (err != NULL) {
2485         return err;
2486     }
2487 
2488     host = port = NULL;
2489     if (!p) {
2490 	port = strrchr(h, ':');
2491 	if (port != NULL) {
2492 	    if (port == h) {
2493 		return "Missing IP address";
2494 	    }
2495 	    else if (port[1] == '\0') {
2496 		return "Address must end in :<port-number>";
2497 	    }
2498 	    *(port++) = '\0';
2499 	    if (*h)
2500 		host = h;
2501 	} else {
2502 	    host = NULL;
2503 	    port = h;
2504 	}
2505     } else {
2506 	host = h;
2507 	port = p;
2508     }
2509 
2510     if (host && strcmp(host, "*") == 0)
2511 	host = NULL;
2512 
2513     new = ap_pcalloc(cmd->pool, sizeof(listen_rec));
2514 
2515     memset(&hints, 0, sizeof(hints));
2516     hints.ai_family = host ? PF_UNSPEC : ap_default_family;
2517     hints.ai_flags = AI_PASSIVE;
2518     hints.ai_socktype = SOCK_STREAM;
2519     error = getaddrinfo(host, port, &hints, &res);
2520     if (error || !res) {
2521 	fprintf(stderr, "could not resolve ");
2522 	if (host)
2523 	    fprintf(stderr, "host \"%s\" ", host);
2524 	if (port)
2525 	    fprintf(stderr, "port \"%s\" ", port);
2526 	fprintf(stderr, "--- %s\n", gai_strerror(error));
2527 	exit(1);
2528     }
2529     if (res->ai_next) {
2530         if (host)
2531 	    fprintf(stderr, "host \"%s\" ", host);
2532 	if (port)
2533 	    fprintf(stderr, "port \"%s\" ", port);
2534 	fprintf(stderr, "resolved to multiple addresses, ambiguous.\n");
2535 	exit(1);
2536     }
2537 
2538     memcpy(&new->local_addr, res->ai_addr, res->ai_addrlen);
2539 
2540     new->fd = -1;
2541     new->used = 0;
2542     new->next = ap_listeners;
2543     ap_listeners = new;
2544     return NULL;
2545 }
2546 
set_listenbacklog(cmd_parms * cmd,void * dummy,char * arg)2547 static const char *set_listenbacklog(cmd_parms *cmd, void *dummy, char *arg)
2548 {
2549     int b;
2550 
2551     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2552     if (err != NULL) {
2553         return err;
2554     }
2555 
2556     b = atoi(arg);
2557     if (b < 1) {
2558         return "ListenBacklog must be > 0";
2559     }
2560     ap_listenbacklog = b;
2561     return NULL;
2562 }
2563 
set_coredumpdir(cmd_parms * cmd,void * dummy,char * arg)2564 static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, char *arg)
2565 {
2566     struct stat finfo;
2567     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2568     if (err != NULL) {
2569         return err;
2570     }
2571 
2572     arg = ap_server_root_relative(cmd->pool, arg);
2573     if ((stat(arg, &finfo) == -1) || !S_ISDIR(finfo.st_mode)) {
2574 	return ap_pstrcat(cmd->pool, "CoreDumpDirectory ", arg,
2575 			  " does not exist or is not a directory", NULL);
2576     }
2577     ap_cpystrn(ap_coredump_dir, arg, sizeof(ap_coredump_dir));
2578     return NULL;
2579 }
2580 
include_config(cmd_parms * cmd,void * dummy,char * name)2581 static const char *include_config (cmd_parms *cmd, void *dummy, char *name)
2582 {
2583     name = ap_server_root_relative(cmd->pool, name);
2584 
2585     ap_process_resource_config(cmd->server, name, cmd->pool, cmd->temp_pool);
2586 
2587     return NULL;
2588 }
2589 
set_loglevel(cmd_parms * cmd,void * dummy,const char * arg)2590 static const char *set_loglevel(cmd_parms *cmd, void *dummy, const char *arg)
2591 {
2592     char *str;
2593 
2594     const char *err = ap_check_cmd_context(cmd,
2595 					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2596     if (err != NULL) {
2597         return err;
2598     }
2599 
2600     if ((str = ap_getword_conf(cmd->pool, &arg))) {
2601         if (!strcasecmp(str, "emerg")) {
2602 	    cmd->server->loglevel = APLOG_EMERG;
2603 	}
2604 	else if (!strcasecmp(str, "alert")) {
2605 	    cmd->server->loglevel = APLOG_ALERT;
2606 	}
2607 	else if (!strcasecmp(str, "crit")) {
2608 	    cmd->server->loglevel = APLOG_CRIT;
2609 	}
2610 	else if (!strcasecmp(str, "error")) {
2611 	    cmd->server->loglevel = APLOG_ERR;
2612 	}
2613 	else if (!strcasecmp(str, "warn")) {
2614 	    cmd->server->loglevel = APLOG_WARNING;
2615 	}
2616 	else if (!strcasecmp(str, "notice")) {
2617 	    cmd->server->loglevel = APLOG_NOTICE;
2618 	}
2619 	else if (!strcasecmp(str, "info")) {
2620 	    cmd->server->loglevel = APLOG_INFO;
2621 	}
2622 	else if (!strcasecmp(str, "debug")) {
2623 	    cmd->server->loglevel = APLOG_DEBUG;
2624 	}
2625 	else {
2626             return "LogLevel requires level keyword: one of "
2627 	           "emerg/alert/crit/error/warn/notice/info/debug";
2628 	}
2629     }
2630     else {
2631         return "LogLevel requires level keyword";
2632     }
2633 
2634     return NULL;
2635 }
2636 
ap_psignature(const char * prefix,request_rec * r)2637 API_EXPORT(const char *) ap_psignature(const char *prefix, request_rec *r)
2638 {
2639     char sport[20];
2640     core_dir_config *conf;
2641 
2642     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
2643 						   &core_module);
2644     if ((conf->server_signature == srv_sig_off)
2645 	    || (conf->server_signature == srv_sig_unset)) {
2646 	return "";
2647     }
2648 
2649     snprintf(sport, sizeof sport, "%u", (unsigned) ap_get_server_port(r));
2650 
2651     if (conf->server_signature == srv_sig_withmail) {
2652 	return ap_pstrcat(r->pool, prefix, "<address>" SERVER_BASEVERSION
2653 			  " Server at <a href=\"mailto:",
2654 			  r->server->server_admin, "\">",
2655 			  ap_escape_html(r->pool, ap_get_server_name(r)),
2656                           "</a> Port ", sport,
2657 			  "</address>\n", NULL);
2658     }
2659     return ap_pstrcat(r->pool, prefix, "<address>" SERVER_BASEVERSION
2660 		      " Server at ",
2661                       ap_escape_html(r->pool, ap_get_server_name(r)),
2662                       " Port ", sport,
2663 		      "</address>\n", NULL);
2664 }
2665 
2666 /*
2667  * Load an authorisation realm into our location configuration, applying the
2668  * usual rules that apply to realms.
2669  */
set_authname(cmd_parms * cmd,void * mconfig,char * word1)2670 static const char *set_authname(cmd_parms *cmd, void *mconfig, char *word1)
2671 {
2672     core_dir_config *aconfig = (core_dir_config *)mconfig;
2673 
2674     aconfig->ap_auth_name = ap_escape_quotes(cmd->pool, word1);
2675     return NULL;
2676 }
2677 
2678 /*
2679  * Load an authorisation nonce into our location configuration, and
2680  * force it to be in the 0-9/A-Z realm.
2681  */
set_authnonce(cmd_parms * cmd,void * mconfig,char * word1)2682 static const char *set_authnonce (cmd_parms *cmd, void *mconfig, char *word1)
2683 {
2684     core_dir_config *aconfig = (core_dir_config *)mconfig;
2685     size_t i;
2686 
2687     aconfig->ap_auth_nonce = ap_escape_quotes(cmd->pool, word1);
2688 
2689     if (strlen(aconfig->ap_auth_nonce) > 510)
2690        return "AuthDigestRealmSeed length limited to 510 chars for browser compatibility";
2691 
2692     for(i=0;i<strlen(aconfig->ap_auth_nonce );i++)
2693        if (!ap_isalnum(aconfig->ap_auth_nonce [i]))
2694          return "AuthDigestRealmSeed limited to 0-9 and A-Z range for browser compatibility";
2695 
2696     return NULL;
2697 }
2698 
2699 
set_protocol_req_check(cmd_parms * cmd,core_dir_config * d,int arg)2700 static const char *set_protocol_req_check(cmd_parms *cmd,
2701                                               core_dir_config *d, int arg)
2702 {
2703     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2704     if (err != NULL) {
2705         return err;
2706     }
2707 
2708     ap_protocol_req_check = arg != 0;
2709     return NULL;
2710 }
2711 
set_change_shmem_uid(cmd_parms * cmd,core_dir_config * d,int arg)2712 static const char *set_change_shmem_uid(cmd_parms *cmd,
2713                                               core_dir_config *d, int arg)
2714 {
2715     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2716     if (err != NULL) {
2717         return err;
2718     }
2719 
2720     ap_change_shmem_uid = arg != 0;
2721     return NULL;
2722 }
2723 
2724 /*
2725  * Handle a request to include the server's OS platform in the Server
2726  * response header field (the ServerTokens directive).  Unfortunately
2727  * this requires a new global in order to communicate the setting back to
2728  * http_main so it can insert the information in the right place in the
2729  * string.
2730  */
set_serv_tokens(cmd_parms * cmd,void * dummy,char * arg)2731 static const char *set_serv_tokens(cmd_parms *cmd, void *dummy, char *arg)
2732 {
2733     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2734     if (err != NULL) {
2735         return err;
2736     }
2737 
2738     if (!strcasecmp(arg, "OS")) {
2739         ap_server_tokens = SrvTk_OS;
2740     }
2741     else if (!strcasecmp(arg, "Min") || !strcasecmp(arg, "Minimal")) {
2742         ap_server_tokens = SrvTk_MIN;
2743     }
2744     else if (!strcasecmp(arg, "Full")) {
2745         ap_server_tokens = SrvTk_FULL;
2746     }
2747     else if (!strcasecmp(arg, "Prod") || !strcasecmp(arg, "ProductOnly")) {
2748         ap_server_tokens = SrvTk_PRODUCT_ONLY;
2749     }
2750     else {
2751 	return ap_pstrcat(cmd->pool, "Unrecognised ServerTokens keyword: ",
2752 			  arg, NULL);
2753     }
2754     return NULL;
2755 }
2756 
set_limit_req_line(cmd_parms * cmd,void * dummy,char * arg)2757 static const char *set_limit_req_line(cmd_parms *cmd, void *dummy, char *arg)
2758 {
2759     const char *err = ap_check_cmd_context(cmd,
2760                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2761     int lim;
2762 
2763     if (err != NULL) {
2764         return err;
2765     }
2766     lim = atoi(arg);
2767     if (lim < 0) {
2768         return ap_pstrcat(cmd->temp_pool, "LimitRequestLine \"", arg,
2769                           "\" must be a non-negative integer", NULL);
2770     }
2771     if (lim > DEFAULT_LIMIT_REQUEST_LINE) {
2772         return ap_psprintf(cmd->temp_pool, "LimitRequestLine \"%s\" "
2773                            "must not exceed the precompiled maximum of %d",
2774                            arg, DEFAULT_LIMIT_REQUEST_LINE);
2775     }
2776     cmd->server->limit_req_line = lim;
2777     return NULL;
2778 }
2779 
set_limit_req_fieldsize(cmd_parms * cmd,void * dummy,char * arg)2780 static const char *set_limit_req_fieldsize(cmd_parms *cmd, void *dummy,
2781                                            char *arg)
2782 {
2783     const char *err = ap_check_cmd_context(cmd,
2784                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2785     int lim;
2786 
2787     if (err != NULL) {
2788         return err;
2789     }
2790     lim = atoi(arg);
2791     if (lim < 0) {
2792         return ap_pstrcat(cmd->temp_pool, "LimitRequestFieldsize \"", arg,
2793                           "\" must be a non-negative integer (0 = no limit)",
2794                           NULL);
2795     }
2796     if (lim > DEFAULT_LIMIT_REQUEST_FIELDSIZE) {
2797         return ap_psprintf(cmd->temp_pool, "LimitRequestFieldsize \"%s\" "
2798                           "must not exceed the precompiled maximum of %d",
2799                            arg, DEFAULT_LIMIT_REQUEST_FIELDSIZE);
2800     }
2801     cmd->server->limit_req_fieldsize = lim;
2802     return NULL;
2803 }
2804 
set_limit_req_fields(cmd_parms * cmd,void * dummy,char * arg)2805 static const char *set_limit_req_fields(cmd_parms *cmd, void *dummy, char *arg)
2806 {
2807     const char *err = ap_check_cmd_context(cmd,
2808                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2809     int lim;
2810 
2811     if (err != NULL) {
2812         return err;
2813     }
2814     lim = atoi(arg);
2815     if (lim < 0) {
2816         return ap_pstrcat(cmd->temp_pool, "LimitRequestFields \"", arg,
2817                           "\" must be a non-negative integer (0 = no limit)",
2818                           NULL);
2819     }
2820     cmd->server->limit_req_fields = lim;
2821     return NULL;
2822 }
2823 
set_limit_req_body(cmd_parms * cmd,core_dir_config * conf,char * arg)2824 static const char *set_limit_req_body(cmd_parms *cmd, core_dir_config *conf,
2825                                       char *arg)
2826 {
2827     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2828     if (err != NULL) {
2829         return err;
2830     }
2831 
2832     /* WTF: If strtoul is not portable, then write a replacement.
2833      *      Instead we have an idiotic define in httpd.h that prevents
2834      *      it from being used even when it is available. Sheesh.
2835      */
2836     conf->limit_req_body = (unsigned long)ap_strtol(arg, (char **)NULL, 10);
2837     return NULL;
2838 }
2839 
set_cgi_command_args(cmd_parms * cmd,void * mconfig,int arg)2840 static const char *set_cgi_command_args(cmd_parms *cmd,
2841                                               void *mconfig,
2842                                               int arg)
2843 {
2844     core_dir_config *cfg = (core_dir_config *)mconfig;
2845     cfg->cgi_command_args = arg ? AP_FLAG_ON : AP_FLAG_OFF;
2846     return NULL;
2847 }
2848 
2849 /*
2850  * Note what data should be used when forming file ETag values.
2851  * It would be nicer to do this as an ITERATE, but then we couldn't
2852  * remember the +/- state properly.
2853  */
set_etag_bits(cmd_parms * cmd,void * mconfig,const char * args_p)2854 static const char *set_etag_bits(cmd_parms *cmd, void *mconfig,
2855                                  const char *args_p)
2856 {
2857     core_dir_config *cfg;
2858     etag_components_t bit;
2859     char action;
2860     char *token;
2861     const char *args;
2862     int valid;
2863     int first;
2864     int explicit;
2865 
2866     cfg = (core_dir_config *) mconfig;
2867 
2868     args = args_p;
2869     first = 1;
2870     explicit = 0;
2871     while (args[0] != '\0') {
2872         action = '*';
2873         bit = ETAG_UNSET;
2874         valid = 1;
2875         token = ap_getword_conf(cmd->pool, &args);
2876         if ((*token == '+') || (*token == '-')) {
2877             action = *token;
2878             token++;
2879         }
2880         else {
2881             /*
2882              * The occurrence of an absolute setting wipes
2883              * out any previous relative ones.  The first such
2884              * occurrence forgets any inherited ones, too.
2885              */
2886             if (first) {
2887                 cfg->etag_bits = ETAG_UNSET;
2888                 cfg->etag_add = ETAG_UNSET;
2889                 cfg->etag_remove = ETAG_UNSET;
2890                 first = 0;
2891             }
2892         }
2893 
2894         if (strcasecmp(token, "None") == 0) {
2895             if (action != '*') {
2896                 valid = 0;
2897             }
2898             else {
2899                 cfg->etag_bits = bit = ETAG_NONE;
2900                 explicit = 1;
2901             }
2902         }
2903         else if (strcasecmp(token, "All") == 0) {
2904             if (action != '*') {
2905                 valid = 0;
2906             }
2907             else {
2908                 explicit = 1;
2909                 cfg->etag_bits = bit = ETAG_ALL;
2910             }
2911         }
2912         else if (strcasecmp(token, "Size") == 0) {
2913             bit = ETAG_SIZE;
2914         }
2915         else if ((strcasecmp(token, "LMTime") == 0)
2916                  || (strcasecmp(token, "MTime") == 0)
2917                  || (strcasecmp(token, "LastModified") == 0)) {
2918             bit = ETAG_MTIME;
2919         }
2920         else if (strcasecmp(token, "INode") == 0) {
2921             bit = ETAG_INODE;
2922         }
2923         else {
2924             return ap_pstrcat(cmd->pool, "Unknown keyword '",
2925                               token, "' for ", cmd->cmd->name,
2926                               " directive", NULL);
2927         }
2928 
2929         if (! valid) {
2930             return ap_pstrcat(cmd->pool, cmd->cmd->name, " keyword '",
2931                               token, "' cannot be used with '+' or '-'",
2932                               NULL);
2933         }
2934 
2935         if (action == '+') {
2936             /*
2937              * Make sure it's in the 'add' list and absent from the
2938              * 'subtract' list.
2939              */
2940             cfg->etag_add |= bit;
2941             cfg->etag_remove &= (~ bit);
2942         }
2943         else if (action == '-') {
2944             cfg->etag_remove |= bit;
2945             cfg->etag_add &= (~ bit);
2946         }
2947         else {
2948             /*
2949              * Non-relative values wipe out any + or - values
2950              * accumulated so far.
2951              */
2952             cfg->etag_bits |= bit;
2953             cfg->etag_add = ETAG_UNSET;
2954             cfg->etag_remove = ETAG_UNSET;
2955             explicit = 1;
2956         }
2957     }
2958 
2959     /*
2960      * Any setting at all will clear the 'None' and 'Unset' bits.
2961      */
2962 
2963     if (cfg->etag_add != ETAG_UNSET) {
2964         cfg->etag_add &= (~ ETAG_UNSET);
2965     }
2966     if (cfg->etag_remove != ETAG_UNSET) {
2967         cfg->etag_remove &= (~ ETAG_UNSET);
2968     }
2969     if (explicit) {
2970         cfg->etag_bits &= (~ ETAG_UNSET);
2971         if ((cfg->etag_bits & ETAG_NONE) != ETAG_NONE) {
2972             cfg->etag_bits &= (~ ETAG_NONE);
2973         }
2974     }
2975     return NULL;
2976 }
2977 
set_recursion_limit(cmd_parms * cmd,void * dummy,const char * arg1,const char * arg2)2978 static const char *set_recursion_limit(cmd_parms *cmd, void *dummy,
2979                                        const char *arg1, const char *arg2)
2980 {
2981     core_server_config *conf = ap_get_module_config(cmd->server->module_config,
2982                                                     &core_module);
2983     int limit = atoi(arg1);
2984 
2985     if (limit < 0) {
2986         return "The redirect recursion limit cannot be less than zero.";
2987     }
2988     if (limit && limit < 4) {
2989         ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, cmd->server,
2990                      "Limiting internal redirects to very low numbers may "
2991                      "cause normal requests to fail.");
2992     }
2993 
2994     conf->redirect_limit = limit;
2995 
2996     if (arg2) {
2997         limit = atoi(arg2);
2998 
2999         if (limit < 0) {
3000             return "The subrequest recursion limit cannot be less than zero.";
3001         }
3002         if (limit && limit < 4) {
3003             ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, cmd->server,
3004                          "Limiting the subrequest depth to a very low level may"
3005                          " cause normal requests to fail.");
3006         }
3007     }
3008 
3009     conf->subreq_limit = limit;
3010     conf->recursion_limit_set = 1;
3011 
3012     return NULL;
3013 }
3014 
log_backtrace(const request_rec * r)3015 static void log_backtrace(const request_rec *r)
3016 {
3017     const request_rec *top = r;
3018 
3019     ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
3020                   "r->uri = %s", r->uri ? r->uri : "(unexpectedly NULL)");
3021 
3022     while (top && (top->prev || top->main)) {
3023         if (top->prev) {
3024             top = top->prev;
3025             ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
3026                           "redirected from r->uri = %s",
3027                           top->uri ? top->uri : "(unexpectedly NULL)");
3028         }
3029 
3030         if (!top->prev && top->main) {
3031             top = top->main;
3032             ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
3033                           "subrequested from r->uri = %s",
3034                           top->uri ? top->uri : "(unexpectedly NULL)");
3035         }
3036     }
3037 }
3038 
3039 /*
3040  * check whether redirect limit is reached
3041  */
ap_is_recursion_limit_exceeded(const request_rec * r)3042 API_EXPORT(int) ap_is_recursion_limit_exceeded(const request_rec *r)
3043 {
3044     core_server_config *conf = ap_get_module_config(r->server->module_config,
3045                                                     &core_module);
3046     const request_rec *top = r;
3047     int redirects = 0, subreqs = 0;
3048     int rlimit = conf->recursion_limit_set
3049                  ? conf->redirect_limit
3050                  : AP_DEFAULT_MAX_INTERNAL_REDIRECTS;
3051     int slimit = conf->recursion_limit_set
3052                  ? conf->subreq_limit
3053                  : AP_DEFAULT_MAX_SUBREQ_DEPTH;
3054 
3055     /* fast exit (unlimited) */
3056     if (!rlimit && !slimit) {
3057         return 0;
3058     }
3059 
3060     while (top->prev || top->main) {
3061         if (top->prev) {
3062             if (rlimit && ++redirects >= rlimit) {
3063                 /* uuh, too much. */
3064                 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
3065                               "Request exceeded the limit of %d internal "
3066                               "redirects due to probable configuration error. "
3067                               "Use 'LimitInternalRecursion' to increase the "
3068                               "limit if necessary. Use 'LogLevel debug' to get "
3069                               "a backtrace.", rlimit);
3070 
3071                 /* post backtrace */
3072                 log_backtrace(r);
3073 
3074                 /* return failure */
3075                 return 1;
3076             }
3077 
3078             top = top->prev;
3079         }
3080 
3081         if (!top->prev && top->main) {
3082             if (slimit && ++subreqs >= slimit) {
3083                 /* uuh, too much. */
3084                 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
3085                               "Request exceeded the limit of %d subrequest "
3086                               "nesting levels due to probable confguration "
3087                               "error. Use 'LimitInternalRecursion' to increase "
3088                               "the limit if necessary. Use 'LogLevel debug' to "
3089                               "get a backtrace.", slimit);
3090 
3091                 /* post backtrace */
3092                 log_backtrace(r);
3093 
3094                 /* return failure */
3095                 return 1;
3096             }
3097 
3098             top = top->main;
3099         }
3100     }
3101 
3102     /* recursion state: ok */
3103     return 0;
3104 }
3105 
3106 /* Note --- ErrorDocument will now work from .htaccess files.
3107  * The AllowOverride of Fileinfo allows webmasters to turn it off
3108  */
3109 
3110 static const command_rec core_cmds[] = {
3111 
3112 /* Old access config file commands */
3113 
3114 { "<Directory", dirsection, NULL, RSRC_CONF, RAW_ARGS,
3115   "Container for directives affecting resources located in the specified "
3116   "directories" },
3117 { end_directory_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
3118   "Marks end of <Directory>" },
3119 { "<Location", urlsection, NULL, RSRC_CONF, RAW_ARGS,
3120   "Container for directives affecting resources accessed through the "
3121   "specified URL paths" },
3122 { end_location_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
3123   "Marks end of <Location>" },
3124 { "<VirtualHost", virtualhost_section, NULL, RSRC_CONF, RAW_ARGS,
3125   "Container to map directives to a particular virtual host, takes one or "
3126   "more host addresses" },
3127 { end_virtualhost_section, end_nested_section, NULL, RSRC_CONF, NO_ARGS,
3128   "Marks end of <VirtualHost>" },
3129 { "<Files", filesection, NULL, OR_ALL, RAW_ARGS, "Container for directives "
3130   "affecting files matching specified patterns" },
3131 { end_files_section, end_nested_section, NULL, OR_ALL, NO_ARGS,
3132   "Marks end of <Files>" },
3133 { "<Limit", ap_limit_section, NULL, OR_ALL, RAW_ARGS, "Container for "
3134   "authentication directives when accessed using specified HTTP methods" },
3135 { "</Limit>", endlimit_section, NULL, OR_ALL, NO_ARGS,
3136   "Marks end of <Limit>" },
3137 { "<LimitExcept", ap_limit_section, (void*)1, OR_ALL, RAW_ARGS,
3138   "Container for authentication directives to be applied when any HTTP "
3139   "method other than those specified is used to access the resource" },
3140 { "</LimitExcept>", endlimit_section, (void*)1, OR_ALL, NO_ARGS,
3141   "Marks end of <LimitExcept>" },
3142 { "<IfModule", start_ifmod, NULL, OR_ALL, TAKE1,
3143   "Container for directives based on existance of specified modules" },
3144 { end_ifmodule_section, end_ifmod, NULL, OR_ALL, NO_ARGS,
3145   "Marks end of <IfModule>" },
3146 { "<IfDefine", start_ifdefine, NULL, OR_ALL, TAKE1,
3147   "Container for directives based on existance of command line defines" },
3148 { end_ifdefine_section, end_ifdefine, NULL, OR_ALL, NO_ARGS,
3149   "Marks end of <IfDefine>" },
3150 { "<DirectoryMatch", dirsection, (void*)1, RSRC_CONF, RAW_ARGS,
3151   "Container for directives affecting resources located in the "
3152   "specified directories" },
3153 { end_directorymatch_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
3154   "Marks end of <DirectoryMatch>" },
3155 { "<LocationMatch", urlsection, (void*)1, RSRC_CONF, RAW_ARGS,
3156   "Container for directives affecting resources accessed through the "
3157   "specified URL paths" },
3158 { end_locationmatch_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
3159   "Marks end of <LocationMatch>" },
3160 { "<FilesMatch", filesection, (void*)1, OR_ALL, RAW_ARGS,
3161   "Container for directives affecting files matching specified patterns" },
3162 { end_filesmatch_section, end_nested_section, NULL, OR_ALL, NO_ARGS,
3163   "Marks end of <FilesMatch>" },
3164 { "AuthType", ap_set_string_slot,
3165   (void*)XtOffsetOf(core_dir_config, ap_auth_type), OR_AUTHCFG, TAKE1,
3166   "An HTTP authorization type (e.g., \"Basic\")" },
3167 { "AuthName", set_authname, NULL, OR_AUTHCFG, TAKE1,
3168   "The authentication realm (e.g. \"Members Only\")" },
3169 { "AuthDigestRealmSeed", set_authnonce, NULL, OR_AUTHCFG, TAKE1,
3170   "An authentication token which should be different for each logical realm. "\
3171   "A random value or the servers IP may be a good choise.\n" },
3172 { "Require", require, NULL, OR_AUTHCFG, RAW_ARGS,
3173   "Selects which authenticated users or groups may access a protected space" },
3174 { "Satisfy", satisfy, NULL, OR_AUTHCFG, TAKE1,
3175   "access policy if both allow and require used ('all' or 'any')" },
3176 #ifdef GPROF
3177 { "GprofDir", set_gprof_dir, NULL, RSRC_CONF, TAKE1,
3178   "Directory to plop gmon.out files" },
3179 #endif
3180 { "AddDefaultCharset", set_add_default_charset, NULL, OR_FILEINFO,
3181   TAKE1, "The name of the default charset to add to any Content-Type without one or 'Off' to disable" },
3182 
3183 /* Old resource config file commands */
3184 
3185 { "AccessFileName", set_access_name, NULL, RSRC_CONF, RAW_ARGS,
3186   "Name(s) of per-directory config files (default: .htaccess)" },
3187 { "DocumentRoot", set_document_root, NULL, RSRC_CONF, TAKE1,
3188   "Root directory of the document tree"  },
3189 { "ErrorDocument", set_error_document, NULL, OR_FILEINFO, RAW_ARGS,
3190   "Change responses for HTTP errors" },
3191 { "AllowOverride", set_override, NULL, ACCESS_CONF, RAW_ARGS,
3192   "Controls what groups of directives can be configured by per-directory "
3193   "config files" },
3194 { "Options", set_options, NULL, OR_OPTIONS, RAW_ARGS,
3195   "Set a number of attributes for a given directory" },
3196 { "DefaultType", ap_set_string_slot,
3197   (void*)XtOffsetOf (core_dir_config, ap_default_type),
3198   OR_FILEINFO, TAKE1, "the default MIME type for untypable files" },
3199 
3200 /* Old server config file commands */
3201 
3202 { "ServerType", server_type, NULL, RSRC_CONF, TAKE1,
3203   "'inetd' or 'standalone'"},
3204 { "Port", server_port, NULL, RSRC_CONF, TAKE1, "A TCP port number"},
3205 { "HostnameLookups", set_hostname_lookups, NULL, ACCESS_CONF|RSRC_CONF, TAKE1,
3206   "\"on\" to enable, \"off\" to disable reverse DNS lookups, or \"double\" to "
3207   "enable double-reverse DNS lookups" },
3208 { "User", set_user, NULL, RSRC_CONF, TAKE1,
3209   "Effective user id for this server"},
3210 { "Group", set_group, NULL, RSRC_CONF, TAKE1,
3211   "Effective group id for this server"},
3212 { "ServerAdmin", set_server_string_slot,
3213   (void *)XtOffsetOf (server_rec, server_admin), RSRC_CONF, TAKE1,
3214   "The email address of the server administrator" },
3215 { "ServerName", set_server_string_slot,
3216   (void *)XtOffsetOf (server_rec, server_hostname), RSRC_CONF, TAKE1,
3217   "The hostname of the server" },
3218 { "ServerSignature", set_signature_flag, NULL, OR_ALL, TAKE1,
3219   "En-/disable server signature (on|off|email)" },
3220 { "ServerRoot", set_server_root, NULL, RSRC_CONF, TAKE1,
3221   "Common directory of server-related files (logs, confs, etc.)" },
3222 { "ErrorLog", set_server_string_slot,
3223   (void *)XtOffsetOf (server_rec, error_fname), RSRC_CONF, TAKE1,
3224   "The filename of the error log" },
3225 { "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1,
3226     "A file for logging the server process ID"},
3227 { "ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, TAKE1,
3228     "A file for Apache to maintain runtime process management information"},
3229 { "LockFile", set_lockfile, NULL, RSRC_CONF, TAKE1,
3230     "The lockfile used when Apache needs to lock the accept() call"},
3231 { "AccessConfig", set_server_string_slot,
3232   (void *)XtOffsetOf (server_rec, access_confname), RSRC_CONF, TAKE1,
3233   "The filename of the access config file" },
3234 { "ResourceConfig", set_server_string_slot,
3235   (void *)XtOffsetOf (server_rec, srm_confname), RSRC_CONF, TAKE1,
3236   "The filename of the resource config file" },
3237 { "ServerAlias", set_server_alias, NULL, RSRC_CONF, RAW_ARGS,
3238   "A name or names alternately used to access the server" },
3239 { "ServerPath", set_serverpath, NULL, RSRC_CONF, TAKE1,
3240   "The pathname the server can be reached at" },
3241 { "Timeout", set_timeout, NULL, RSRC_CONF, TAKE1, "Timeout duration (sec)" },
3242 { "KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF, TAKE1,
3243   "Keep-Alive timeout duration (sec)"},
3244 { "MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF, TAKE1,
3245   "Maximum number of Keep-Alive requests per connection, or 0 for infinite" },
3246 { "KeepAlive", set_keep_alive, NULL, RSRC_CONF, TAKE1,
3247   "Whether persistent connections should be On or Off" },
3248 { "IdentityCheck", set_idcheck, NULL, RSRC_CONF|ACCESS_CONF, FLAG,
3249   "Enable identd (RFC 1413) user lookups - SLOW" },
3250 { "ContentDigest", set_content_md5, NULL, OR_OPTIONS,
3251   FLAG, "whether or not to send a Content-MD5 header with each request" },
3252 { "UseCanonicalName", set_use_canonical_name, NULL,
3253   RSRC_CONF|ACCESS_CONF, TAKE1,
3254   "How to work out the ServerName : Port when constructing URLs" },
3255 { "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1,
3256   "Number of child processes launched at server startup" },
3257 { "MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, TAKE1,
3258   "Minimum number of idle children, to handle request spikes" },
3259 { "MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1,
3260   "Maximum number of idle children" },
3261 { "MaxServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1,
3262   "Deprecated equivalent to MaxSpareServers" },
3263 { "ServersSafetyLimit", set_server_limit, NULL, RSRC_CONF, TAKE1,
3264   "Deprecated equivalent to MaxClients" },
3265 { "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1,
3266   "Maximum number of children alive at the same time" },
3267 { "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1,
3268   "Maximum number of requests a particular child serves before dying." },
3269 { "MaxCPUPerChild", set_child_rl_cpu, NULL, RSRC_CONF, TAKE1,
3270   "Maximum amount of CPU time a child can use (rlimit)." },
3271 { "MaxDATAPerChild", set_child_rl_data, NULL, RSRC_CONF, TAKE1,
3272   "Maximum size of the data segment for a child process (rlimit)." },
3273 { "MaxNOFILEPerChild", set_child_rl_nofile, NULL, RSRC_CONF, TAKE1,
3274   "Maximum number of open file descriptors a child can have (rlimit)." },
3275 { "MaxRSSPerChild", set_child_rl_rss, NULL, RSRC_CONF, TAKE1,
3276   "Maximum amount of physical memory a child can use (rlimit)." },
3277 { "MaxSTACKPerChild", set_child_rl_stack, NULL, RSRC_CONF, TAKE1,
3278   "Maximum amount of stack space a child can use (rlimit)." },
3279 #ifdef RLIMIT_TIME
3280 { "MaxTIMEPerChild", set_child_rl_time, NULL, RSRC_CONF, TAKE1,
3281   "Maximum lifetime (in seconds) of a child (rlimit)." },
3282 #endif
3283 { "RLimitCPU",
3284   set_limit_cpu, (void*)XtOffsetOf(core_dir_config, limit_cpu),
3285   OR_ALL, TAKE12, "Soft/hard limits for max CPU usage in seconds" },
3286 { "RLimitMEM",
3287   set_limit_mem, (void*)XtOffsetOf(core_dir_config, limit_mem),
3288   OR_ALL, TAKE12, "Soft/hard limits for max memory usage per process" },
3289 { "RLimitNPROC",
3290   set_limit_nproc, (void*)XtOffsetOf(core_dir_config, limit_nproc),
3291    OR_ALL, TAKE12, "soft/hard limits for max number of processes per uid" },
3292 { "RLimitNOFILE",
3293   set_limit_nofile, (void*)XtOffsetOf(core_dir_config, limit_nofile),
3294    OR_ALL, TAKE12, "soft/hard limits for max number of files per process" },
3295 #ifdef RLIMIT_TIME
3296 { "RLimitTIME",
3297   set_limit_time, (void*)XtOffsetOf(core_dir_config, limit_time),
3298   OR_ALL, TAKE12, "Soft/hard limits for max human time in seconds" },
3299 #endif
3300 { "BindAddress", set_bind_address, NULL, RSRC_CONF, TAKE1,
3301   "'*', a numeric IP address, or the name of a host with a unique IP address"},
3302 { "Listen", set_listener, NULL, RSRC_CONF, TAKE12,
3303   "A port number or a numeric IP address and a port number"},
3304 { "SendBufferSize", set_send_buffer_size, NULL, RSRC_CONF, TAKE1,
3305   "Send buffer size in bytes"},
3306 { "AddModule", add_module_command, NULL, RSRC_CONF, ITERATE,
3307   "The name of a module" },
3308 { "ClearModuleList", clear_module_list_command, NULL, RSRC_CONF, NO_ARGS,
3309   NULL },
3310 { "ThreadsPerChild", set_threads, NULL, RSRC_CONF, TAKE1,
3311   "Number of threads a child creates" },
3312 { "ExcessRequestsPerChild", set_excess_requests, NULL, RSRC_CONF, TAKE1,
3313   "Maximum number of requests a particular child serves after it is ready "
3314   "to die." },
3315 { "ListenBacklog", set_listenbacklog, NULL, RSRC_CONF, TAKE1,
3316   "Maximum length of the queue of pending connections, as used by listen(2)" },
3317 { "AcceptFilter", set_acceptfilter, NULL, RSRC_CONF, FLAG,
3318   "Switch AcceptFiltering on/off (default is "
3319 	"on"
3320 	")."
3321 	"This feature is currently not compiled in; so this directive "
3322 	"is ignored."
3323    },
3324 { "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1,
3325   "The location of the directory Apache changes to before dumping core" },
3326 { "Include", include_config, NULL, (RSRC_CONF | ACCESS_CONF), TAKE1,
3327   "Name of the config file to be included" },
3328 { "LogLevel", set_loglevel, NULL, RSRC_CONF, TAKE1,
3329   "Level of verbosity in error logging" },
3330 { "NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF, TAKE12,
3331   "A numeric IP address:port, or the name of a host" },
3332 { "CGICommandArgs", set_cgi_command_args, NULL, OR_OPTIONS, FLAG,
3333   "Allow or Disallow CGI requests to pass args on the command line" },
3334 { "ServerTokens", set_serv_tokens, NULL, RSRC_CONF, TAKE1,
3335   "Tokens displayed in the Server: header - Min[imal], OS, Prod[uctOnly], Full" },
3336 { "LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF, TAKE1,
3337   "Limit on maximum size of an HTTP request line"},
3338 { "LimitRequestFieldsize", set_limit_req_fieldsize, NULL, RSRC_CONF, TAKE1,
3339   "Limit on maximum size of an HTTP request header field"},
3340 { "LimitRequestFields", set_limit_req_fields, NULL, RSRC_CONF, TAKE1,
3341   "Limit (0 = unlimited) on max number of header fields in a request message"},
3342 { "LimitRequestBody", set_limit_req_body,
3343   (void*)XtOffsetOf(core_dir_config, limit_req_body),
3344   OR_ALL, TAKE1,
3345   "Limit (in bytes) on maximum size of request message body" },
3346 { "ProtocolReqCheck", set_protocol_req_check, NULL, RSRC_CONF, FLAG,
3347   "Enable strict checking of Protocol type in requests" },
3348 { "ShmemUIDisUser", set_change_shmem_uid, NULL, RSRC_CONF, FLAG,
3349   "Enable the setting of SysV shared memory scoreboard uid/gid to User/Group" },
3350 { "AcceptMutex", set_accept_mutex, NULL, RSRC_CONF, TAKE1,
3351   "Serialized Accept Mutex; the methods "
3352     "'sysvsem' "
3353     "'flock' "
3354     "are compiled in"
3355 },
3356 
3357 { "FileETag", set_etag_bits, NULL, OR_FILEINFO, RAW_ARGS,
3358   "Specify components used to construct a file's ETag"},
3359 
3360 { "LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF, TAKE12,
3361   "maximum recursion depth of internal redirects and subrequests"},
3362 
3363 { NULL }
3364 };
3365 
3366 /*****************************************************************
3367  *
3368  * Core handlers for various phases of server operation...
3369  */
3370 
core_translate(request_rec * r)3371 static int core_translate(request_rec *r)
3372 {
3373     void *sconf = r->server->module_config;
3374     core_server_config *conf = ap_get_module_config(sconf, &core_module);
3375 
3376     if (r->proxyreq != NOT_PROXY) {
3377         return HTTP_FORBIDDEN;
3378     }
3379     if ((r->uri[0] != '/') && strcmp(r->uri, "*")) {
3380 	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
3381 		     "Invalid URI in request %s", r->the_request);
3382 	return BAD_REQUEST;
3383     }
3384 
3385     if (r->server->path
3386 	&& !strncmp(r->uri, r->server->path, r->server->pathlen)
3387 	&& (r->server->path[r->server->pathlen - 1] == '/'
3388 	    || r->uri[r->server->pathlen] == '/'
3389 	    || r->uri[r->server->pathlen] == '\0')) {
3390         r->filename = ap_pstrcat(r->pool, conf->ap_document_root,
3391 				 (r->uri + r->server->pathlen), NULL);
3392     }
3393     else {
3394 	/*
3395          * Make sure that we do not mess up the translation by adding two
3396          * /'s in a row.  This happens under windows when the document
3397          * root ends with a /
3398          */
3399         if ((conf->ap_document_root[strlen(conf->ap_document_root)-1] == '/')
3400 	    && (*(r->uri) == '/')) {
3401 	    r->filename = ap_pstrcat(r->pool, conf->ap_document_root, r->uri+1,
3402 				     NULL);
3403 	}
3404 	else {
3405 	    r->filename = ap_pstrcat(r->pool, conf->ap_document_root, r->uri,
3406 				     NULL);
3407 	}
3408     }
3409 
3410     return OK;
3411 }
3412 
do_nothing(request_rec * r)3413 static int do_nothing(request_rec *r) { return OK; }
3414 
3415 struct mmap_rec {
3416     void *mm;
3417     size_t length;
3418 };
3419 
mmap_cleanup(void * mmv)3420 static void mmap_cleanup(void *mmv)
3421 {
3422     struct mmap_rec *mmd = mmv;
3423 
3424     if (munmap(mmd->mm, mmd->length) == -1) {
3425         ap_log_error(APLOG_MARK, APLOG_ERR, NULL,
3426                      "Failed to munmap memory of length %ld at 0x%lx",
3427                      (long) mmd->length, (long) mmd->mm);
3428     }
3429 }
3430 
3431 /*
3432  * Default handler for MIME types without other handlers.  Only GET
3433  * and OPTIONS at this point... anyone who wants to write a generic
3434  * handler for PUT or POST is free to do so, but it seems unwise to provide
3435  * any defaults yet... So, for now, we assume that this will always be
3436  * the last handler called and return 405 or 501.
3437  */
3438 
default_handler(request_rec * r)3439 static int default_handler(request_rec *r)
3440 {
3441     core_dir_config *d =
3442       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
3443     int rangestatus, errstatus;
3444     FILE *f;
3445     caddr_t mm;
3446 
3447     /* This handler has no use for a request body (yet), but we still
3448      * need to read and discard it if the client sent one.
3449      */
3450     if ((errstatus = ap_discard_request_body(r)) != OK) {
3451         return errstatus;
3452     }
3453 
3454     r->allowed |= (1 << M_GET) | (1 << M_OPTIONS);
3455 
3456     if (r->method_number == M_INVALID) {
3457 	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
3458 		    "Invalid method in request %s",
3459 		    ap_escape_logitem(r->pool, r->the_request));
3460 	return NOT_IMPLEMENTED;
3461     }
3462     if (r->method_number == M_OPTIONS) {
3463         return ap_send_http_options(r);
3464     }
3465     if (r->method_number == M_PUT) {
3466         return METHOD_NOT_ALLOWED;
3467     }
3468 
3469     if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) {
3470 	ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
3471 		      "File does not exist: %s",r->path_info ?
3472 		      ap_pstrcat(r->pool, r->filename, r->path_info, NULL)
3473 		      : r->filename);
3474 	return HTTP_NOT_FOUND;
3475     }
3476     if (r->method_number != M_GET) {
3477         return METHOD_NOT_ALLOWED;
3478     }
3479 
3480     f = ap_pfopen(r->pool, r->filename, "r");
3481 
3482     if (f == NULL) {
3483         ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
3484 		     "file permissions deny server access: %s", r->filename);
3485         return FORBIDDEN;
3486     }
3487 
3488     ap_update_mtime(r, r->finfo.st_mtime);
3489     ap_set_last_modified(r);
3490     ap_set_etag(r);
3491     ap_table_setn(r->headers_out, "Accept-Ranges", "bytes");
3492     if (((errstatus = ap_meets_conditions(r)) != OK)
3493 	|| (errstatus = ap_set_content_length(r, r->finfo.st_size))) {
3494         return errstatus;
3495     }
3496 
3497     ap_block_alarms();
3498     if ((r->finfo.st_size >= MMAP_THRESHOLD)
3499 	&& (r->finfo.st_size < MMAP_LIMIT)
3500 	&& (!r->header_only || (d->content_md5 & 1))) {
3501 	/* we need to protect ourselves in case we die while we've got the
3502  	 * file mmapped */
3503 	mm = mmap(NULL, r->finfo.st_size, PROT_READ, MAP_PRIVATE,
3504 		  fileno(f), 0);
3505 	if (mm == (caddr_t)-1) {
3506 	    ap_log_rerror(APLOG_MARK, APLOG_CRIT, r,
3507 			 "default_handler: mmap failed: %s", r->filename);
3508 	}
3509     }
3510     else {
3511 	mm = (caddr_t)-1;
3512     }
3513 
3514     if (mm == (caddr_t)-1) {
3515 	ap_unblock_alarms();
3516 
3517 	if (d->content_md5 & 1) {
3518 	    ap_table_setn(r->headers_out, "Content-MD5",
3519 			  ap_md5digest(r->pool, f));
3520 	}
3521 
3522 	rangestatus = ap_set_byterange(r);
3523 
3524 	ap_send_http_header(r);
3525 
3526 	if (!r->header_only) {
3527 	    if (!rangestatus) {
3528 		ap_send_fd(f, r);
3529 	    }
3530 	    else {
3531 		long offset, length;
3532 		while (ap_each_byterange(r, &offset, &length)) {
3533 		    /*
3534 		     * Non zero returns are more portable than checking
3535 		     * for a return of -1.
3536 		     */
3537 		    if (fseek(f, offset, SEEK_SET)) {
3538 			ap_log_error(APLOG_MARK, APLOG_ERR, r->server,
3539 			      "Failed to fseek for byterange (%ld, %ld): %s",
3540 			      offset, length, r->filename);
3541 		    }
3542 		    else {
3543 			ap_send_fd_length(f, r, length);
3544 		    }
3545 		}
3546 	    }
3547 	}
3548 
3549     }
3550     else {
3551 	struct mmap_rec *mmd;
3552 
3553 	mmd = ap_palloc(r->pool, sizeof(*mmd));
3554 	mmd->mm = mm;
3555 	mmd->length = r->finfo.st_size;
3556 	ap_register_cleanup(r->pool, (void *)mmd, mmap_cleanup, mmap_cleanup);
3557 	ap_unblock_alarms();
3558 
3559 	if (d->content_md5 & 1) {
3560 	    AP_MD5_CTX context;
3561 
3562 	    ap_MD5Init(&context);
3563 	    ap_MD5Update(&context, (void *)mm, (unsigned int)r->finfo.st_size);
3564 	    ap_table_setn(r->headers_out, "Content-MD5",
3565 			  ap_md5contextTo64(r->pool, &context));
3566 	}
3567 
3568 	rangestatus = ap_set_byterange(r);
3569 	ap_send_http_header(r);
3570 
3571 	if (!r->header_only) {
3572 	    if (!rangestatus) {
3573 		ap_send_mmap(mm, r, 0, r->finfo.st_size);
3574 	    }
3575 	    else {
3576 		long offset, length;
3577 		while (ap_each_byterange(r, &offset, &length)) {
3578 		    ap_send_mmap(mm, r, offset, length);
3579 		}
3580 	    }
3581 	}
3582     }
3583 
3584     ap_pfclose(r->pool, f);
3585     return OK;
3586 }
3587 
3588 static const handler_rec core_handlers[] = {
3589 { "*/*", default_handler },
3590 { "default-handler", default_handler },
3591 { NULL, NULL }
3592 };
3593 
3594 API_VAR_EXPORT module core_module = {
3595     STANDARD_MODULE_STUFF,
3596     NULL,			/* initializer */
3597     create_core_dir_config,	/* create per-directory config structure */
3598     merge_core_dir_configs,	/* merge per-directory config structures */
3599     create_core_server_config,	/* create per-server config structure */
3600     merge_core_server_configs,	/* merge per-server config structures */
3601     core_cmds,			/* command table */
3602     core_handlers,		/* handlers */
3603     core_translate,		/* translate_handler */
3604     NULL,			/* check_user_id */
3605     NULL,			/* check auth */
3606     do_nothing,			/* check access */
3607     do_nothing,			/* type_checker */
3608     NULL,			/* pre-run fixups */
3609     NULL,			/* logger */
3610     NULL,			/* header parser */
3611     NULL,			/* child_init */
3612     NULL,			/* child_exit */
3613     NULL			/* post_read_request */
3614 };
3615