]> granicus.if.org Git - apache/blob - server/core.c
correction to r1031776, retain OR_UNSET with default AllowOverride None
[apache] / server / core.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr.h"
18 #include "apr_strings.h"
19 #include "apr_lib.h"
20 #include "apr_fnmatch.h"
21 #include "apr_hash.h"
22 #include "apr_thread_proc.h"    /* for RLIMIT stuff */
23 #include "apr_hooks.h"
24
25 #define APR_WANT_IOVEC
26 #define APR_WANT_STRFUNC
27 #define APR_WANT_MEMFUNC
28 #include "apr_want.h"
29
30 #include "ap_config.h"
31 #include "httpd.h"
32 #include "http_config.h"
33 #include "http_core.h"
34 #include "http_protocol.h" /* For index_of_response().  Grump. */
35 #include "http_request.h"
36 #include "http_vhost.h"
37 #include "http_main.h"     /* For the default_handler below... */
38 #include "http_log.h"
39 #include "util_md5.h"
40 #include "http_connection.h"
41 #include "apr_buckets.h"
42 #include "util_filter.h"
43 #include "util_ebcdic.h"
44 #include "util_mutex.h"
45 #include "util_time.h"
46 #include "mpm_common.h"
47 #include "scoreboard.h"
48 #include "mod_core.h"
49 #include "mod_proxy.h"
50 #include "ap_listen.h"
51
52 #include "mod_so.h" /* for ap_find_loaded_module_symbol */
53
54 #if defined(RLIMIT_CPU) || defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS) || defined (RLIMIT_NPROC)
55 #include "unixd.h"
56 #endif
57 #if APR_HAVE_UNISTD_H
58 #include <unistd.h>
59 #endif
60
61 /* LimitRequestBody handling */
62 #define AP_LIMIT_REQ_BODY_UNSET         ((apr_off_t) -1)
63 #define AP_DEFAULT_LIMIT_REQ_BODY       ((apr_off_t) 0)
64
65 /* LimitXMLRequestBody handling */
66 #define AP_LIMIT_UNSET                  ((long) -1)
67 #define AP_DEFAULT_LIMIT_XML_BODY       ((size_t)1000000)
68
69 #define AP_MIN_SENDFILE_BYTES           (256)
70
71 /* maximum include nesting level */
72 #ifndef AP_MAX_INCLUDE_DEPTH
73 #define AP_MAX_INCLUDE_DEPTH            (128)
74 #endif
75
76 APR_HOOK_STRUCT(
77     APR_HOOK_LINK(get_mgmt_items)
78 )
79
80 AP_IMPLEMENT_HOOK_RUN_ALL(int, get_mgmt_items,
81                           (apr_pool_t *p, const char *val, apr_hash_t *ht),
82                           (p, val, ht), OK, DECLINED)
83
84 /* Server core module... This module provides support for really basic
85  * server operations, including options and commands which control the
86  * operation of other modules.  Consider this the bureaucracy module.
87  *
88  * The core module also defines handlers, etc., to handle just enough
89  * to allow a server with the core module ONLY to actually serve documents.
90  *
91  * This file could almost be mod_core.c, except for the stuff which affects
92  * the http_conf_globals.
93  */
94
95 /* Handles for core filters */
96 AP_DECLARE_DATA ap_filter_rec_t *ap_subreq_core_filter_handle;
97 AP_DECLARE_DATA ap_filter_rec_t *ap_core_output_filter_handle;
98 AP_DECLARE_DATA ap_filter_rec_t *ap_content_length_filter_handle;
99 AP_DECLARE_DATA ap_filter_rec_t *ap_core_input_filter_handle;
100
101 /* Provide ap_document_root_check storage and default value = true */
102 AP_DECLARE_DATA int ap_document_root_check = 1;
103
104 /* magic pointer for ErrorDocument xxx "default" */
105 static char errordocument_default;
106
107 static void *create_core_dir_config(apr_pool_t *a, char *dir)
108 {
109     core_dir_config *conf;
110
111     conf = (core_dir_config *)apr_pcalloc(a, sizeof(core_dir_config));
112
113     /* conf->r and conf->d[_*] are initialized by dirsection() or left NULL */
114
115     conf->opts = dir ? OPT_UNSET : OPT_UNSET|OPT_ALL;
116     conf->opts_add = conf->opts_remove = OPT_NONE;
117     conf->override = OR_UNSET|OR_NONE;
118     conf->override_opts = OPT_UNSET | OPT_ALL | OPT_SYM_OWNER | OPT_MULTI;
119
120     conf->content_md5 = 2;
121     conf->accept_path_info = 3;
122
123     conf->use_canonical_name = USE_CANONICAL_NAME_UNSET;
124     conf->use_canonical_phys_port = USE_CANONICAL_PHYS_PORT_UNSET;
125
126     conf->hostname_lookups = HOSTNAME_LOOKUP_UNSET;
127
128 #ifdef RLIMIT_CPU
129     conf->limit_cpu = NULL;
130 #endif
131 #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
132     conf->limit_mem = NULL;
133 #endif
134 #ifdef RLIMIT_NPROC
135     conf->limit_nproc = NULL;
136 #endif
137
138     conf->limit_req_body = AP_LIMIT_REQ_BODY_UNSET;
139     conf->limit_xml_body = AP_LIMIT_UNSET;
140     conf->sec_file = apr_array_make(a, 2, sizeof(ap_conf_vector_t *));
141
142     conf->server_signature = srv_sig_unset;
143
144     conf->add_default_charset = ADD_DEFAULT_CHARSET_UNSET;
145     conf->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
146
147     /* Overriding all negotiation
148      */
149     conf->mime_type = NULL;
150     conf->handler = NULL;
151     conf->output_filters = NULL;
152     conf->input_filters = NULL;
153
154     /*
155      * Flag for use of inodes in ETags.
156      */
157     conf->etag_bits = ETAG_UNSET;
158     conf->etag_add = ETAG_UNSET;
159     conf->etag_remove = ETAG_UNSET;
160
161     conf->enable_mmap = ENABLE_MMAP_UNSET;
162     conf->enable_sendfile = ENABLE_SENDFILE_UNSET;
163     conf->allow_encoded_slashes = 0;
164
165     return (void *)conf;
166 }
167
168 static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv)
169 {
170     core_dir_config *base = (core_dir_config *)basev;
171     core_dir_config *new = (core_dir_config *)newv;
172     core_dir_config *conf;
173     int i;
174
175     /* Create this conf by duplicating the base, replacing elements
176      * (or creating copies for merging) where new-> values exist.
177      */
178     conf = (core_dir_config *)apr_pmemdup(a, base, sizeof(core_dir_config));
179
180     conf->d = new->d;
181     conf->d_is_fnmatch = new->d_is_fnmatch;
182     conf->d_components = new->d_components;
183     conf->r = new->r;
184     conf->condition = new->condition;
185
186     if (new->opts & OPT_UNSET) {
187         /* there was no explicit setting of new->opts, so we merge
188          * preserve the invariant (opts_add & opts_remove) == 0
189          */
190         conf->opts_add = (conf->opts_add & ~new->opts_remove) | new->opts_add;
191         conf->opts_remove = (conf->opts_remove & ~new->opts_add)
192                             | new->opts_remove;
193         conf->opts = (conf->opts & ~conf->opts_remove) | conf->opts_add;
194
195         /* If Includes was enabled with exec in the base config, but
196          * was enabled without exec in the new config, then disable
197          * exec in the merged set. */
198         if (((base->opts & (OPT_INCLUDES|OPT_INC_WITH_EXEC))
199              == (OPT_INCLUDES|OPT_INC_WITH_EXEC))
200             && ((new->opts & (OPT_INCLUDES|OPT_INC_WITH_EXEC))
201                 == OPT_INCLUDES)) {
202             conf->opts &= ~OPT_INC_WITH_EXEC;
203         }
204     }
205     else {
206         /* otherwise we just copy, because an explicit opts setting
207          * overrides all earlier +/- modifiers
208          */
209         conf->opts = new->opts;
210         conf->opts_add = new->opts_add;
211         conf->opts_remove = new->opts_remove;
212     }
213
214     if (!(new->override & OR_UNSET)) {
215         conf->override = new->override;
216     }
217
218     if (!(new->override_opts & OPT_UNSET)) {
219         conf->override_opts = new->override_opts;
220     }
221
222     if (conf->response_code_strings == NULL) {
223         conf->response_code_strings = new->response_code_strings;
224     }
225     else if (new->response_code_strings != NULL) {
226         /* If we merge, the merge-result must have it's own array
227          */
228         conf->response_code_strings = apr_pmemdup(a,
229             base->response_code_strings,
230             sizeof(*conf->response_code_strings) * RESPONSE_CODES);
231
232         for (i = 0; i < RESPONSE_CODES; ++i) {
233             if (new->response_code_strings[i] != NULL) {
234                 conf->response_code_strings[i] = new->response_code_strings[i];
235             }
236         }
237     }
238     /* Otherwise we simply use the base->response_code_strings array
239      */
240
241     if (new->hostname_lookups != HOSTNAME_LOOKUP_UNSET) {
242         conf->hostname_lookups = new->hostname_lookups;
243     }
244
245     if ((new->content_md5 & 2) == 0) {
246         conf->content_md5 = new->content_md5;
247     }
248
249     if (new->accept_path_info != 3) {
250         conf->accept_path_info = new->accept_path_info;
251     }
252
253     if (new->use_canonical_name != USE_CANONICAL_NAME_UNSET) {
254         conf->use_canonical_name = new->use_canonical_name;
255     }
256
257     if (new->use_canonical_phys_port != USE_CANONICAL_PHYS_PORT_UNSET) {
258         conf->use_canonical_phys_port = new->use_canonical_phys_port;
259     }
260
261 #ifdef RLIMIT_CPU
262     if (new->limit_cpu) {
263         conf->limit_cpu = new->limit_cpu;
264     }
265 #endif
266
267 #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
268     if (new->limit_mem) {
269         conf->limit_mem = new->limit_mem;
270     }
271 #endif
272
273 #ifdef RLIMIT_NPROC
274     if (new->limit_nproc) {
275         conf->limit_nproc = new->limit_nproc;
276     }
277 #endif
278
279     if (new->limit_req_body != AP_LIMIT_REQ_BODY_UNSET) {
280         conf->limit_req_body = new->limit_req_body;
281     }
282
283     if (new->limit_xml_body != AP_LIMIT_UNSET)
284         conf->limit_xml_body = new->limit_xml_body;
285     else
286         conf->limit_xml_body = base->limit_xml_body;
287
288     if (!conf->sec_file) {
289         conf->sec_file = new->sec_file;
290     }
291     else if (new->sec_file) {
292         /* If we merge, the merge-result must have it's own array
293          */
294         conf->sec_file = apr_array_append(a, base->sec_file, new->sec_file);
295     }
296     /* Otherwise we simply use the base->sec_file array
297      */
298
299     if (new->server_signature != srv_sig_unset) {
300         conf->server_signature = new->server_signature;
301     }
302
303     if (new->add_default_charset != ADD_DEFAULT_CHARSET_UNSET) {
304         conf->add_default_charset = new->add_default_charset;
305         conf->add_default_charset_name = new->add_default_charset_name;
306     }
307
308     /* Overriding all negotiation
309      */
310     if (new->mime_type) {
311         conf->mime_type = new->mime_type;
312     }
313
314     if (new->handler) {
315         conf->handler = new->handler;
316     }
317
318     if (new->output_filters) {
319         conf->output_filters = new->output_filters;
320     }
321
322     if (new->input_filters) {
323         conf->input_filters = new->input_filters;
324     }
325
326     /*
327      * Now merge the setting of the FileETag directive.
328      */
329     if (new->etag_bits == ETAG_UNSET) {
330         conf->etag_add =
331             (conf->etag_add & (~ new->etag_remove)) | new->etag_add;
332         conf->etag_remove =
333             (conf->etag_remove & (~ new->etag_add)) | new->etag_remove;
334         conf->etag_bits =
335             (conf->etag_bits & (~ conf->etag_remove)) | conf->etag_add;
336     }
337     else {
338         conf->etag_bits = new->etag_bits;
339         conf->etag_add = new->etag_add;
340         conf->etag_remove = new->etag_remove;
341     }
342
343     if (conf->etag_bits != ETAG_NONE) {
344         conf->etag_bits &= (~ ETAG_NONE);
345     }
346
347     if (new->enable_mmap != ENABLE_MMAP_UNSET) {
348         conf->enable_mmap = new->enable_mmap;
349     }
350
351     if (new->enable_sendfile != ENABLE_SENDFILE_UNSET) {
352         conf->enable_sendfile = new->enable_sendfile;
353     }
354
355     conf->allow_encoded_slashes = new->allow_encoded_slashes;
356
357     if (new->log) {
358         if (!conf->log) {
359             conf->log = new->log;
360         }
361         else {
362             conf->log = ap_new_log_config(a, new->log);
363             ap_merge_log_config(base->log, conf->log);
364         }
365     }
366
367     return (void*)conf;
368 }
369
370 #if APR_HAS_SO_ACCEPTFILTER
371 #ifndef ACCEPT_FILTER_NAME
372 #define ACCEPT_FILTER_NAME "httpready"
373 #ifdef __FreeBSD_version
374 #if __FreeBSD_version < 411000 /* httpready broken before 4.1.1 */
375 #undef ACCEPT_FILTER_NAME
376 #define ACCEPT_FILTER_NAME "dataready"
377 #endif
378 #endif
379 #endif
380 #endif
381
382 static void *create_core_server_config(apr_pool_t *a, server_rec *s)
383 {
384     core_server_config *conf;
385     int is_virtual = s->is_virtual;
386
387     conf = (core_server_config *)apr_pcalloc(a, sizeof(core_server_config));
388
389     /* global-default / global-only settings */
390
391     if (!is_virtual) {
392         conf->ap_document_root = DOCUMENT_LOCATION;
393         conf->access_name = DEFAULT_ACCESS_FNAME;
394
395         /* A mapping only makes sense in the global context */
396         conf->accf_map = apr_table_make(a, 5);
397 #if APR_HAS_SO_ACCEPTFILTER
398         apr_table_setn(conf->accf_map, "http", ACCEPT_FILTER_NAME);
399         apr_table_setn(conf->accf_map, "https", "dataready");
400 #else
401         apr_table_setn(conf->accf_map, "http", "data");
402         apr_table_setn(conf->accf_map, "https", "data");
403 #endif
404     }
405     /* pcalloc'ed - we have NULL's/0's
406     else ** is_virtual ** {
407         conf->ap_document_root = NULL;
408         conf->access_name = NULL;
409         conf->accf_map = NULL;
410     }
411      */
412
413     /* initialization, no special case for global context */
414
415     conf->sec_dir = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));
416     conf->sec_url = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));
417
418     /* pcalloc'ed - we have NULL's/0's
419     conf->gprof_dir = NULL;
420
421     ** recursion stopper; 0 == unset
422     conf->redirect_limit = 0;
423     conf->subreq_limit = 0;
424
425     conf->protocol = NULL;
426      */
427
428     conf->trace_enable = AP_TRACE_UNSET;
429
430     return (void *)conf;
431 }
432
433 static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
434 {
435     core_server_config *base = (core_server_config *)basev;
436     core_server_config *virt = (core_server_config *)virtv;
437     core_server_config *conf = (core_server_config *)
438                                apr_pmemdup(p, base, sizeof(core_server_config));
439
440     if (virt->ap_document_root)
441         conf->ap_document_root = virt->ap_document_root;
442
443     if (virt->access_name)
444         conf->access_name = virt->access_name;
445
446     /* XXX optimize to keep base->sec_ pointers if virt->sec_ array is empty */
447     conf->sec_dir = apr_array_append(p, base->sec_dir, virt->sec_dir);
448     conf->sec_url = apr_array_append(p, base->sec_url, virt->sec_url);
449
450     if (virt->redirect_limit)
451         conf->redirect_limit = virt->redirect_limit;
452
453     if (virt->subreq_limit)
454         conf->subreq_limit = virt->subreq_limit;
455
456     if (virt->trace_enable != AP_TRACE_UNSET)
457         conf->trace_enable = virt->trace_enable;
458
459     /* no action for virt->accf_map, not allowed per-vhost */
460
461     if (virt->protocol)
462         conf->protocol = virt->protocol;
463
464     if (virt->gprof_dir)
465         conf->gprof_dir = virt->gprof_dir;
466
467     if (virt->error_log_format)
468         conf->error_log_format = virt->error_log_format;
469
470     if (virt->error_log_conn)
471         conf->error_log_conn = virt->error_log_conn;
472
473     if (virt->error_log_req)
474         conf->error_log_req = virt->error_log_req;
475
476     return conf;
477 }
478
479 /* Add per-directory configuration entry (for <directory> section);
480  * these are part of the core server config.
481  */
482
483 AP_CORE_DECLARE(void) ap_add_per_dir_conf(server_rec *s, void *dir_config)
484 {
485     core_server_config *sconf = ap_get_module_config(s->module_config,
486                                                      &core_module);
487     void **new_space = (void **)apr_array_push(sconf->sec_dir);
488
489     *new_space = dir_config;
490 }
491
492 AP_CORE_DECLARE(void) ap_add_per_url_conf(server_rec *s, void *url_config)
493 {
494     core_server_config *sconf = ap_get_module_config(s->module_config,
495                                                      &core_module);
496     void **new_space = (void **)apr_array_push(sconf->sec_url);
497
498     *new_space = url_config;
499 }
500
501 AP_CORE_DECLARE(void) ap_add_file_conf(core_dir_config *conf, void *url_config)
502 {
503     void **new_space = (void **)apr_array_push(conf->sec_file);
504
505     *new_space = url_config;
506 }
507
508 /* We need to do a stable sort, qsort isn't stable.  So to make it stable
509  * we'll be maintaining the original index into the list, and using it
510  * as the minor key during sorting.  The major key is the number of
511  * components (where the root component is zero).
512  */
513 struct reorder_sort_rec {
514     ap_conf_vector_t *elt;
515     int orig_index;
516 };
517
518 static int reorder_sorter(const void *va, const void *vb)
519 {
520     const struct reorder_sort_rec *a = va;
521     const struct reorder_sort_rec *b = vb;
522     core_dir_config *core_a;
523     core_dir_config *core_b;
524
525     core_a = ap_get_module_config(a->elt, &core_module);
526     core_b = ap_get_module_config(b->elt, &core_module);
527
528     /* a regex always sorts after a non-regex
529      */
530     if (!core_a->r && core_b->r) {
531         return -1;
532     }
533     else if (core_a->r && !core_b->r) {
534         return 1;
535     }
536
537     /* we always sort next by the number of components
538      */
539     if (core_a->d_components < core_b->d_components) {
540         return -1;
541     }
542     else if (core_a->d_components > core_b->d_components) {
543         return 1;
544     }
545
546     /* They have the same number of components, we now have to compare
547      * the minor key to maintain the original order (from the config.)
548      */
549     return a->orig_index - b->orig_index;
550 }
551
552 void ap_core_reorder_directories(apr_pool_t *p, server_rec *s)
553 {
554     core_server_config *sconf;
555     apr_array_header_t *sec_dir;
556     struct reorder_sort_rec *sortbin;
557     int nelts;
558     ap_conf_vector_t **elts;
559     int i;
560     apr_pool_t *tmp;
561
562     sconf = ap_get_module_config(s->module_config, &core_module);
563     sec_dir = sconf->sec_dir;
564     nelts = sec_dir->nelts;
565     elts = (ap_conf_vector_t **)sec_dir->elts;
566
567     if (!nelts) {
568         /* simple case of already being sorted... */
569         /* We're not checking this condition to be fast... we're checking
570          * it to avoid trying to palloc zero bytes, which can trigger some
571          * memory debuggers to barf
572          */
573         return;
574     }
575
576     /* we have to allocate tmp space to do a stable sort */
577     apr_pool_create(&tmp, p);
578     sortbin = apr_palloc(tmp, sec_dir->nelts * sizeof(*sortbin));
579     for (i = 0; i < nelts; ++i) {
580         sortbin[i].orig_index = i;
581         sortbin[i].elt = elts[i];
582     }
583
584     qsort(sortbin, nelts, sizeof(*sortbin), reorder_sorter);
585
586     /* and now copy back to the original array */
587     for (i = 0; i < nelts; ++i) {
588         elts[i] = sortbin[i].elt;
589     }
590
591     apr_pool_destroy(tmp);
592 }
593
594 /*****************************************************************
595  *
596  * There are some elements of the core config structures in which
597  * other modules have a legitimate interest (this is ugly, but necessary
598  * to preserve NCSA back-compatibility).  So, we have a bunch of accessors
599  * here...
600  */
601
602 AP_DECLARE(int) ap_allow_options(request_rec *r)
603 {
604     core_dir_config *conf =
605       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
606
607     return conf->opts;
608 }
609
610 AP_DECLARE(int) ap_allow_overrides(request_rec *r)
611 {
612     core_dir_config *conf;
613     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
614                                                    &core_module);
615
616     return conf->override;
617 }
618
619 /*
620  * Optional function coming from mod_authn_core, used for
621  * retrieving the type of autorization
622  */
623 static APR_OPTIONAL_FN_TYPE(authn_ap_auth_type) *authn_ap_auth_type;
624
625 AP_DECLARE(const char *) ap_auth_type(request_rec *r)
626 {
627     if (authn_ap_auth_type) {
628         return authn_ap_auth_type(r);
629     }
630     return NULL;
631 }
632
633 /*
634  * Optional function coming from mod_authn_core, used for
635  * retrieving the authorization realm
636  */
637 static APR_OPTIONAL_FN_TYPE(authn_ap_auth_name) *authn_ap_auth_name;
638
639 AP_DECLARE(const char *) ap_auth_name(request_rec *r)
640 {
641     if (authn_ap_auth_name) {
642         return authn_ap_auth_name(r);
643     }
644     return NULL;
645 }
646
647 /*
648  * Optional function coming from mod_access_compat, used to determine how
649    access control interacts with authentication/authorization
650  */
651 static APR_OPTIONAL_FN_TYPE(access_compat_ap_satisfies) *access_compat_ap_satisfies;
652
653 AP_DECLARE(int) ap_satisfies(request_rec *r)
654 {
655     if (access_compat_ap_satisfies) {
656         return access_compat_ap_satisfies(r);
657     }
658     return SATISFY_NOSPEC;
659 }
660
661 AP_DECLARE(const char *) ap_document_root(request_rec *r) /* Don't use this! */
662 {
663     core_server_config *conf;
664
665     conf = (core_server_config *)ap_get_module_config(r->server->module_config,
666                                                       &core_module);
667
668     return conf->ap_document_root;
669 }
670
671 /* Should probably just get rid of this... the only code that cares is
672  * part of the core anyway (and in fact, it isn't publicised to other
673  * modules).
674  */
675
676 char *ap_response_code_string(request_rec *r, int error_index)
677 {
678     core_dir_config *dirconf;
679     core_request_config *reqconf;
680
681     /* check for string registered via ap_custom_response() first */
682     reqconf = (core_request_config *)ap_get_module_config(r->request_config,
683                                                           &core_module);
684     if (reqconf->response_code_strings != NULL &&
685         reqconf->response_code_strings[error_index] != NULL) {
686         return reqconf->response_code_strings[error_index];
687     }
688
689     /* check for string specified via ErrorDocument */
690     dirconf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
691                                                       &core_module);
692
693     if (dirconf->response_code_strings == NULL) {
694         return NULL;
695     }
696
697     if (dirconf->response_code_strings[error_index] == &errordocument_default) {
698         return NULL;
699     }
700
701     return dirconf->response_code_strings[error_index];
702 }
703
704
705 /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
706 static APR_INLINE void do_double_reverse (conn_rec *conn)
707 {
708     apr_sockaddr_t *sa;
709     apr_status_t rv;
710
711     if (conn->double_reverse) {
712         /* already done */
713         return;
714     }
715
716     if (conn->remote_host == NULL || conn->remote_host[0] == '\0') {
717         /* single reverse failed, so don't bother */
718         conn->double_reverse = -1;
719         return;
720     }
721
722     rv = apr_sockaddr_info_get(&sa, conn->remote_host, APR_UNSPEC, 0, 0, conn->pool);
723     if (rv == APR_SUCCESS) {
724         while (sa) {
725             if (apr_sockaddr_equal(sa, conn->remote_addr)) {
726                 conn->double_reverse = 1;
727                 return;
728             }
729
730             sa = sa->next;
731         }
732     }
733
734     conn->double_reverse = -1;
735 }
736
737 AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
738                                             int type, int *str_is_ip)
739 {
740     int hostname_lookups;
741     int ignored_str_is_ip;
742
743     if (!str_is_ip) { /* caller doesn't want to know */
744         str_is_ip = &ignored_str_is_ip;
745     }
746     *str_is_ip = 0;
747
748     /* If we haven't checked the host name, and we want to */
749     if (dir_config) {
750         hostname_lookups =
751             ((core_dir_config *)ap_get_module_config(dir_config, &core_module))
752             ->hostname_lookups;
753
754         if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) {
755             hostname_lookups = HOSTNAME_LOOKUP_OFF;
756         }
757     }
758     else {
759         /* the default */
760         hostname_lookups = HOSTNAME_LOOKUP_OFF;
761     }
762
763     if (type != REMOTE_NOLOOKUP
764         && conn->remote_host == NULL
765         && (type == REMOTE_DOUBLE_REV
766         || hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
767
768         if (apr_getnameinfo(&conn->remote_host, conn->remote_addr, 0)
769             == APR_SUCCESS) {
770             ap_str_tolower(conn->remote_host);
771
772             if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
773                 do_double_reverse(conn);
774                 if (conn->double_reverse != 1) {
775                     conn->remote_host = NULL;
776                 }
777             }
778         }
779
780         /* if failed, set it to the NULL string to indicate error */
781         if (conn->remote_host == NULL) {
782             conn->remote_host = "";
783         }
784     }
785
786     if (type == REMOTE_DOUBLE_REV) {
787         do_double_reverse(conn);
788         if (conn->double_reverse == -1) {
789             return NULL;
790         }
791     }
792
793     /*
794      * Return the desired information; either the remote DNS name, if found,
795      * or either NULL (if the hostname was requested) or the IP address
796      * (if any identifier was requested).
797      */
798     if (conn->remote_host != NULL && conn->remote_host[0] != '\0') {
799         return conn->remote_host;
800     }
801     else {
802         if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) {
803             return NULL;
804         }
805         else {
806             *str_is_ip = 1;
807             return conn->remote_ip;
808         }
809     }
810 }
811
812 /*
813  * Optional function coming from mod_ident, used for looking up ident user
814  */
815 static APR_OPTIONAL_FN_TYPE(ap_ident_lookup) *ident_lookup;
816
817 AP_DECLARE(const char *) ap_get_remote_logname(request_rec *r)
818 {
819     if (r->connection->remote_logname != NULL) {
820         return r->connection->remote_logname;
821     }
822
823     if (ident_lookup) {
824         return ident_lookup(r);
825     }
826
827     return NULL;
828 }
829
830 /* There are two options regarding what the "name" of a server is.  The
831  * "canonical" name as defined by ServerName and Port, or the "client's
832  * name" as supplied by a possible Host: header or full URI.
833  *
834  * The DNS option to UseCanonicalName causes this routine to do a
835  * reverse lookup on the local IP address of the connection and use
836  * that for the ServerName. This makes its value more reliable while
837  * at the same time allowing Demon's magic virtual hosting to work.
838  * The assumption is that DNS lookups are sufficiently quick...
839  * -- fanf 1998-10-03
840  */
841 AP_DECLARE(const char *) ap_get_server_name(request_rec *r)
842 {
843     conn_rec *conn = r->connection;
844     core_dir_config *d;
845     const char *retval;
846
847     d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
848                                                 &core_module);
849
850     switch (d->use_canonical_name) {
851         case USE_CANONICAL_NAME_ON:
852             retval = r->server->server_hostname;
853             break;
854         case USE_CANONICAL_NAME_DNS:
855             if (conn->local_host == NULL) {
856                 if (apr_getnameinfo(&conn->local_host,
857                                 conn->local_addr, 0) != APR_SUCCESS)
858                     conn->local_host = apr_pstrdup(conn->pool,
859                                                r->server->server_hostname);
860                 else {
861                     ap_str_tolower(conn->local_host);
862                 }
863             }
864             retval = conn->local_host;
865             break;
866         case USE_CANONICAL_NAME_OFF:
867         case USE_CANONICAL_NAME_UNSET:
868             retval = r->hostname ? r->hostname : r->server->server_hostname;
869             break;
870         default:
871             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
872                          "ap_get_server_name: Invalid UCN Option somehow");
873             retval = "localhost";
874             break;
875     }
876     return retval;
877 }
878
879 /*
880  * Get the current server name from the request for the purposes
881  * of using in a URL.  If the server name is an IPv6 literal
882  * address, it will be returned in URL format (e.g., "[fe80::1]").
883  */
884 AP_DECLARE(const char *) ap_get_server_name_for_url(request_rec *r)
885 {
886     const char *plain_server_name = ap_get_server_name(r);
887
888 #if APR_HAVE_IPV6
889     if (ap_strchr_c(plain_server_name, ':')) { /* IPv6 literal? */
890         return apr_psprintf(r->pool, "[%s]", plain_server_name);
891     }
892 #endif
893     return plain_server_name;
894 }
895
896 AP_DECLARE(apr_port_t) ap_get_server_port(const request_rec *r)
897 {
898     apr_port_t port;
899     core_dir_config *d =
900       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
901
902     switch (d->use_canonical_name) {
903         case USE_CANONICAL_NAME_OFF:
904         case USE_CANONICAL_NAME_DNS:
905         case USE_CANONICAL_NAME_UNSET:
906             if (d->use_canonical_phys_port == USE_CANONICAL_PHYS_PORT_ON)
907                 port = r->parsed_uri.port_str ? r->parsed_uri.port :
908                        r->connection->local_addr->port ? r->connection->local_addr->port :
909                        r->server->port ? r->server->port :
910                        ap_default_port(r);
911             else /* USE_CANONICAL_PHYS_PORT_OFF or USE_CANONICAL_PHYS_PORT_UNSET */
912                 port = r->parsed_uri.port_str ? r->parsed_uri.port :
913                        r->server->port ? r->server->port :
914                        ap_default_port(r);
915             break;
916         case USE_CANONICAL_NAME_ON:
917             /* With UseCanonicalName on (and in all versions prior to 1.3)
918              * Apache will use the hostname and port specified in the
919              * ServerName directive to construct a canonical name for the
920              * server. (If no port was specified in the ServerName
921              * directive, Apache uses the port supplied by the client if
922              * any is supplied, and finally the default port for the protocol
923              * used.
924              */
925             if (d->use_canonical_phys_port == USE_CANONICAL_PHYS_PORT_ON)
926                 port = r->server->port ? r->server->port :
927                        r->connection->local_addr->port ? r->connection->local_addr->port :
928                        ap_default_port(r);
929             else /* USE_CANONICAL_PHYS_PORT_OFF or USE_CANONICAL_PHYS_PORT_UNSET */
930                 port = r->server->port ? r->server->port :
931                        ap_default_port(r);
932             break;
933         default:
934             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
935                          "ap_get_server_port: Invalid UCN Option somehow");
936             port = ap_default_port(r);
937             break;
938     }
939
940     return port;
941 }
942
943 AP_DECLARE(char *) ap_construct_url(apr_pool_t *p, const char *uri,
944                                     request_rec *r)
945 {
946     unsigned port = ap_get_server_port(r);
947     const char *host = ap_get_server_name_for_url(r);
948
949     if (ap_is_default_port(port, r)) {
950         return apr_pstrcat(p, ap_http_scheme(r), "://", host, uri, NULL);
951     }
952
953     return apr_psprintf(p, "%s://%s:%u%s", ap_http_scheme(r), host, port, uri);
954 }
955
956 AP_DECLARE(apr_off_t) ap_get_limit_req_body(const request_rec *r)
957 {
958     core_dir_config *d =
959       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
960
961     if (d->limit_req_body == AP_LIMIT_REQ_BODY_UNSET) {
962         return AP_DEFAULT_LIMIT_REQ_BODY;
963     }
964
965     return d->limit_req_body;
966 }
967
968
969 /*****************************************************************
970  *
971  * Commands... this module handles almost all of the NCSA httpd.conf
972  * commands, but most of the old srm.conf is in the the modules.
973  */
974
975
976 /* returns a parent if it matches the given directive */
977 static const ap_directive_t * find_parent(const ap_directive_t *dirp,
978                                           const char *what)
979 {
980     while (dirp->parent != NULL) {
981         dirp = dirp->parent;
982
983         /* ### it would be nice to have atom-ized directives */
984         if (strcasecmp(dirp->directive, what) == 0)
985             return dirp;
986     }
987
988     return NULL;
989 }
990
991 AP_DECLARE(const char *) ap_check_cmd_context(cmd_parms *cmd,
992                                               unsigned forbidden)
993 {
994     const char *gt = (cmd->cmd->name[0] == '<'
995                       && cmd->cmd->name[strlen(cmd->cmd->name)-1] != '>')
996                          ? ">" : "";
997     const ap_directive_t *found;
998
999     if ((forbidden & NOT_IN_VIRTUALHOST) && cmd->server->is_virtual) {
1000         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1001                            " cannot occur within <VirtualHost> section", NULL);
1002     }
1003
1004     if ((forbidden & (NOT_IN_LIMIT | NOT_IN_DIR_LOC_FILE))
1005         && cmd->limited != -1) {
1006         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1007                            " cannot occur within <Limit> or <LimitExcept> "
1008                            "section", NULL);
1009     }
1010
1011     if ((forbidden & NOT_IN_DIR_LOC_FILE) == NOT_IN_DIR_LOC_FILE) {
1012         if (cmd->path != NULL) {
1013             return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1014                             " cannot occur within <Directory/Location/Files> "
1015                             "section", NULL);
1016         }
1017         if (cmd->cmd->req_override & EXEC_ON_READ) {
1018             /* EXEC_ON_READ must be NOT_IN_DIR_LOC_FILE, if not, it will
1019              * (deliberately) segfault below in the individual tests...
1020              */
1021             return NULL;
1022         }
1023     }
1024
1025     if (((forbidden & NOT_IN_DIRECTORY)
1026          && ((found = find_parent(cmd->directive, "<Directory"))
1027              || (found = find_parent(cmd->directive, "<DirectoryMatch"))))
1028         || ((forbidden & NOT_IN_LOCATION)
1029             && ((found = find_parent(cmd->directive, "<Location"))
1030                 || (found = find_parent(cmd->directive, "<LocationMatch"))))
1031         || ((forbidden & NOT_IN_FILES)
1032             && ((found = find_parent(cmd->directive, "<Files"))
1033                 || (found = find_parent(cmd->directive, "<FilesMatch"))))) {
1034         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1035                            " cannot occur within ", found->directive,
1036                            "> section", NULL);
1037     }
1038
1039     return NULL;
1040 }
1041
1042 static const char *set_access_name(cmd_parms *cmd, void *dummy,
1043                                    const char *arg)
1044 {
1045     void *sconf = cmd->server->module_config;
1046     core_server_config *conf = ap_get_module_config(sconf, &core_module);
1047
1048     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
1049     if (err != NULL) {
1050         return err;
1051     }
1052
1053     conf->access_name = apr_pstrdup(cmd->pool, arg);
1054     return NULL;
1055 }
1056
1057
1058 static const char *set_define(cmd_parms *cmd, void *dummy,
1059                               const char *optarg)
1060 {
1061     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1062     if (err != NULL) {
1063         return err;
1064     }
1065
1066     if (!ap_exists_config_define(optarg)) {
1067         char **newv = (char **)apr_array_push(ap_server_config_defines);
1068         *newv = apr_pstrdup(cmd->pool, optarg);
1069     }
1070
1071     return NULL;
1072 }
1073
1074 static const char *unset_define(cmd_parms *cmd, void *dummy,
1075                                 const char *optarg)
1076 {
1077     int i;
1078     char **defines;
1079     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1080     if (err != NULL) {
1081         return err;
1082     }
1083
1084     defines = (char **)ap_server_config_defines->elts;
1085     for (i = 0; i < ap_server_config_defines->nelts; i++) {
1086         if (strcmp(defines[i], optarg) == 0) {
1087             defines[i] = apr_array_pop(ap_server_config_defines);
1088             break;
1089         }
1090     }
1091
1092     return NULL;
1093 }
1094
1095 #ifdef GPROF
1096 static const char *set_gprof_dir(cmd_parms *cmd, void *dummy, const char *arg)
1097 {
1098     void *sconf = cmd->server->module_config;
1099     core_server_config *conf = ap_get_module_config(sconf, &core_module);
1100
1101     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
1102     if (err != NULL) {
1103         return err;
1104     }
1105
1106     conf->gprof_dir = arg;
1107     return NULL;
1108 }
1109 #endif /*GPROF*/
1110
1111 static const char *set_add_default_charset(cmd_parms *cmd,
1112                                            void *d_, const char *arg)
1113 {
1114     core_dir_config *d = d_;
1115
1116     if (!strcasecmp(arg, "Off")) {
1117        d->add_default_charset = ADD_DEFAULT_CHARSET_OFF;
1118     }
1119     else if (!strcasecmp(arg, "On")) {
1120        d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
1121        d->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
1122     }
1123     else {
1124        d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
1125        d->add_default_charset_name = arg;
1126     }
1127
1128     return NULL;
1129 }
1130
1131 static const char *set_document_root(cmd_parms *cmd, void *dummy,
1132                                      const char *arg)
1133 {
1134     void *sconf = cmd->server->module_config;
1135     core_server_config *conf = ap_get_module_config(sconf, &core_module);
1136
1137     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
1138     if (err != NULL) {
1139         return err;
1140     }
1141
1142     /* When ap_document_root_check is false; skip all the stuff below */
1143     if (!ap_document_root_check) {
1144        conf->ap_document_root = arg;
1145        return NULL;
1146     }
1147
1148     /* Make it absolute, relative to ServerRoot */
1149     arg = ap_server_root_relative(cmd->pool, arg);
1150     if (arg == NULL) {
1151         return "DocumentRoot must be a directory";
1152     }
1153
1154     /* TODO: ap_configtestonly */
1155     if (apr_filepath_merge((char**)&conf->ap_document_root, NULL, arg,
1156                            APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS
1157         || !ap_is_directory(cmd->pool, arg)) {
1158         if (cmd->server->is_virtual) {
1159             ap_log_perror(APLOG_MARK, APLOG_STARTUP, 0,
1160                           cmd->pool,
1161                           "Warning: DocumentRoot [%s] does not exist",
1162                           arg);
1163             conf->ap_document_root = arg;
1164         }
1165         else {
1166             return "DocumentRoot must be a directory";
1167         }
1168     }
1169     return NULL;
1170 }
1171
1172 AP_DECLARE(void) ap_custom_response(request_rec *r, int status,
1173                                     const char *string)
1174 {
1175     core_request_config *conf =
1176         ap_get_module_config(r->request_config, &core_module);
1177     int idx;
1178
1179     if (conf->response_code_strings == NULL) {
1180         conf->response_code_strings =
1181             apr_pcalloc(r->pool,
1182                         sizeof(*conf->response_code_strings) * RESPONSE_CODES);
1183     }
1184
1185     idx = ap_index_of_response(status);
1186
1187     conf->response_code_strings[idx] =
1188        ((ap_is_url(string) || (*string == '/')) && (*string != '"')) ?
1189        apr_pstrdup(r->pool, string) : apr_pstrcat(r->pool, "\"", string, NULL);
1190 }
1191
1192 static const char *set_error_document(cmd_parms *cmd, void *conf_,
1193                                       const char *errno_str, const char *msg)
1194 {
1195     core_dir_config *conf = conf_;
1196     int error_number, index_number, idx500;
1197     enum { MSG, LOCAL_PATH, REMOTE_PATH } what = MSG;
1198
1199     /* 1st parameter should be a 3 digit number, which we recognize;
1200      * convert it into an array index
1201      */
1202     error_number = atoi(errno_str);
1203     idx500 = ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);
1204
1205     if (error_number == HTTP_INTERNAL_SERVER_ERROR) {
1206         index_number = idx500;
1207     }
1208     else if ((index_number = ap_index_of_response(error_number)) == idx500) {
1209         return apr_pstrcat(cmd->pool, "Unsupported HTTP response code ",
1210                            errno_str, NULL);
1211     }
1212
1213     /* Heuristic to determine second argument. */
1214     if (ap_strchr_c(msg,' '))
1215         what = MSG;
1216     else if (msg[0] == '/')
1217         what = LOCAL_PATH;
1218     else if (ap_is_url(msg))
1219         what = REMOTE_PATH;
1220     else
1221         what = MSG;
1222
1223     /* The entry should be ignored if it is a full URL for a 401 error */
1224
1225     if (error_number == 401 && what == REMOTE_PATH) {
1226         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, cmd->server,
1227                      "cannot use a full URL in a 401 ErrorDocument "
1228                      "directive --- ignoring!");
1229     }
1230     else { /* Store it... */
1231         if (conf->response_code_strings == NULL) {
1232             conf->response_code_strings =
1233                 apr_pcalloc(cmd->pool,
1234                             sizeof(*conf->response_code_strings) *
1235                             RESPONSE_CODES);
1236         }
1237
1238         if (strcmp(msg, "default") == 0) {
1239             /* special case: ErrorDocument 404 default restores the
1240              * canned server error response
1241              */
1242             conf->response_code_strings[index_number] = &errordocument_default;
1243         }
1244         else {
1245             /* hack. Prefix a " if it is a msg; as that is what
1246              * http_protocol.c relies on to distinguish between
1247              * a msg and a (local) path.
1248              */
1249             conf->response_code_strings[index_number] = (what == MSG) ?
1250                     apr_pstrcat(cmd->pool, "\"",msg,NULL) :
1251                     apr_pstrdup(cmd->pool, msg);
1252         }
1253     }
1254
1255     return NULL;
1256 }
1257
1258 static const char *set_allow_opts(cmd_parms *cmd, allow_options_t *opts,
1259                                   const char *l)
1260 {
1261     allow_options_t opt;
1262     int first = 1;
1263
1264     char *w, *p = (char *) l;
1265     char *tok_state;
1266
1267     while ((w = apr_strtok(p, ",", &tok_state)) != NULL) {
1268
1269         if (first) {
1270             p = NULL;
1271             *opts = OPT_NONE;
1272             first = 0;
1273         }
1274
1275         if (!strcasecmp(w, "Indexes")) {
1276             opt = OPT_INDEXES;
1277         }
1278         else if (!strcasecmp(w, "Includes")) {
1279             /* If Includes is permitted, both Includes and
1280              * IncludesNOEXEC may be changed. */
1281             opt = (OPT_INCLUDES | OPT_INC_WITH_EXEC);
1282         }
1283         else if (!strcasecmp(w, "IncludesNOEXEC")) {
1284             opt = OPT_INCLUDES;
1285         }
1286         else if (!strcasecmp(w, "FollowSymLinks")) {
1287             opt = OPT_SYM_LINKS;
1288         }
1289         else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
1290             opt = OPT_SYM_OWNER;
1291         }
1292         else if (!strcasecmp(w, "ExecCGI")) {
1293             opt = OPT_EXECCGI;
1294         }
1295         else if (!strcasecmp(w, "MultiViews")) {
1296             opt = OPT_MULTI;
1297         }
1298         else if (!strcasecmp(w, "RunScripts")) { /* AI backcompat. Yuck */
1299             opt = OPT_MULTI|OPT_EXECCGI;
1300         }
1301         else if (!strcasecmp(w, "None")) {
1302             opt = OPT_NONE;
1303         }
1304         else if (!strcasecmp(w, "All")) {
1305             opt = OPT_ALL;
1306         }
1307         else {
1308             return apr_pstrcat(cmd->pool, "Illegal option ", w, NULL);
1309         }
1310
1311         *opts |= opt;
1312     }
1313
1314     (*opts) &= (~OPT_UNSET);
1315
1316     return NULL;
1317 }
1318
1319 static const char *set_override(cmd_parms *cmd, void *d_, const char *l)
1320 {
1321     core_dir_config *d = d_;
1322     char *w;
1323     char *k, *v;
1324
1325     /* Throw a warning if we're in <Location> or <Files> */
1326     if (ap_check_cmd_context(cmd, NOT_IN_LOCATION | NOT_IN_FILES)) {
1327         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
1328                      "Useless use of AllowOverride in line %d of %s.",
1329                      cmd->directive->line_num, cmd->directive->filename);
1330     }
1331
1332     d->override = OR_NONE;
1333     while (l[0]) {
1334         w = ap_getword_conf(cmd->temp_pool, &l);
1335
1336         k = w;
1337         v = strchr(k, '=');
1338         if (v) {
1339                 *v++ = '\0';
1340         }
1341
1342         if (!strcasecmp(w, "Limit")) {
1343             d->override |= OR_LIMIT;
1344         }
1345         else if (!strcasecmp(k, "Options")) {
1346             d->override |= OR_OPTIONS;
1347             if (v)
1348                 set_allow_opts(cmd, &(d->override_opts), v);
1349             else
1350                 d->override_opts = OPT_ALL;
1351         }
1352         else if (!strcasecmp(w, "FileInfo")) {
1353             d->override |= OR_FILEINFO;
1354         }
1355         else if (!strcasecmp(w, "AuthConfig")) {
1356             d->override |= OR_AUTHCFG;
1357         }
1358         else if (!strcasecmp(w, "Indexes")) {
1359             d->override |= OR_INDEXES;
1360         }
1361         else if (!strcasecmp(w, "None")) {
1362             d->override = OR_NONE;
1363         }
1364         else if (!strcasecmp(w, "All")) {
1365             d->override = OR_ALL;
1366         }
1367         else {
1368             return apr_pstrcat(cmd->pool, "Illegal override option ", w, NULL);
1369         }
1370
1371         d->override &= ~OR_UNSET;
1372     }
1373
1374     return NULL;
1375 }
1376
1377 static const char *set_options(cmd_parms *cmd, void *d_, const char *l)
1378 {
1379     core_dir_config *d = d_;
1380     allow_options_t opt;
1381     int first = 1;
1382     char action;
1383
1384     while (l[0]) {
1385         char *w = ap_getword_conf(cmd->temp_pool, &l);
1386         action = '\0';
1387
1388         if (*w == '+' || *w == '-') {
1389             action = *(w++);
1390         }
1391         else if (first) {
1392               d->opts = OPT_NONE;
1393             first = 0;
1394         }
1395
1396         if (!strcasecmp(w, "Indexes")) {
1397             opt = OPT_INDEXES;
1398         }
1399         else if (!strcasecmp(w, "Includes")) {
1400             opt = (OPT_INCLUDES | OPT_INC_WITH_EXEC);
1401         }
1402         else if (!strcasecmp(w, "IncludesNOEXEC")) {
1403             opt = OPT_INCLUDES;
1404         }
1405         else if (!strcasecmp(w, "FollowSymLinks")) {
1406             opt = OPT_SYM_LINKS;
1407         }
1408         else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
1409             opt = OPT_SYM_OWNER;
1410         }
1411         else if (!strcasecmp(w, "ExecCGI")) {
1412             opt = OPT_EXECCGI;
1413         }
1414         else if (!strcasecmp(w, "MultiViews")) {
1415             opt = OPT_MULTI;
1416         }
1417         else if (!strcasecmp(w, "RunScripts")) { /* AI backcompat. Yuck */
1418             opt = OPT_MULTI|OPT_EXECCGI;
1419         }
1420         else if (!strcasecmp(w, "None")) {
1421             opt = OPT_NONE;
1422         }
1423         else if (!strcasecmp(w, "All")) {
1424             opt = OPT_ALL;
1425         }
1426         else {
1427             return apr_pstrcat(cmd->pool, "Illegal option ", w, NULL);
1428         }
1429
1430         if ( (cmd->override_opts & opt) != opt ) {
1431             return apr_pstrcat(cmd->pool, "Option ", w, " not allowed here", NULL);
1432         }
1433         else if (action == '-') {
1434             /* we ensure the invariant (d->opts_add & d->opts_remove) == 0 */
1435             d->opts_remove |= opt;
1436             d->opts_add &= ~opt;
1437             d->opts &= ~opt;
1438         }
1439         else if (action == '+') {
1440             d->opts_add |= opt;
1441             d->opts_remove &= ~opt;
1442             d->opts |= opt;
1443         }
1444         else {
1445             d->opts |= opt;
1446         }
1447     }
1448
1449     return NULL;
1450 }
1451
1452 static const char *set_default_type(cmd_parms *cmd, void *d_,
1453                                    const char *arg)
1454 {
1455     if ((strcasecmp(arg, "off") != 0) && (strcasecmp(arg, "none") != 0)) {
1456         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
1457               "Ignoring deprecated use of DefaultType in line %d of %s.",
1458                      cmd->directive->line_num, cmd->directive->filename);
1459     }
1460
1461     return NULL;
1462 }
1463
1464 /*
1465  * Note what data should be used when forming file ETag values.
1466  * It would be nicer to do this as an ITERATE, but then we couldn't
1467  * remember the +/- state properly.
1468  */
1469 static const char *set_etag_bits(cmd_parms *cmd, void *mconfig,
1470                                  const char *args_p)
1471 {
1472     core_dir_config *cfg;
1473     etag_components_t bit;
1474     char action;
1475     char *token;
1476     const char *args;
1477     int valid;
1478     int first;
1479     int explicit;
1480
1481     cfg = (core_dir_config *)mconfig;
1482
1483     args = args_p;
1484     first = 1;
1485     explicit = 0;
1486     while (args[0] != '\0') {
1487         action = '*';
1488         bit = ETAG_UNSET;
1489         valid = 1;
1490         token = ap_getword_conf(cmd->temp_pool, &args);
1491         if ((*token == '+') || (*token == '-')) {
1492             action = *token;
1493             token++;
1494         }
1495         else {
1496             /*
1497              * The occurrence of an absolute setting wipes
1498              * out any previous relative ones.  The first such
1499              * occurrence forgets any inherited ones, too.
1500              */
1501             if (first) {
1502                 cfg->etag_bits = ETAG_UNSET;
1503                 cfg->etag_add = ETAG_UNSET;
1504                 cfg->etag_remove = ETAG_UNSET;
1505                 first = 0;
1506             }
1507         }
1508
1509         if (strcasecmp(token, "None") == 0) {
1510             if (action != '*') {
1511                 valid = 0;
1512             }
1513             else {
1514                 cfg->etag_bits = bit = ETAG_NONE;
1515                 explicit = 1;
1516             }
1517         }
1518         else if (strcasecmp(token, "All") == 0) {
1519             if (action != '*') {
1520                 valid = 0;
1521             }
1522             else {
1523                 explicit = 1;
1524                 cfg->etag_bits = bit = ETAG_ALL;
1525             }
1526         }
1527         else if (strcasecmp(token, "Size") == 0) {
1528             bit = ETAG_SIZE;
1529         }
1530         else if ((strcasecmp(token, "LMTime") == 0)
1531                  || (strcasecmp(token, "MTime") == 0)
1532                  || (strcasecmp(token, "LastModified") == 0)) {
1533             bit = ETAG_MTIME;
1534         }
1535         else if (strcasecmp(token, "INode") == 0) {
1536             bit = ETAG_INODE;
1537         }
1538         else {
1539             return apr_pstrcat(cmd->pool, "Unknown keyword '",
1540                                token, "' for ", cmd->cmd->name,
1541                                " directive", NULL);
1542         }
1543
1544         if (! valid) {
1545             return apr_pstrcat(cmd->pool, cmd->cmd->name, " keyword '",
1546                                token, "' cannot be used with '+' or '-'",
1547                                NULL);
1548         }
1549
1550         if (action == '+') {
1551             /*
1552              * Make sure it's in the 'add' list and absent from the
1553              * 'subtract' list.
1554              */
1555             cfg->etag_add |= bit;
1556             cfg->etag_remove &= (~ bit);
1557         }
1558         else if (action == '-') {
1559             cfg->etag_remove |= bit;
1560             cfg->etag_add &= (~ bit);
1561         }
1562         else {
1563             /*
1564              * Non-relative values wipe out any + or - values
1565              * accumulated so far.
1566              */
1567             cfg->etag_bits |= bit;
1568             cfg->etag_add = ETAG_UNSET;
1569             cfg->etag_remove = ETAG_UNSET;
1570             explicit = 1;
1571         }
1572     }
1573
1574     /*
1575      * Any setting at all will clear the 'None' and 'Unset' bits.
1576      */
1577
1578     if (cfg->etag_add != ETAG_UNSET) {
1579         cfg->etag_add &= (~ ETAG_UNSET);
1580     }
1581
1582     if (cfg->etag_remove != ETAG_UNSET) {
1583         cfg->etag_remove &= (~ ETAG_UNSET);
1584     }
1585
1586     if (explicit) {
1587         cfg->etag_bits &= (~ ETAG_UNSET);
1588
1589         if ((cfg->etag_bits & ETAG_NONE) != ETAG_NONE) {
1590             cfg->etag_bits &= (~ ETAG_NONE);
1591         }
1592     }
1593
1594     return NULL;
1595 }
1596
1597 static const char *set_enable_mmap(cmd_parms *cmd, void *d_,
1598                                    const char *arg)
1599 {
1600     core_dir_config *d = d_;
1601
1602     if (strcasecmp(arg, "on") == 0) {
1603         d->enable_mmap = ENABLE_MMAP_ON;
1604     }
1605     else if (strcasecmp(arg, "off") == 0) {
1606         d->enable_mmap = ENABLE_MMAP_OFF;
1607     }
1608     else {
1609         return "parameter must be 'on' or 'off'";
1610     }
1611
1612     return NULL;
1613 }
1614
1615 static const char *set_enable_sendfile(cmd_parms *cmd, void *d_,
1616                                    const char *arg)
1617 {
1618     core_dir_config *d = d_;
1619
1620     if (strcasecmp(arg, "on") == 0) {
1621         d->enable_sendfile = ENABLE_SENDFILE_ON;
1622     }
1623     else if (strcasecmp(arg, "off") == 0) {
1624         d->enable_sendfile = ENABLE_SENDFILE_OFF;
1625     }
1626     else {
1627         return "parameter must be 'on' or 'off'";
1628     }
1629
1630     return NULL;
1631 }
1632
1633
1634 /*
1635  * Report a missing-'>' syntax error.
1636  */
1637 static char *unclosed_directive(cmd_parms *cmd)
1638 {
1639     return apr_pstrcat(cmd->pool, cmd->cmd->name,
1640                        "> directive missing closing '>'", NULL);
1641 }
1642
1643 /*
1644  * Report a missing args in '<Foo >' syntax error.
1645  */
1646 static char *missing_container_arg(cmd_parms *cmd)
1647 {
1648     return apr_pstrcat(cmd->pool, cmd->cmd->name,
1649                        "> directive requires additional arguments", NULL);
1650 }
1651
1652 AP_CORE_DECLARE_NONSTD(const char *) ap_limit_section(cmd_parms *cmd,
1653                                                       void *dummy,
1654                                                       const char *arg)
1655 {
1656     const char *endp = ap_strrchr_c(arg, '>');
1657     const char *limited_methods;
1658     void *tog = cmd->cmd->cmd_data;
1659     apr_int64_t limited = 0;
1660     apr_int64_t old_limited = cmd->limited;
1661     const char *errmsg;
1662
1663     if (endp == NULL) {
1664         return unclosed_directive(cmd);
1665     }
1666
1667     limited_methods = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
1668
1669     if (!limited_methods[0]) {
1670         return missing_container_arg(cmd);
1671     }
1672
1673     while (limited_methods[0]) {
1674         char *method = ap_getword_conf(cmd->temp_pool, &limited_methods);
1675         int methnum;
1676
1677         /* check for builtin or module registered method number */
1678         methnum = ap_method_number_of(method);
1679
1680         if (methnum == M_TRACE && !tog) {
1681             return "TRACE cannot be controlled by <Limit>, see TraceEnable";
1682         }
1683         else if (methnum == M_INVALID) {
1684             /* method has not been registered yet, but resorce restriction
1685              * is always checked before method handling, so register it.
1686              */
1687             methnum = ap_method_register(cmd->pool,
1688                                          apr_pstrdup(cmd->pool, method));
1689         }
1690
1691         limited |= (AP_METHOD_BIT << methnum);
1692     }
1693
1694     /* Killing two features with one function,
1695      * if (tog == NULL) <Limit>, else <LimitExcept>
1696      */
1697     limited = tog ? ~limited : limited;
1698
1699     if (!(old_limited & limited)) {
1700         return apr_pstrcat(cmd->pool, cmd->cmd->name,
1701                            "> directive excludes all methods", NULL);
1702     }
1703     else if ((old_limited & limited) == old_limited) {
1704         return apr_pstrcat(cmd->pool, cmd->cmd->name,
1705                            "> directive specifies methods already excluded",
1706                            NULL);
1707     }
1708
1709     cmd->limited &= limited;
1710
1711     errmsg = ap_walk_config(cmd->directive->first_child, cmd, cmd->context);
1712
1713     cmd->limited = old_limited;
1714
1715     return errmsg;
1716 }
1717
1718 /* XXX: Bogus - need to do this differently (at least OS2/Netware suffer
1719  * the same problem!!!
1720  * We use this in <DirectoryMatch> and <FilesMatch>, to ensure that
1721  * people don't get bitten by wrong-cased regex matches
1722  */
1723
1724 #ifdef WIN32
1725 #define USE_ICASE AP_REG_ICASE
1726 #else
1727 #define USE_ICASE 0
1728 #endif
1729
1730 static const char *dirsection(cmd_parms *cmd, void *mconfig, const char *arg)
1731 {
1732     const char *errmsg;
1733     const char *endp = ap_strrchr_c(arg, '>');
1734     int old_overrides = cmd->override;
1735     char *old_path = cmd->path;
1736     core_dir_config *conf;
1737     ap_conf_vector_t *new_dir_conf = ap_create_per_dir_config(cmd->pool);
1738     ap_regex_t *r = NULL;
1739     const command_rec *thiscmd = cmd->cmd;
1740
1741     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
1742     if (err != NULL) {
1743         return err;
1744     }
1745
1746     if (endp == NULL) {
1747         return unclosed_directive(cmd);
1748     }
1749
1750     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
1751
1752     if (!arg[0]) {
1753         return missing_container_arg(cmd);
1754     }
1755
1756     cmd->path = ap_getword_conf(cmd->pool, &arg);
1757     cmd->override = OR_ALL|ACCESS_CONF;
1758
1759     if (!strcmp(cmd->path, "~")) {
1760         cmd->path = ap_getword_conf(cmd->pool, &arg);
1761         if (!cmd->path)
1762             return "<Directory ~ > block must specify a path";
1763         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
1764         if (!r) {
1765             return "Regex could not be compiled";
1766         }
1767     }
1768     else if (thiscmd->cmd_data) { /* <DirectoryMatch> */
1769         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
1770         if (!r) {
1771             return "Regex could not be compiled";
1772         }
1773     }
1774     else if (!strcmp(cmd->path, "/") == 0)
1775     {
1776         char *newpath;
1777
1778         /*
1779          * Ensure that the pathname is canonical, and append the trailing /
1780          */
1781         apr_status_t rv = apr_filepath_merge(&newpath, NULL, cmd->path,
1782                                              APR_FILEPATH_TRUENAME, cmd->pool);
1783         if (rv != APR_SUCCESS && rv != APR_EPATHWILD) {
1784             return apr_pstrcat(cmd->pool, "<Directory \"", cmd->path,
1785                                "\"> path is invalid.", NULL);
1786         }
1787
1788         cmd->path = newpath;
1789         if (cmd->path[strlen(cmd->path) - 1] != '/')
1790             cmd->path = apr_pstrcat(cmd->pool, cmd->path, "/", NULL);
1791     }
1792
1793     /* initialize our config and fetch it */
1794     conf = ap_set_config_vectors(cmd->server, new_dir_conf, cmd->path,
1795                                  &core_module, cmd->pool);
1796
1797     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_dir_conf);
1798     if (errmsg != NULL)
1799         return errmsg;
1800
1801     conf->r = r;
1802     conf->d = cmd->path;
1803     conf->d_is_fnmatch = (apr_fnmatch_test(conf->d) != 0);
1804
1805     /* Make this explicit - the "/" root has 0 elements, that is, we
1806      * will always merge it, and it will always sort and merge first.
1807      * All others are sorted and tested by the number of slashes.
1808      */
1809     if (strcmp(conf->d, "/") == 0)
1810         conf->d_components = 0;
1811     else
1812         conf->d_components = ap_count_dirs(conf->d);
1813
1814     ap_add_per_dir_conf(cmd->server, new_dir_conf);
1815
1816     if (*arg != '\0') {
1817         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1818                            "> arguments not (yet) supported.", NULL);
1819     }
1820
1821     cmd->path = old_path;
1822     cmd->override = old_overrides;
1823
1824     return NULL;
1825 }
1826
1827 static const char *urlsection(cmd_parms *cmd, void *mconfig, const char *arg)
1828 {
1829     const char *errmsg;
1830     const char *endp = ap_strrchr_c(arg, '>');
1831     int old_overrides = cmd->override;
1832     char *old_path = cmd->path;
1833     core_dir_config *conf;
1834     ap_regex_t *r = NULL;
1835     const command_rec *thiscmd = cmd->cmd;
1836     ap_conf_vector_t *new_url_conf = ap_create_per_dir_config(cmd->pool);
1837     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
1838     if (err != NULL) {
1839         return err;
1840     }
1841
1842     if (endp == NULL) {
1843         return unclosed_directive(cmd);
1844     }
1845
1846     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
1847
1848     if (!arg[0]) {
1849         return missing_container_arg(cmd);
1850     }
1851
1852     cmd->path = ap_getword_conf(cmd->pool, &arg);
1853     cmd->override = OR_ALL|ACCESS_CONF;
1854
1855     if (thiscmd->cmd_data) { /* <LocationMatch> */
1856         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED);
1857         if (!r) {
1858             return "Regex could not be compiled";
1859         }
1860     }
1861     else if (!strcmp(cmd->path, "~")) {
1862         cmd->path = ap_getword_conf(cmd->pool, &arg);
1863         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED);
1864         if (!r) {
1865             return "Regex could not be compiled";
1866         }
1867     }
1868
1869     /* initialize our config and fetch it */
1870     conf = ap_set_config_vectors(cmd->server, new_url_conf, cmd->path,
1871                                  &core_module, cmd->pool);
1872
1873     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_url_conf);
1874     if (errmsg != NULL)
1875         return errmsg;
1876
1877     conf->d = apr_pstrdup(cmd->pool, cmd->path);     /* No mangling, please */
1878     conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0;
1879     conf->r = r;
1880
1881     ap_add_per_url_conf(cmd->server, new_url_conf);
1882
1883     if (*arg != '\0') {
1884         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1885                            "> arguments not (yet) supported.", NULL);
1886     }
1887
1888     cmd->path = old_path;
1889     cmd->override = old_overrides;
1890
1891     return NULL;
1892 }
1893
1894 static const char *filesection(cmd_parms *cmd, void *mconfig, const char *arg)
1895 {
1896     const char *errmsg;
1897     const char *endp = ap_strrchr_c(arg, '>');
1898     int old_overrides = cmd->override;
1899     char *old_path = cmd->path;
1900     core_dir_config *conf;
1901     ap_regex_t *r = NULL;
1902     const command_rec *thiscmd = cmd->cmd;
1903     core_dir_config *c = mconfig;
1904     ap_conf_vector_t *new_file_conf = ap_create_per_dir_config(cmd->pool);
1905     const char *err = ap_check_cmd_context(cmd,
1906                                            NOT_IN_LOCATION | NOT_IN_LIMIT);
1907
1908     if (err != NULL) {
1909         return err;
1910     }
1911
1912     if (endp == NULL) {
1913         return unclosed_directive(cmd);
1914     }
1915
1916     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
1917
1918     if (!arg[0]) {
1919         return missing_container_arg(cmd);
1920     }
1921
1922     cmd->path = ap_getword_conf(cmd->pool, &arg);
1923     /* Only if not an .htaccess file */
1924     if (!old_path) {
1925         cmd->override = OR_ALL|ACCESS_CONF;
1926     }
1927
1928     if (thiscmd->cmd_data) { /* <FilesMatch> */
1929         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
1930         if (!r) {
1931             return "Regex could not be compiled";
1932         }
1933     }
1934     else if (!strcmp(cmd->path, "~")) {
1935         cmd->path = ap_getword_conf(cmd->pool, &arg);
1936         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
1937         if (!r) {
1938             return "Regex could not be compiled";
1939         }
1940     }
1941     else {
1942         char *newpath;
1943         /* Ensure that the pathname is canonical, but we
1944          * can't test the case/aliases without a fixed path */
1945         if (apr_filepath_merge(&newpath, "", cmd->path,
1946                                0, cmd->pool) != APR_SUCCESS)
1947                 return apr_pstrcat(cmd->pool, "<Files \"", cmd->path,
1948                                "\"> is invalid.", NULL);
1949         cmd->path = newpath;
1950     }
1951
1952     /* initialize our config and fetch it */
1953     conf = ap_set_config_vectors(cmd->server, new_file_conf, cmd->path,
1954                                  &core_module, cmd->pool);
1955
1956     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_file_conf);
1957     if (errmsg != NULL)
1958         return errmsg;
1959
1960     conf->d = cmd->path;
1961     conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0;
1962     conf->r = r;
1963
1964     ap_add_file_conf(c, new_file_conf);
1965
1966     if (*arg != '\0') {
1967         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1968                            "> arguments not (yet) supported.", NULL);
1969     }
1970
1971     cmd->path = old_path;
1972     cmd->override = old_overrides;
1973
1974     return NULL;
1975 }
1976 static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
1977 {
1978     const char *errmsg;
1979     const char *endp = ap_strrchr_c(arg, '>');
1980     int old_overrides = cmd->override;
1981     char *old_path = cmd->path;
1982     core_dir_config *conf;
1983     const command_rec *thiscmd = cmd->cmd;
1984     core_dir_config *c = mconfig;
1985     ap_conf_vector_t *new_file_conf = ap_create_per_dir_config(cmd->pool);
1986     const char *err = ap_check_cmd_context(cmd,
1987                                            NOT_IN_LOCATION | NOT_IN_LIMIT);
1988     const char *condition;
1989     int expr_err = 0;
1990
1991     if (err != NULL) {
1992         return err;
1993     }
1994
1995     if (endp == NULL) {
1996         return unclosed_directive(cmd);
1997     }
1998
1999     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
2000
2001     if (!arg[0]) {
2002         return missing_container_arg(cmd);
2003     }
2004
2005     condition = ap_getword_conf(cmd->pool, &arg);
2006     /* Only if not an .htaccess file */
2007     if (!old_path) {
2008         cmd->override = OR_ALL|ACCESS_CONF;
2009     }
2010
2011     /* initialize our config and fetch it */
2012     conf = ap_set_config_vectors(cmd->server, new_file_conf, cmd->path,
2013                                  &core_module, cmd->pool);
2014
2015     conf->condition = ap_expr_parse(cmd->pool, condition, &expr_err);
2016     if (expr_err) {
2017         return "Cannot parse condition clause";
2018     }
2019
2020     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_file_conf);
2021     if (errmsg != NULL)
2022         return errmsg;
2023
2024     conf->d = cmd->path;
2025     conf->d_is_fnmatch = 0;
2026     conf->r = NULL;
2027
2028     ap_add_file_conf(c, new_file_conf);
2029
2030     if (*arg != '\0') {
2031         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
2032                            "> arguments not supported.", NULL);
2033     }
2034
2035     cmd->path = old_path;
2036     cmd->override = old_overrides;
2037
2038     return NULL;
2039 }
2040
2041 static module *find_module(server_rec *s, const char *name)
2042 {
2043     module *found = ap_find_linked_module(name);
2044
2045     /* search prelinked stuff */
2046     if (!found) {
2047         ap_module_symbol_t *current = ap_prelinked_module_symbols;
2048
2049         for (; current->name; ++current) {
2050             if (!strcmp(current->name, name)) {
2051                 found = current->modp;
2052                 break;
2053             }
2054         }
2055     }
2056
2057     /* search dynamic stuff */
2058     if (!found) {
2059         APR_OPTIONAL_FN_TYPE(ap_find_loaded_module_symbol) *check_symbol =
2060             APR_RETRIEVE_OPTIONAL_FN(ap_find_loaded_module_symbol);
2061
2062         if (check_symbol) {
2063             /*
2064              * There are two phases where calling ap_find_loaded_module_symbol
2065              * is problematic:
2066              *
2067              * During reading of the config, ap_server_conf is invalid but s
2068              * points to the main server config, if passed from cmd->server
2069              * of an EXEC_ON_READ directive.
2070              *
2071              * During config parsing, s may be a virtual host that would cause
2072              * a segfault in mod_so if passed to ap_find_loaded_module_symbol,
2073              * because mod_so's server config for vhosts is initialized later.
2074              * But ap_server_conf is already set at this time.
2075              *
2076              * Therefore we use s if it is not virtual and ap_server_conf if
2077              * s is virtual.
2078              */
2079             found = check_symbol(s->is_virtual ? ap_server_conf : s, name);
2080         }
2081     }
2082
2083     return found;
2084 }
2085
2086
2087 static const char *start_ifmod(cmd_parms *cmd, void *mconfig, const char *arg)
2088 {
2089     const char *endp = ap_strrchr_c(arg, '>');
2090     int not = (arg[0] == '!');
2091     module *found;
2092
2093     if (endp == NULL) {
2094         return unclosed_directive(cmd);
2095     }
2096
2097     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
2098
2099     if (not) {
2100         arg++;
2101     }
2102
2103     if (!arg[0]) {
2104         return missing_container_arg(cmd);
2105     }
2106
2107     found = find_module(cmd->server, arg);
2108
2109     if ((!not && found) || (not && !found)) {
2110         ap_directive_t *parent = NULL;
2111         ap_directive_t *current = NULL;
2112         const char *retval;
2113
2114         retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
2115                                       &current, &parent, "<IfModule");
2116         *(ap_directive_t **)mconfig = current;
2117         return retval;
2118     }
2119     else {
2120         *(ap_directive_t **)mconfig = NULL;
2121         return ap_soak_end_container(cmd, "<IfModule");
2122     }
2123 }
2124
2125 AP_DECLARE(int) ap_exists_config_define(const char *name)
2126 {
2127     char **defines;
2128     int i;
2129
2130     defines = (char **)ap_server_config_defines->elts;
2131     for (i = 0; i < ap_server_config_defines->nelts; i++) {
2132         if (strcmp(defines[i], name) == 0) {
2133             return 1;
2134         }
2135     }
2136
2137     return 0;
2138 }
2139
2140 static const char *start_ifdefine(cmd_parms *cmd, void *dummy, const char *arg)
2141 {
2142     const char *endp;
2143     int defined;
2144     int not = 0;
2145
2146     endp = ap_strrchr_c(arg, '>');
2147     if (endp == NULL) {
2148         return unclosed_directive(cmd);
2149     }
2150
2151     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
2152
2153     if (arg[0] == '!') {
2154         not = 1;
2155         arg++;
2156     }
2157
2158     if (!arg[0]) {
2159         return missing_container_arg(cmd);
2160     }
2161
2162     defined = ap_exists_config_define(arg);
2163     if ((!not && defined) || (not && !defined)) {
2164         ap_directive_t *parent = NULL;
2165         ap_directive_t *current = NULL;
2166         const char *retval;
2167
2168         retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
2169                                       &current, &parent, "<IfDefine");
2170         *(ap_directive_t **)dummy = current;
2171         return retval;
2172     }
2173     else {
2174         *(ap_directive_t **)dummy = NULL;
2175         return ap_soak_end_container(cmd, "<IfDefine");
2176     }
2177 }
2178
2179 /* httpd.conf commands... beginning with the <VirtualHost> business */
2180
2181 static const char *virtualhost_section(cmd_parms *cmd, void *dummy,
2182                                        const char *arg)
2183 {
2184     server_rec *main_server = cmd->server, *s;
2185     const char *errmsg;
2186     const char *endp = ap_strrchr_c(arg, '>');
2187     apr_pool_t *p = cmd->pool;
2188
2189     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2190     if (err != NULL) {
2191         return err;
2192     }
2193
2194     if (endp == NULL) {
2195         return unclosed_directive(cmd);
2196     }
2197
2198     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
2199
2200     if (!arg[0]) {
2201         return missing_container_arg(cmd);
2202     }
2203
2204     /* FIXME: There's another feature waiting to happen here -- since you
2205         can now put multiple addresses/names on a single <VirtualHost>
2206         you might want to use it to group common definitions and then
2207         define other "subhosts" with their individual differences.  But
2208         personally I'd rather just do it with a macro preprocessor. -djg */
2209     if (main_server->is_virtual) {
2210         return "<VirtualHost> doesn't nest!";
2211     }
2212
2213     errmsg = ap_init_virtual_host(p, arg, main_server, &s);
2214     if (errmsg) {
2215         return errmsg;
2216     }
2217
2218     s->next = main_server->next;
2219     main_server->next = s;
2220
2221     s->defn_name = cmd->directive->filename;
2222     s->defn_line_number = cmd->directive->line_num;
2223
2224     cmd->server = s;
2225
2226     errmsg = ap_walk_config(cmd->directive->first_child, cmd,
2227                             s->lookup_defaults);
2228
2229     cmd->server = main_server;
2230
2231     return errmsg;
2232 }
2233
2234 static const char *set_server_alias(cmd_parms *cmd, void *dummy,
2235                                     const char *arg)
2236 {
2237     if (!cmd->server->names) {
2238         return "ServerAlias only used in <VirtualHost>";
2239     }
2240
2241     while (*arg) {
2242         char **item, *name = ap_getword_conf(cmd->pool, &arg);
2243
2244         if (ap_is_matchexp(name)) {
2245             item = (char **)apr_array_push(cmd->server->wild_names);
2246         }
2247         else {
2248             item = (char **)apr_array_push(cmd->server->names);
2249         }
2250
2251         *item = name;
2252     }
2253
2254     return NULL;
2255 }
2256
2257 static const char *set_accf_map(cmd_parms *cmd, void *dummy,
2258                                 const char *iproto, const char* iaccf)
2259 {
2260     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2261     core_server_config *conf = ap_get_module_config(cmd->server->module_config,
2262                                                     &core_module);
2263     char* proto;
2264     char* accf;
2265     if (err != NULL) {
2266         return err;
2267     }
2268
2269     proto = apr_pstrdup(cmd->pool, iproto);
2270     ap_str_tolower(proto);
2271     accf = apr_pstrdup(cmd->pool, iaccf);
2272     ap_str_tolower(accf);
2273     apr_table_setn(conf->accf_map, proto, accf);
2274
2275     return NULL;
2276 }
2277
2278 AP_DECLARE(const char*) ap_get_server_protocol(server_rec* s)
2279 {
2280     core_server_config *conf = ap_get_module_config(s->module_config,
2281                                                     &core_module);
2282     return conf->protocol;
2283 }
2284
2285 AP_DECLARE(void) ap_set_server_protocol(server_rec* s, const char* proto)
2286 {
2287     core_server_config *conf = ap_get_module_config(s->module_config,
2288                                                     &core_module);
2289     conf->protocol = proto;
2290 }
2291
2292 static const char *set_protocol(cmd_parms *cmd, void *dummy,
2293                                 const char *arg)
2294 {
2295     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
2296     core_server_config *conf = ap_get_module_config(cmd->server->module_config,
2297                                                     &core_module);
2298     char* proto;
2299
2300     if (err != NULL) {
2301         return err;
2302     }
2303
2304     proto = apr_pstrdup(cmd->pool, arg);
2305     ap_str_tolower(proto);
2306     conf->protocol = proto;
2307
2308     return NULL;
2309 }
2310
2311 static const char *set_server_string_slot(cmd_parms *cmd, void *dummy,
2312                                           const char *arg)
2313 {
2314     /* This one's pretty generic... */
2315
2316     int offset = (int)(long)cmd->info;
2317     char *struct_ptr = (char *)cmd->server;
2318
2319     const char *err = ap_check_cmd_context(cmd,
2320                                            NOT_IN_DIR_LOC_FILE);
2321     if (err != NULL) {
2322         return err;
2323     }
2324
2325     *(const char **)(struct_ptr + offset) = arg;
2326     return NULL;
2327 }
2328
2329 /*
2330  * The ServerName directive takes one argument with format
2331  * [scheme://]fully-qualified-domain-name[:port], for instance
2332  * ServerName www.example.com
2333  * ServerName www.example.com:80
2334  * ServerName https://www.example.com:443
2335  */
2336
2337 static const char *server_hostname_port(cmd_parms *cmd, void *dummy, const char *arg)
2338 {
2339     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
2340     const char *portstr, *part;
2341     char *scheme;
2342     int port;
2343
2344     if (err != NULL) {
2345         return err;
2346     }
2347
2348     part = ap_strstr_c(arg, "://");
2349
2350     if (part) {
2351       scheme = apr_pstrndup(cmd->pool, arg, part - arg);
2352       ap_str_tolower(scheme);
2353       cmd->server->server_scheme = (const char *)scheme;
2354       part += 3;
2355     } else {
2356       part = arg;
2357     }
2358
2359     portstr = ap_strchr_c(part, ':');
2360     if (portstr) {
2361         cmd->server->server_hostname = apr_pstrndup(cmd->pool, part,
2362                                                     portstr - part);
2363         portstr++;
2364         port = atoi(portstr);
2365         if (port <= 0 || port >= 65536) { /* 65536 == 1<<16 */
2366             return apr_pstrcat(cmd->temp_pool, "The port number \"", arg,
2367                           "\" is outside the appropriate range "
2368                           "(i.e., 1..65535).", NULL);
2369         }
2370     }
2371     else {
2372         cmd->server->server_hostname = apr_pstrdup(cmd->pool, part);
2373         port = 0;
2374     }
2375
2376     cmd->server->port = port;
2377     return NULL;
2378 }
2379
2380 static const char *set_signature_flag(cmd_parms *cmd, void *d_,
2381                                       const char *arg)
2382 {
2383     core_dir_config *d = d_;
2384
2385     if (strcasecmp(arg, "On") == 0) {
2386         d->server_signature = srv_sig_on;
2387     }
2388     else if (strcasecmp(arg, "Off") == 0) {
2389         d->server_signature = srv_sig_off;
2390     }
2391     else if (strcasecmp(arg, "EMail") == 0) {
2392         d->server_signature = srv_sig_withmail;
2393     }
2394     else {
2395         return "ServerSignature: use one of: off | on | email";
2396     }
2397
2398     return NULL;
2399 }
2400
2401 static const char *set_server_root(cmd_parms *cmd, void *dummy,
2402                                    const char *arg)
2403 {
2404     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2405
2406     if (err != NULL) {
2407         return err;
2408     }
2409
2410     if ((apr_filepath_merge((char**)&ap_server_root, NULL, arg,
2411                             APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS)
2412         || !ap_is_directory(cmd->temp_pool, ap_server_root)) {
2413         return "ServerRoot must be a valid directory";
2414     }
2415
2416     return NULL;
2417 }
2418
2419 static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg)
2420 {
2421     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
2422
2423     if (err != NULL) {
2424         return err;
2425     }
2426
2427     cmd->server->timeout = apr_time_from_sec(atoi(arg));
2428     return NULL;
2429 }
2430
2431 static const char *set_allow2f(cmd_parms *cmd, void *d_, int arg)
2432 {
2433     core_dir_config *d = d_;
2434
2435     d->allow_encoded_slashes = arg != 0;
2436     return NULL;
2437 }
2438
2439 static const char *set_hostname_lookups(cmd_parms *cmd, void *d_,
2440                                         const char *arg)
2441 {
2442     core_dir_config *d = d_;
2443
2444     if (!strcasecmp(arg, "on")) {
2445         d->hostname_lookups = HOSTNAME_LOOKUP_ON;
2446     }
2447     else if (!strcasecmp(arg, "off")) {
2448         d->hostname_lookups = HOSTNAME_LOOKUP_OFF;
2449     }
2450     else if (!strcasecmp(arg, "double")) {
2451         d->hostname_lookups = HOSTNAME_LOOKUP_DOUBLE;
2452     }
2453     else {
2454         return "parameter must be 'on', 'off', or 'double'";
2455     }
2456
2457     return NULL;
2458 }
2459
2460 static const char *set_serverpath(cmd_parms *cmd, void *dummy,
2461                                   const char *arg)
2462 {
2463     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
2464
2465     if (err != NULL) {
2466         return err;
2467     }
2468
2469     cmd->server->path = arg;
2470     cmd->server->pathlen = (int)strlen(arg);
2471     return NULL;
2472 }
2473
2474 static const char *set_content_md5(cmd_parms *cmd, void *d_, int arg)
2475 {
2476     core_dir_config *d = d_;
2477
2478     d->content_md5 = arg != 0;
2479     return NULL;
2480 }
2481
2482 static const char *set_accept_path_info(cmd_parms *cmd, void *d_, const char *arg)
2483 {
2484     core_dir_config *d = d_;
2485
2486     if (strcasecmp(arg, "on") == 0) {
2487         d->accept_path_info = AP_REQ_ACCEPT_PATH_INFO;
2488     }
2489     else if (strcasecmp(arg, "off") == 0) {
2490         d->accept_path_info = AP_REQ_REJECT_PATH_INFO;
2491     }
2492     else if (strcasecmp(arg, "default") == 0) {
2493         d->accept_path_info = AP_REQ_DEFAULT_PATH_INFO;
2494     }
2495     else {
2496         return "AcceptPathInfo must be set to on, off or default";
2497     }
2498
2499     return NULL;
2500 }
2501
2502 static const char *set_use_canonical_name(cmd_parms *cmd, void *d_,
2503                                           const char *arg)
2504 {
2505     core_dir_config *d = d_;
2506
2507     if (strcasecmp(arg, "on") == 0) {
2508         d->use_canonical_name = USE_CANONICAL_NAME_ON;
2509     }
2510     else if (strcasecmp(arg, "off") == 0) {
2511         d->use_canonical_name = USE_CANONICAL_NAME_OFF;
2512     }
2513     else if (strcasecmp(arg, "dns") == 0) {
2514         d->use_canonical_name = USE_CANONICAL_NAME_DNS;
2515     }
2516     else {
2517         return "parameter must be 'on', 'off', or 'dns'";
2518     }
2519
2520     return NULL;
2521 }
2522
2523 static const char *set_use_canonical_phys_port(cmd_parms *cmd, void *d_,
2524                                           const char *arg)
2525 {
2526     core_dir_config *d = d_;
2527
2528     if (strcasecmp(arg, "on") == 0) {
2529         d->use_canonical_phys_port = USE_CANONICAL_PHYS_PORT_ON;
2530     }
2531     else if (strcasecmp(arg, "off") == 0) {
2532         d->use_canonical_phys_port = USE_CANONICAL_PHYS_PORT_OFF;
2533     }
2534     else {
2535         return "parameter must be 'on' or 'off'";
2536     }
2537
2538     return NULL;
2539 }
2540
2541 static const char *include_config (cmd_parms *cmd, void *dummy,
2542                                    const char *name)
2543 {
2544     ap_directive_t *conftree = NULL;
2545     const char *conffile, *error;
2546     unsigned *recursion;
2547     int optional = cmd->cmd->cmd_data ? 1 : 0;
2548     void *data;
2549
2550     apr_pool_userdata_get(&data, "ap_include_sentinel", cmd->pool);
2551     if (data) {
2552         recursion = data;
2553     }
2554     else {
2555         data = recursion = apr_palloc(cmd->pool, sizeof(*recursion));
2556         *recursion = 0;
2557         apr_pool_userdata_setn(data, "ap_include_sentinel", NULL, cmd->pool);
2558     }
2559
2560     if (++*recursion > AP_MAX_INCLUDE_DEPTH) {
2561         *recursion = 0;
2562         return apr_psprintf(cmd->pool, "Exceeded maximum include depth of %u, "
2563                             "There appears to be a recursion.",
2564                             AP_MAX_INCLUDE_DEPTH);
2565     }
2566
2567     conffile = ap_server_root_relative(cmd->pool, name);
2568     if (!conffile) {
2569         *recursion = 0;
2570         return apr_pstrcat(cmd->pool, "Invalid Include path ",
2571                            name, NULL);
2572     }
2573
2574     error = ap_process_fnmatch_configs(cmd->server, conffile, &conftree, 
2575                                        cmd->pool, cmd->temp_pool, 
2576                                        optional);
2577     if (error) {
2578         *recursion = 0;
2579         return error;
2580     }
2581
2582     *(ap_directive_t **)dummy = conftree;
2583
2584     /* recursion level done */
2585     if (*recursion) {
2586         --*recursion;
2587     }
2588
2589     return NULL;
2590 }
2591
2592 static const char *set_loglevel(cmd_parms *cmd, void *config_, const char *arg_)
2593 {
2594     char *level_str;
2595     int level;
2596     module *module;
2597     char *arg = apr_pstrdup(cmd->temp_pool, arg_);
2598     struct ap_logconf *log;
2599     const char *err;
2600
2601     /* XXX: what check is necessary here? */
2602 #if 0
2603     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
2604     if (err != NULL) {
2605         return err;
2606     }
2607 #endif
2608
2609     if (cmd->path) {
2610         core_dir_config *dconf = config_;
2611         if (!dconf->log) {
2612             dconf->log = ap_new_log_config(cmd->pool, NULL);
2613         }
2614         log = dconf->log;
2615     }
2616     else {
2617         log = &cmd->server->log;
2618     }
2619
2620     if (arg == NULL)
2621         return "LogLevel requires level keyword or module loglevel specifier";
2622
2623     level_str = ap_strchr(arg, ':');
2624
2625     if (level_str == NULL) {
2626         err = ap_parse_log_level(arg, &log->level);
2627         if (err != NULL)
2628             return err;
2629         ap_reset_module_loglevels(log, APLOG_NO_MODULE);
2630         ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, cmd->server,
2631                      "Setting LogLevel for all modules to %s", arg);
2632         return NULL;
2633     }
2634
2635     *level_str++ = '\0';
2636     if (!*level_str) {
2637         return apr_psprintf(cmd->temp_pool, "Module specifier '%s' must be "
2638                             "followed by a log level keyword", arg);
2639     }
2640
2641     err = ap_parse_log_level(level_str, &level);
2642     if (err != NULL)
2643         return apr_psprintf(cmd->temp_pool, "%s:%s: %s", arg, level_str, err);
2644
2645     if ((module = find_module(cmd->server, arg)) == NULL) {
2646         char *name = apr_psprintf(cmd->temp_pool, "%s_module", arg);
2647         ap_log_error(APLOG_MARK, APLOG_TRACE6, 0, cmd->server,
2648                      "Cannot find module '%s', trying '%s'", arg, name);
2649         module = find_module(cmd->server, name);
2650     }
2651
2652     if (module == NULL) {
2653         return apr_psprintf(cmd->temp_pool, "Cannot find module %s", arg);
2654     }
2655
2656     ap_set_module_loglevel(cmd->pool, log, module->module_index, level);
2657     ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, cmd->server,
2658                  "Setting LogLevel for module %s to %s", module->name,
2659                  level_str);
2660
2661     return NULL;
2662 }
2663
2664 AP_DECLARE(const char *) ap_psignature(const char *prefix, request_rec *r)
2665 {
2666     char sport[20];
2667     core_dir_config *conf;
2668
2669     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
2670                                                    &core_module);
2671     if ((conf->server_signature == srv_sig_off)
2672             || (conf->server_signature == srv_sig_unset)) {
2673         return "";
2674     }
2675
2676     apr_snprintf(sport, sizeof sport, "%u", (unsigned) ap_get_server_port(r));
2677
2678     if (conf->server_signature == srv_sig_withmail) {
2679         return apr_pstrcat(r->pool, prefix, "<address>",
2680                            ap_get_server_banner(),
2681                            " Server at <a href=\"",
2682                            ap_is_url(r->server->server_admin) ? "" : "mailto:",
2683                            ap_escape_html(r->pool, r->server->server_admin),
2684                            "\">",
2685                            ap_escape_html(r->pool, ap_get_server_name(r)),
2686                            "</a> Port ", sport,
2687                            "</address>\n", NULL);
2688     }
2689
2690     return apr_pstrcat(r->pool, prefix, "<address>", ap_get_server_banner(),
2691                        " Server at ",
2692                        ap_escape_html(r->pool, ap_get_server_name(r)),
2693                        " Port ", sport,
2694                        "</address>\n", NULL);
2695 }
2696
2697 /*
2698  * Handle a request to include the server's OS platform in the Server
2699  * response header field (the ServerTokens directive).  Unfortunately
2700  * this requires a new global in order to communicate the setting back to
2701  * http_main so it can insert the information in the right place in the
2702  * string.
2703  */
2704
2705 static char *server_banner = NULL;
2706 static int banner_locked = 0;
2707 static const char *server_description = NULL;
2708
2709 enum server_token_type {
2710     SrvTk_MAJOR,         /* eg: Apache/2 */
2711     SrvTk_MINOR,         /* eg. Apache/2.0 */
2712     SrvTk_MINIMAL,       /* eg: Apache/2.0.41 */
2713     SrvTk_OS,            /* eg: Apache/2.0.41 (UNIX) */
2714     SrvTk_FULL,          /* eg: Apache/2.0.41 (UNIX) PHP/4.2.2 FooBar/1.2b */
2715     SrvTk_PRODUCT_ONLY  /* eg: Apache */
2716 };
2717 static enum server_token_type ap_server_tokens = SrvTk_FULL;
2718
2719 static apr_status_t reset_banner(void *dummy)
2720 {
2721     banner_locked = 0;
2722     ap_server_tokens = SrvTk_FULL;
2723     server_banner = NULL;
2724     server_description = NULL;
2725     return APR_SUCCESS;
2726 }
2727
2728 AP_DECLARE(void) ap_get_server_revision(ap_version_t *version)
2729 {
2730     version->major = AP_SERVER_MAJORVERSION_NUMBER;
2731     version->minor = AP_SERVER_MINORVERSION_NUMBER;
2732     version->patch = AP_SERVER_PATCHLEVEL_NUMBER;
2733     version->add_string = AP_SERVER_ADD_STRING;
2734 }
2735
2736 AP_DECLARE(const char *) ap_get_server_description(void)
2737 {
2738     return server_description ? server_description :
2739         AP_SERVER_BASEVERSION " (" PLATFORM ")";
2740 }
2741
2742 AP_DECLARE(const char *) ap_get_server_banner(void)
2743 {
2744     return server_banner ? server_banner : AP_SERVER_BASEVERSION;
2745 }
2746
2747 AP_DECLARE(void) ap_add_version_component(apr_pool_t *pconf, const char *component)
2748 {
2749     if (! banner_locked) {
2750         /*
2751          * If the version string is null, register our cleanup to reset the
2752          * pointer on pool destruction. We also know that, if NULL,
2753          * we are adding the original SERVER_BASEVERSION string.
2754          */
2755         if (server_banner == NULL) {
2756             apr_pool_cleanup_register(pconf, NULL, reset_banner,
2757                                       apr_pool_cleanup_null);
2758             server_banner = apr_pstrdup(pconf, component);
2759         }
2760         else {
2761             /*
2762              * Tack the given component identifier to the end of
2763              * the existing string.
2764              */
2765             server_banner = apr_pstrcat(pconf, server_banner, " ",
2766                                         component, NULL);
2767         }
2768     }
2769     server_description = apr_pstrcat(pconf, server_description, " ",
2770                                      component, NULL);
2771 }
2772
2773 /*
2774  * This routine adds the real server base identity to the banner string,
2775  * and then locks out changes until the next reconfig.
2776  */
2777 static void set_banner(apr_pool_t *pconf)
2778 {
2779     if (ap_server_tokens == SrvTk_PRODUCT_ONLY) {
2780         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT);
2781     }
2782     else if (ap_server_tokens == SrvTk_MINIMAL) {
2783         ap_add_version_component(pconf, AP_SERVER_BASEVERSION);
2784     }
2785     else if (ap_server_tokens == SrvTk_MINOR) {
2786         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MINORREVISION);
2787     }
2788     else if (ap_server_tokens == SrvTk_MAJOR) {
2789         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MAJORVERSION);
2790     }
2791     else {
2792         ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ")");
2793     }
2794
2795     /*
2796      * Lock the server_banner string if we're not displaying
2797      * the full set of tokens
2798      */
2799     if (ap_server_tokens != SrvTk_FULL) {
2800         banner_locked++;
2801     }
2802     server_description = AP_SERVER_BASEVERSION " (" PLATFORM ")";
2803 }
2804
2805 static const char *set_serv_tokens(cmd_parms *cmd, void *dummy,
2806                                    const char *arg1, const char *arg2)
2807 {
2808     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2809
2810     if (err != NULL) {
2811         return err;
2812     }
2813
2814     if (!strcasecmp(arg1, "OS")) {
2815         ap_server_tokens = SrvTk_OS;
2816     }
2817     else if (!strcasecmp(arg1, "Min") || !strcasecmp(arg1, "Minimal")) {
2818         ap_server_tokens = SrvTk_MINIMAL;
2819     }
2820     else if (!strcasecmp(arg1, "Major")) {
2821         ap_server_tokens = SrvTk_MAJOR;
2822     }
2823     else if (!strcasecmp(arg1, "Minor") ) {
2824         ap_server_tokens = SrvTk_MINOR;
2825     }
2826     else if (!strcasecmp(arg1, "Prod") || !strcasecmp(arg1, "ProductOnly")) {
2827         ap_server_tokens = SrvTk_PRODUCT_ONLY;
2828     }
2829     else {
2830         ap_server_tokens = SrvTk_FULL;
2831     }
2832
2833     return NULL;
2834 }
2835
2836 static const char *set_limit_req_line(cmd_parms *cmd, void *dummy,
2837                                       const char *arg)
2838 {
2839     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
2840     int lim;
2841
2842     if (err != NULL) {
2843         return err;
2844     }
2845
2846     lim = atoi(arg);
2847     if (lim < 0) {
2848         return apr_pstrcat(cmd->temp_pool, "LimitRequestLine \"", arg,
2849                            "\" must be a non-negative integer", NULL);
2850     }
2851
2852     cmd->server->limit_req_line = lim;
2853     return NULL;
2854 }
2855
2856 static const char *set_limit_req_fieldsize(cmd_parms *cmd, void *dummy,
2857                                            const char *arg)
2858 {
2859     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
2860     int lim;
2861
2862     if (err != NULL) {
2863         return err;
2864     }
2865
2866     lim = atoi(arg);
2867     if (lim < 0) {
2868         return apr_pstrcat(cmd->temp_pool, "LimitRequestFieldsize \"", arg,
2869                           "\" must be a non-negative integer",
2870                           NULL);
2871     }
2872
2873     cmd->server->limit_req_fieldsize = lim;
2874     return NULL;
2875 }
2876
2877 static const char *set_limit_req_fields(cmd_parms *cmd, void *dummy,
2878                                         const char *arg)
2879 {
2880     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
2881     int lim;
2882
2883     if (err != NULL) {
2884         return err;
2885     }
2886
2887     lim = atoi(arg);
2888     if (lim < 0) {
2889         return apr_pstrcat(cmd->temp_pool, "LimitRequestFields \"", arg,
2890                            "\" must be a non-negative integer (0 = no limit)",
2891                            NULL);
2892     }
2893
2894     cmd->server->limit_req_fields = lim;
2895     return NULL;
2896 }
2897
2898 static const char *set_limit_req_body(cmd_parms *cmd, void *conf_,
2899                                       const char *arg)
2900 {
2901     core_dir_config *conf = conf_;
2902     char *errp;
2903
2904     if (APR_SUCCESS != apr_strtoff(&conf->limit_req_body, arg, &errp, 10)) {
2905         return "LimitRequestBody argument is not parsable.";
2906     }
2907     if (*errp || conf->limit_req_body < 0) {
2908         return "LimitRequestBody requires a non-negative integer.";
2909     }
2910
2911     return NULL;
2912 }
2913
2914 static const char *set_limit_xml_req_body(cmd_parms *cmd, void *conf_,
2915                                           const char *arg)
2916 {
2917     core_dir_config *conf = conf_;
2918
2919     conf->limit_xml_body = atol(arg);
2920     if (conf->limit_xml_body < 0)
2921         return "LimitXMLRequestBody requires a non-negative integer.";
2922
2923     return NULL;
2924 }
2925
2926 AP_DECLARE(size_t) ap_get_limit_xml_body(const request_rec *r)
2927 {
2928     core_dir_config *conf;
2929
2930     conf = ap_get_module_config(r->per_dir_config, &core_module);
2931     if (conf->limit_xml_body == AP_LIMIT_UNSET)
2932         return AP_DEFAULT_LIMIT_XML_BODY;
2933
2934     return (size_t)conf->limit_xml_body;
2935 }
2936
2937 #if !defined (RLIMIT_CPU) || !(defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)) || !defined (RLIMIT_NPROC)
2938 static const char *no_set_limit(cmd_parms *cmd, void *conf_,
2939                                 const char *arg, const char *arg2)
2940 {
2941     ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server,
2942                 "%s not supported on this platform", cmd->cmd->name);
2943
2944     return NULL;
2945 }
2946 #endif
2947
2948 #ifdef RLIMIT_CPU
2949 static const char *set_limit_cpu(cmd_parms *cmd, void *conf_,
2950                                  const char *arg, const char *arg2)
2951 {
2952     core_dir_config *conf = conf_;
2953
2954     ap_unixd_set_rlimit(cmd, &conf->limit_cpu, arg, arg2, RLIMIT_CPU);
2955     return NULL;
2956 }
2957 #endif
2958
2959 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)
2960 static const char *set_limit_mem(cmd_parms *cmd, void *conf_,
2961                                  const char *arg, const char * arg2)
2962 {
2963     core_dir_config *conf = conf_;
2964
2965 #if defined(RLIMIT_AS)
2966     ap_unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2 ,RLIMIT_AS);
2967 #elif defined(RLIMIT_DATA)
2968     ap_unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_DATA);
2969 #elif defined(RLIMIT_VMEM)
2970     ap_unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_VMEM);
2971 #endif
2972
2973     return NULL;
2974 }
2975 #endif
2976
2977 #ifdef RLIMIT_NPROC
2978 static const char *set_limit_nproc(cmd_parms *cmd, void *conf_,
2979                                    const char *arg, const char * arg2)
2980 {
2981     core_dir_config *conf = conf_;
2982
2983     ap_unixd_set_rlimit(cmd, &conf->limit_nproc, arg, arg2, RLIMIT_NPROC);
2984     return NULL;
2985 }
2986 #endif
2987
2988 static const char *set_recursion_limit(cmd_parms *cmd, void *dummy,
2989                                        const char *arg1, const char *arg2)
2990 {
2991     core_server_config *conf = ap_get_module_config(cmd->server->module_config,
2992                                                     &core_module);
2993     int limit = atoi(arg1);
2994
2995     if (limit <= 0) {
2996         return "The recursion limit must be greater than zero.";
2997     }
2998     if (limit < 4) {
2999         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
3000                      "Limiting internal redirects to very low numbers may "
3001                      "cause normal requests to fail.");
3002     }
3003
3004     conf->redirect_limit = limit;
3005
3006     if (arg2) {
3007         limit = atoi(arg2);
3008
3009         if (limit <= 0) {
3010             return "The recursion limit must be greater than zero.";
3011         }
3012         if (limit < 4) {
3013             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
3014                          "Limiting the subrequest depth to a very low level may"
3015                          " cause normal requests to fail.");
3016         }
3017     }
3018
3019     conf->subreq_limit = limit;
3020
3021     return NULL;
3022 }
3023
3024 static void log_backtrace(const request_rec *r)
3025 {
3026     const request_rec *top = r;
3027
3028     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
3029                   "r->uri = %s", r->uri ? r->uri : "(unexpectedly NULL)");
3030
3031     while (top && (top->prev || top->main)) {
3032         if (top->prev) {
3033             top = top->prev;
3034             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
3035                           "redirected from r->uri = %s",
3036                           top->uri ? top->uri : "(unexpectedly NULL)");
3037         }
3038
3039         if (!top->prev && top->main) {
3040             top = top->main;
3041             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
3042                           "subrequested from r->uri = %s",
3043                           top->uri ? top->uri : "(unexpectedly NULL)");
3044         }
3045     }
3046 }
3047
3048 /*
3049  * check whether redirect limit is reached
3050  */
3051 AP_DECLARE(int) ap_is_recursion_limit_exceeded(const request_rec *r)
3052 {
3053     core_server_config *conf = ap_get_module_config(r->server->module_config,
3054                                                     &core_module);
3055     const request_rec *top = r;
3056     int redirects = 0, subreqs = 0;
3057     int rlimit = conf->redirect_limit
3058                  ? conf->redirect_limit
3059                  : AP_DEFAULT_MAX_INTERNAL_REDIRECTS;
3060     int slimit = conf->subreq_limit
3061                  ? conf->subreq_limit
3062                  : AP_DEFAULT_MAX_SUBREQ_DEPTH;
3063
3064
3065     while (top->prev || top->main) {
3066         if (top->prev) {
3067             if (++redirects >= rlimit) {
3068                 /* uuh, too much. */
3069                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3070                               "Request exceeded the limit of %d internal "
3071                               "redirects due to probable configuration error. "
3072                               "Use 'LimitInternalRecursion' to increase the "
3073                               "limit if necessary. Use 'LogLevel debug' to get "
3074                               "a backtrace.", rlimit);
3075
3076                 /* post backtrace */
3077                 log_backtrace(r);
3078
3079                 /* return failure */
3080                 return 1;
3081             }
3082
3083             top = top->prev;
3084         }
3085
3086         if (!top->prev && top->main) {
3087             if (++subreqs >= slimit) {
3088                 /* uuh, too much. */
3089                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3090                               "Request exceeded the limit of %d subrequest "
3091                               "nesting levels due to probable configuration "
3092                               "error. Use 'LimitInternalRecursion' to increase "
3093                               "the limit if necessary. Use 'LogLevel debug' to "
3094                               "get a backtrace.", slimit);
3095
3096                 /* post backtrace */
3097                 log_backtrace(r);
3098
3099                 /* return failure */
3100                 return 1;
3101             }
3102
3103             top = top->main;
3104         }
3105     }
3106
3107     /* recursion state: ok */
3108     return 0;
3109 }
3110
3111 static const char *set_trace_enable(cmd_parms *cmd, void *dummy,
3112                                     const char *arg1)
3113 {
3114     core_server_config *conf = ap_get_module_config(cmd->server->module_config,
3115                                                     &core_module);
3116
3117     if (strcasecmp(arg1, "on") == 0) {
3118         conf->trace_enable = AP_TRACE_ENABLE;
3119     }
3120     else if (strcasecmp(arg1, "off") == 0) {
3121         conf->trace_enable = AP_TRACE_DISABLE;
3122     }
3123     else if (strcasecmp(arg1, "extended") == 0) {
3124         conf->trace_enable = AP_TRACE_EXTENDED;
3125     }
3126     else {
3127         return "TraceEnable must be one of 'on', 'off', or 'extended'";
3128     }
3129
3130     return NULL;
3131 }
3132
3133 static apr_hash_t *errorlog_hash;
3134
3135 static int log_constant_item(const ap_errorlog_info *info, const char *arg,
3136                              char *buf, int buflen)
3137 {
3138     char *end = apr_cpystrn(buf, arg, buflen);
3139     return end - buf;
3140 }
3141
3142 static char *parse_errorlog_misc_string(apr_pool_t *p,
3143                                         ap_errorlog_format_item *it,
3144                                         const char **sa)
3145 {
3146     const char *s;
3147     char scratch[MAX_STRING_LEN];
3148     char *d = scratch;
3149     /*
3150      * non-leading white space terminates this string to allow the next field
3151      * separator to be inserted
3152      */
3153     int at_start = 1;
3154
3155     it->func = log_constant_item;
3156     s = *sa;
3157
3158     while (*s && *s != '%' && (*s != ' ' || at_start) && d < scratch + MAX_STRING_LEN) {
3159         if (*s != '\\') {
3160             if (*s != ' ') {
3161                 at_start = 0;
3162             }
3163             *d++ = *s++;
3164         }
3165         else {
3166             s++;
3167             switch (*s) {
3168             case 'r':
3169                 *d++ = '\r';
3170                 s++;
3171                 break;
3172             case 'n':
3173                 *d++ = '\n';
3174                 s++;
3175                 break;
3176             case 't':
3177                 *d++ = '\t';
3178                 s++;
3179                 break;
3180             case '\0':
3181                 /* handle end of string */
3182                 *d++ = '\\';
3183                 break;
3184             default:
3185                 /* copy next char verbatim */
3186                 *d++ = *s++;
3187                 break;
3188             }
3189         }
3190     }
3191     *d = '\0';
3192     it->arg = apr_pstrdup(p, scratch);
3193
3194     *sa = s;
3195     return NULL;
3196 }
3197
3198 static char *parse_errorlog_item(apr_pool_t *p, ap_errorlog_format_item *it,
3199                                  const char **sa)
3200 {
3201     const char *s = *sa;
3202     ap_errorlog_handler *handler;
3203     int i;
3204
3205     if (*s != '%') {
3206         if (*s == ' ') {
3207             it->flags |= AP_ERRORLOG_FLAG_FIELD_SEP;
3208         }
3209         return parse_errorlog_misc_string(p, it, sa);
3210     }
3211
3212     ++s;
3213
3214     if (*s == ' ') {
3215         /* percent-space (% ) is a field separator */
3216         it->flags |= AP_ERRORLOG_FLAG_FIELD_SEP;
3217         *sa = ++s;
3218         /* recurse */
3219         return parse_errorlog_item(p, it, sa);
3220     }
3221     else if (*s == '%') {
3222         it->arg = "%";
3223         it->func = log_constant_item;
3224         *sa = ++s;
3225         return NULL;
3226     }
3227
3228     while (*s) {
3229         switch (*s) {
3230         case '{':
3231             ++s;
3232             it->arg = ap_getword(p, &s, '}');
3233             break;
3234         case '+':
3235             ++s;
3236             it->flags |= AP_ERRORLOG_FLAG_REQUIRED;
3237             break;
3238         case '-':
3239             ++s;
3240             it->flags |= AP_ERRORLOG_FLAG_NULL_AS_HYPHEN;
3241             break;
3242         case '0':
3243         case '1':
3244         case '2':
3245         case '3':
3246         case '4':
3247         case '5':
3248         case '6':
3249         case '7':
3250         case '8':
3251         case '9':
3252             i = *s - '0';
3253             while (apr_isdigit(*++s))
3254                 i = i * 10 + (*s) - '0';
3255             it->min_loglevel = i;
3256             break;
3257         case 'M':
3258             it->func = NULL;
3259             it->flags |= AP_ERRORLOG_FLAG_MESSAGE;
3260             *sa = ++s;
3261             return NULL;
3262         default:
3263             handler = (ap_errorlog_handler *)apr_hash_get(errorlog_hash, s, 1);
3264             if (!handler) {
3265                 char dummy[2];
3266
3267                 dummy[0] = *s;
3268                 dummy[1] = '\0';
3269                 return apr_pstrcat(p, "Unrecognized error log format directive %",
3270                                dummy, NULL);
3271             }
3272             it->func = handler->func;
3273             *sa = ++s;
3274             return NULL;
3275         }
3276     }
3277
3278     return "Ran off end of error log format parsing args to some directive";
3279 }
3280
3281 static apr_array_header_t *parse_errorlog_string(apr_pool_t *p,
3282                                                  const char *s,
3283                                                  const char **err,
3284                                                  int is_main_fmt)
3285 {
3286     apr_array_header_t *a = apr_array_make(p, 30,
3287                                            sizeof(ap_errorlog_format_item));
3288     char *res;
3289     int seen_msg_fmt = 0;
3290
3291     while (s && *s) {
3292         ap_errorlog_format_item *item =
3293             (ap_errorlog_format_item *)apr_array_push(a);
3294         memset(item, 0, sizeof(*item));
3295         res = parse_errorlog_item(p, item, &s);
3296         if (res) {
3297             *err = res;
3298             return NULL;
3299         }
3300         if (item->flags & AP_ERRORLOG_FLAG_MESSAGE) {
3301             if (!is_main_fmt) {
3302                 *err = "%M cannot be used in once-per-request or "
3303                        "once-per-connection formats";
3304                 return NULL;
3305             }
3306             seen_msg_fmt = 1;
3307         }
3308         if (is_main_fmt && item->flags & AP_ERRORLOG_FLAG_REQUIRED) {
3309             *err = "The '+' flag cannot be used in the main error log format";
3310             return NULL;
3311         }
3312         if (!is_main_fmt && item->min_loglevel) {
3313             *err = "The loglevel cannot be used as a condition in "
3314                    "once-per-request or once-per-connection formats";
3315             return NULL;
3316         }
3317         if (item->min_loglevel > APLOG_TRACE8) {
3318             *err = "The specified loglevel modifier is out of range";
3319             return NULL;
3320         }
3321     }
3322
3323     if (is_main_fmt && !seen_msg_fmt) {
3324         *err = "main ErrorLogFormat must contain message format string '%M'";
3325         return NULL;
3326     }
3327
3328     return a;
3329 }
3330
3331 static const char *set_errorlog_format(cmd_parms *cmd, void *dummy,
3332                                        const char *arg1, const char *arg2)
3333 {
3334     const char *err_string = NULL;
3335     core_server_config *conf = ap_get_module_config(cmd->server->module_config,
3336                                                     &core_module);
3337
3338     if (!arg2) {
3339         conf->error_log_format = parse_errorlog_string(cmd->pool, arg1,
3340                                                        &err_string, 1);
3341     }
3342     else if (!strcasecmp(arg1, "connection")) {
3343         if (!conf->error_log_conn) {
3344             conf->error_log_conn = apr_array_make(cmd->pool, 5,
3345                                                   sizeof(apr_array_header_t *));
3346         }
3347
3348         if (*arg2) {
3349             apr_array_header_t **e;
3350             e = (apr_array_header_t **) apr_array_push(conf->error_log_conn);
3351             *e = parse_errorlog_string(cmd->pool, arg2, &err_string, 0);
3352         }
3353     }
3354     else if (!strcasecmp(arg1, "request")) {
3355         if (!conf->error_log_req) {
3356             conf->error_log_req = apr_array_make(cmd->pool, 5,
3357                                                  sizeof(apr_array_header_t *));
3358         }
3359
3360         if (*arg2) {
3361             apr_array_header_t **e;
3362             e = (apr_array_header_t **) apr_array_push(conf->error_log_req);
3363             *e = parse_errorlog_string(cmd->pool, arg2, &err_string, 0);
3364         }
3365     }
3366     else {
3367         err_string = "ErrorLogFormat type must be one of request, connection";
3368     }
3369
3370     return err_string;
3371 }
3372
3373 AP_DECLARE(void) ap_register_errorlog_handler(apr_pool_t *p, char *tag,
3374                                               ap_errorlog_handler_fn_t *handler,
3375                                               int flags)
3376 {
3377     ap_errorlog_handler *log_struct = apr_palloc(p, sizeof(*log_struct));
3378     log_struct->func = handler;
3379     log_struct->flags = flags;
3380
3381     apr_hash_set(errorlog_hash, tag, 1, (const void *)log_struct);
3382 }
3383
3384
3385 /* Note --- ErrorDocument will now work from .htaccess files.
3386  * The AllowOverride of Fileinfo allows webmasters to turn it off
3387  */
3388
3389 static const command_rec core_cmds[] = {
3390
3391 /* Old access config file commands */
3392
3393 AP_INIT_RAW_ARGS("<Directory", dirsection, NULL, RSRC_CONF,
3394   "Container for directives affecting resources located in the specified "
3395   "directories"),
3396 AP_INIT_RAW_ARGS("<Location", urlsection, NULL, RSRC_CONF,
3397   "Container for directives affecting resources accessed through the "
3398   "specified URL paths"),
3399 AP_INIT_RAW_ARGS("<VirtualHost", virtualhost_section, NULL, RSRC_CONF,
3400   "Container to map directives to a particular virtual host, takes one or "
3401   "more host addresses"),
3402 AP_INIT_RAW_ARGS("<Files", filesection, NULL, OR_ALL,
3403   "Container for directives affecting files matching specified patterns"),
3404 AP_INIT_RAW_ARGS("<Limit", ap_limit_section, NULL, OR_LIMIT | OR_AUTHCFG,
3405   "Container for authentication directives when accessed using specified HTTP "
3406   "methods"),
3407 AP_INIT_RAW_ARGS("<LimitExcept", ap_limit_section, (void*)1,
3408                  OR_LIMIT | OR_AUTHCFG,
3409   "Container for authentication directives to be applied when any HTTP "
3410   "method other than those specified is used to access the resource"),
3411 AP_INIT_TAKE1("<IfModule", start_ifmod, NULL, EXEC_ON_READ | OR_ALL,
3412   "Container for directives based on existence of specified modules"),
3413 AP_INIT_TAKE1("<IfDefine", start_ifdefine, NULL, EXEC_ON_READ | OR_ALL,
3414   "Container for directives based on existence of command line defines"),
3415 AP_INIT_RAW_ARGS("<DirectoryMatch", dirsection, (void*)1, RSRC_CONF,
3416   "Container for directives affecting resources located in the "
3417   "specified directories"),
3418 AP_INIT_RAW_ARGS("<LocationMatch", urlsection, (void*)1, RSRC_CONF,
3419   "Container for directives affecting resources accessed through the "
3420   "specified URL paths"),
3421 AP_INIT_RAW_ARGS("<FilesMatch", filesection, (void*)1, OR_ALL,
3422   "Container for directives affecting files matching specified patterns"),
3423 #ifdef GPROF
3424 AP_INIT_TAKE1("GprofDir", set_gprof_dir, NULL, RSRC_CONF,
3425   "Directory to plop gmon.out files"),
3426 #endif
3427 AP_INIT_TAKE1("AddDefaultCharset", set_add_default_charset, NULL, OR_FILEINFO,
3428   "The name of the default charset to add to any Content-Type without one or 'Off' to disable"),
3429 AP_INIT_TAKE1("AcceptPathInfo", set_accept_path_info, NULL, OR_FILEINFO,
3430   "Set to on or off for PATH_INFO to be accepted by handlers, or default for the per-handler preference"),
3431 AP_INIT_TAKE1("Define", set_define, NULL, RSRC_CONF,
3432               "Define the existence of a variable.  Same as passing -D to the command line."),
3433 AP_INIT_TAKE1("UnDefine", unset_define, NULL, RSRC_CONF,
3434               "Undefine the existence of a variable. Undo a Define."),
3435 AP_INIT_RAW_ARGS("<If", ifsection, NULL, OR_ALL,
3436   "Container for directives to be conditionally applied"),
3437
3438 /* Old resource config file commands */
3439
3440 AP_INIT_RAW_ARGS("AccessFileName", set_access_name, NULL, RSRC_CONF,
3441   "Name(s) of per-directory config files (default: .htaccess)"),
3442 AP_INIT_TAKE1("DocumentRoot", set_document_root, NULL, RSRC_CONF,
3443   "Root directory of the document tree"),
3444 AP_INIT_TAKE2("ErrorDocument", set_error_document, NULL, OR_FILEINFO,
3445   "Change responses for HTTP errors"),
3446 AP_INIT_RAW_ARGS("AllowOverride", set_override, NULL, ACCESS_CONF,
3447   "Controls what groups of directives can be configured by per-directory "
3448   "config files"),
3449 AP_INIT_RAW_ARGS("Options", set_options, NULL, OR_OPTIONS,
3450   "Set a number of attributes for a given directory"),
3451 AP_INIT_TAKE1("DefaultType", set_default_type, NULL, OR_FILEINFO,
3452   "the default media type for otherwise untyped files (DEPRECATED)"),
3453 AP_INIT_RAW_ARGS("FileETag", set_etag_bits, NULL, OR_FILEINFO,
3454   "Specify components used to construct a file's ETag"),
3455 AP_INIT_TAKE1("EnableMMAP", set_enable_mmap, NULL, OR_FILEINFO,
3456   "Controls whether memory-mapping may be used to read files"),
3457 AP_INIT_TAKE1("EnableSendfile", set_enable_sendfile, NULL, OR_FILEINFO,
3458   "Controls whether sendfile may be used to transmit files"),
3459
3460 /* Old server config file commands */
3461
3462 AP_INIT_TAKE1("Protocol", set_protocol, NULL, RSRC_CONF,
3463   "Set the Protocol for httpd to use."),
3464 AP_INIT_TAKE2("AcceptFilter", set_accf_map, NULL, RSRC_CONF,
3465   "Set the Accept Filter to use for a protocol"),
3466 AP_INIT_TAKE1("Port", ap_set_deprecated, NULL, RSRC_CONF,
3467   "Port was replaced with Listen in Apache 2.0"),
3468 AP_INIT_TAKE1("HostnameLookups", set_hostname_lookups, NULL,
3469   ACCESS_CONF|RSRC_CONF,
3470   "\"on\" to enable, \"off\" to disable reverse DNS lookups, or \"double\" to "
3471   "enable double-reverse DNS lookups"),
3472 AP_INIT_TAKE1("ServerAdmin", set_server_string_slot,
3473   (void *)APR_OFFSETOF(server_rec, server_admin), RSRC_CONF,
3474   "The email address of the server administrator"),
3475 AP_INIT_TAKE1("ServerName", server_hostname_port, NULL, RSRC_CONF,
3476   "The hostname and port of the server"),
3477 AP_INIT_TAKE1("ServerSignature", set_signature_flag, NULL, OR_ALL,
3478   "En-/disable server signature (on|off|email)"),
3479 AP_INIT_TAKE1("ServerRoot", set_server_root, NULL, RSRC_CONF | EXEC_ON_READ,
3480   "Common directory of server-related files (logs, confs, etc.)"),
3481 AP_INIT_TAKE1("ErrorLog", set_server_string_slot,
3482   (void *)APR_OFFSETOF(server_rec, error_fname), RSRC_CONF,
3483   "The filename of the error log"),
3484 AP_INIT_TAKE12("ErrorLogFormat", set_errorlog_format, NULL, RSRC_CONF,
3485   "Format string for the ErrorLog"),
3486 AP_INIT_RAW_ARGS("ServerAlias", set_server_alias, NULL, RSRC_CONF,
3487   "A name or names alternately used to access the server"),
3488 AP_INIT_TAKE1("ServerPath", set_serverpath, NULL, RSRC_CONF,
3489   "The pathname the server can be reached at"),
3490 AP_INIT_TAKE1("Timeout", set_timeout, NULL, RSRC_CONF,
3491   "Timeout duration (sec)"),
3492 AP_INIT_FLAG("ContentDigest", set_content_md5, NULL, OR_OPTIONS,
3493   "whether or not to send a Content-MD5 header with each request"),
3494 AP_INIT_TAKE1("UseCanonicalName", set_use_canonical_name, NULL,
3495   RSRC_CONF|ACCESS_CONF,
3496   "How to work out the ServerName : Port when constructing URLs"),
3497 AP_INIT_TAKE1("UseCanonicalPhysicalPort", set_use_canonical_phys_port, NULL,
3498   RSRC_CONF|ACCESS_CONF,
3499   "Whether to use the physical Port when constructing URLs"),
3500 /* TODO: RlimitFoo should all be part of mod_cgi, not in the core */
3501 /* TODO: ListenBacklog in MPM */
3502 AP_INIT_TAKE1("Include", include_config, NULL,
3503   (RSRC_CONF | ACCESS_CONF | EXEC_ON_READ),
3504   "Name(s) of the config file(s) to be included; fails if the wildcard does "
3505   "not match at least one file"),
3506 AP_INIT_TAKE1("IncludeOptional", include_config, (void*)1,
3507   (RSRC_CONF | ACCESS_CONF | EXEC_ON_READ),
3508   "Name or pattern of the config file(s) to be included; ignored if the file "
3509   "does not exist or the pattern does not match any files"),
3510 AP_INIT_ITERATE("LogLevel", set_loglevel, NULL, RSRC_CONF|ACCESS_CONF,
3511   "Level of verbosity in error logging"),
3512 AP_INIT_TAKE1("NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF,
3513   "A numeric IP address:port, or the name of a host"),
3514 AP_INIT_TAKE12("ServerTokens", set_serv_tokens, NULL, RSRC_CONF,
3515   "Determine tokens displayed in the Server: header - Min(imal), "
3516   "Major, Minor, Prod, OS or Full"),
3517 AP_INIT_TAKE1("LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF,
3518   "Limit on maximum size of an HTTP request line"),
3519 AP_INIT_TAKE1("LimitRequestFieldsize", set_limit_req_fieldsize, NULL,
3520   RSRC_CONF,
3521   "Limit on maximum size of an HTTP request header field"),
3522 AP_INIT_TAKE1("LimitRequestFields", set_limit_req_fields, NULL, RSRC_CONF,
3523   "Limit (0 = unlimited) on max number of header fields in a request message"),
3524 AP_INIT_TAKE1("LimitRequestBody", set_limit_req_body,
3525   (void*)APR_OFFSETOF(core_dir_config, limit_req_body), OR_ALL,
3526   "Limit (in bytes) on maximum size of request message body"),
3527 AP_INIT_TAKE1("LimitXMLRequestBody", set_limit_xml_req_body, NULL, OR_ALL,
3528               "Limit (in bytes) on maximum size of an XML-based request "
3529               "body"),
3530 AP_INIT_RAW_ARGS("Mutex", ap_set_mutex, NULL, RSRC_CONF,
3531                  "mutex (or \"default\") and mechanism"),
3532
3533 /* System Resource Controls */
3534 #ifdef RLIMIT_CPU
3535 AP_INIT_TAKE12("RLimitCPU", set_limit_cpu,
3536   (void*)APR_OFFSETOF(core_dir_config, limit_cpu),
3537   OR_ALL, "Soft/hard limits for max CPU usage in seconds"),
3538 #else
3539 AP_INIT_TAKE12("RLimitCPU", no_set_limit, NULL,
3540   OR_ALL, "Soft/hard limits for max CPU usage in seconds"),
3541 #endif
3542 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined (RLIMIT_AS)
3543 AP_INIT_TAKE12("RLimitMEM", set_limit_mem,
3544   (void*)APR_OFFSETOF(core_dir_config, limit_mem),
3545   OR_ALL, "Soft/hard limits for max memory usage per process"),
3546 #else
3547 AP_INIT_TAKE12("RLimitMEM", no_set_limit, NULL,
3548   OR_ALL, "Soft/hard limits for max memory usage per process"),
3549 #endif
3550 #ifdef RLIMIT_NPROC
3551 AP_INIT_TAKE12("RLimitNPROC", set_limit_nproc,
3552   (void*)APR_OFFSETOF(core_dir_config, limit_nproc),
3553   OR_ALL, "soft/hard limits for max number of processes per uid"),
3554 #else
3555 AP_INIT_TAKE12("RLimitNPROC", no_set_limit, NULL,
3556    OR_ALL, "soft/hard limits for max number of processes per uid"),
3557 #endif
3558
3559 /* internal recursion stopper */
3560 AP_INIT_TAKE12("LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF,
3561               "maximum recursion depth of internal redirects and subrequests"),
3562
3563 AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower,
3564        (void *)APR_OFFSETOF(core_dir_config, mime_type), OR_FILEINFO,
3565      "a mime type that overrides other configured type"),
3566 AP_INIT_TAKE1("SetHandler", ap_set_string_slot_lower,
3567        (void *)APR_OFFSETOF(core_dir_config, handler), OR_FILEINFO,
3568    "a handler name that overrides any other configured handler"),
3569 AP_INIT_TAKE1("SetOutputFilter", ap_set_string_slot,
3570        (void *)APR_OFFSETOF(core_dir_config, output_filters), OR_FILEINFO,
3571    "filter (or ; delimited list of filters) to be run on the request content"),
3572 AP_INIT_TAKE1("SetInputFilter", ap_set_string_slot,
3573        (void *)APR_OFFSETOF(core_dir_config, input_filters), OR_FILEINFO,
3574    "filter (or ; delimited list of filters) to be run on the request body"),
3575 AP_INIT_FLAG("AllowEncodedSlashes", set_allow2f, NULL, RSRC_CONF,
3576              "Allow URLs containing '/' encoded as '%2F'"),
3577
3578 /* scoreboard.c directives */
3579 AP_INIT_TAKE1("ScoreboardFile", ap_set_scoreboard, NULL, RSRC_CONF,
3580               "A file for Apache to maintain runtime process management information"),
3581 AP_INIT_FLAG("ExtendedStatus", ap_set_extended_status, NULL, RSRC_CONF,
3582              "\"On\" to track extended status information, \"Off\" to disable"),
3583 AP_INIT_FLAG("SeeRequestTail", ap_set_reqtail, NULL, RSRC_CONF,
3584              "For extended status, \"On\" to see the last 63 chars of "
3585              "the request line, \"Off\" (default) to see the first 63"),
3586
3587 /*
3588  * These are default configuration directives that mpms can/should
3589  * pay attention to.
3590  * XXX These are not for all platforms, and even some Unix MPMs might not want
3591  * some directives.
3592  */
3593 AP_INIT_TAKE1("PidFile",  ap_mpm_set_pidfile, NULL, RSRC_CONF,
3594               "A file for logging the server process ID"),
3595 AP_INIT_TAKE1("MaxRequestsPerChild", ap_mpm_set_max_requests, NULL, RSRC_CONF,
3596               "Maximum number of connections a particular child serves before "
3597               "dying. (DEPRECATED, use MaxConnectionsPerChild)"),
3598 AP_INIT_TAKE1("MaxConnectionsPerChild", ap_mpm_set_max_requests, NULL, RSRC_CONF,
3599               "Maximum number of connections a particular child serves before dying."),
3600 AP_INIT_TAKE1("CoreDumpDirectory", ap_mpm_set_coredumpdir, NULL, RSRC_CONF,
3601               "The location of the directory Apache changes to before dumping core"),
3602 AP_INIT_TAKE1("MaxMemFree", ap_mpm_set_max_mem_free, NULL, RSRC_CONF,
3603               "Maximum number of 1k blocks a particular childs allocator may hold."),
3604 AP_INIT_TAKE1("ThreadStackSize", ap_mpm_set_thread_stacksize, NULL, RSRC_CONF,
3605               "Size in bytes of stack used by threads handling client connections"),
3606 #if AP_ENABLE_EXCEPTION_HOOK
3607 AP_INIT_TAKE1("EnableExceptionHook", ap_mpm_set_exception_hook, NULL, RSRC_CONF,
3608               "Controls whether exception hook may be called after a crash"),
3609 #endif
3610 AP_INIT_TAKE1("TraceEnable", set_trace_enable, NULL, RSRC_CONF,
3611               "'on' (default), 'off' or 'extended' to trace request body content"),
3612 { NULL }
3613 };
3614
3615 /*****************************************************************
3616  *
3617  * Core handlers for various phases of server operation...
3618  */
3619
3620 AP_DECLARE_NONSTD(int) ap_core_translate(request_rec *r)
3621 {
3622     void *sconf = r->server->module_config;
3623     core_server_config *conf = ap_get_module_config(sconf, &core_module);
3624     apr_status_t rv;
3625
3626     /* XXX this seems too specific, this should probably become
3627      * some general-case test
3628      */
3629     if (r->proxyreq) {
3630         return HTTP_FORBIDDEN;
3631     }
3632     if (!r->uri || ((r->uri[0] != '/') && strcmp(r->uri, "*"))) {
3633         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3634                      "Invalid URI in request %s", r->the_request);
3635         return HTTP_BAD_REQUEST;
3636     }
3637
3638     if (r->server->path
3639         && !strncmp(r->uri, r->server->path, r->server->pathlen)
3640         && (r->server->path[r->server->pathlen - 1] == '/'
3641             || r->uri[r->server->pathlen] == '/'
3642             || r->uri[r->server->pathlen] == '\0'))
3643     {
3644         /* skip all leading /'s (e.g. http://localhost///foo)
3645          * so we are looking at only the relative path.
3646          */
3647         char *path = r->uri + r->server->pathlen;
3648         while (*path == '/') {
3649             ++path;
3650         }
3651         if ((rv = apr_filepath_merge(&r->filename, conf->ap_document_root, path,
3652                                      APR_FILEPATH_TRUENAME
3653                                    | APR_FILEPATH_SECUREROOT, r->pool))
3654                     != APR_SUCCESS) {
3655             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
3656                          "Cannot map %s to file", r->the_request);
3657             return HTTP_FORBIDDEN;
3658         }
3659         r->canonical_filename = r->filename;
3660     }
3661     else {
3662         /*
3663          * Make sure that we do not mess up the translation by adding two
3664          * /'s in a row.  This happens under windows when the document
3665          * root ends with a /
3666          */
3667         /* skip all leading /'s (e.g. http://localhost///foo)
3668          * so we are looking at only the relative path.
3669          */
3670         char *path = r->uri;
3671         while (*path == '/') {
3672             ++path;
3673         }
3674         if ((rv = apr_filepath_merge(&r->filename, conf->ap_document_root, path,
3675                                      APR_FILEPATH_TRUENAME
3676                                    | APR_FILEPATH_SECUREROOT, r->pool))
3677                     != APR_SUCCESS) {
3678             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
3679                          "Cannot map %s to file", r->the_request);
3680             return HTTP_FORBIDDEN;
3681         }
3682         r->canonical_filename = r->filename;
3683     }
3684
3685     return OK;
3686 }
3687
3688 /*****************************************************************
3689  *
3690  * Test the filesystem name through directory_walk and file_walk
3691  */
3692 static int core_map_to_storage(request_rec *r)
3693 {
3694     int access_status;
3695
3696     if ((access_status = ap_directory_walk(r))) {
3697         return access_status;
3698     }
3699
3700     if ((access_status = ap_file_walk(r))) {
3701         return access_status;
3702     }
3703
3704     return OK;
3705 }
3706
3707
3708 static int do_nothing(request_rec *r) { return OK; }
3709
3710
3711 static int core_override_type(request_rec *r)
3712 {
3713     core_dir_config *conf =
3714         (core_dir_config *)ap_get_module_config(r->per_dir_config,
3715                                                 &core_module);
3716
3717     /* Check for overrides with ForceType / SetHandler
3718      */
3719     if (conf->mime_type && strcmp(conf->mime_type, "none"))
3720         ap_set_content_type(r, (char*) conf->mime_type);
3721
3722     if (conf->handler && strcmp(conf->handler, "none"))
3723         r->handler = conf->handler;
3724
3725     /* Deal with the poor soul who is trying to force path_info to be
3726      * accepted within the core_handler, where they will let the subreq
3727      * address its contents.  This is toggled by the user in the very
3728      * beginning of the fixup phase, so modules should override the user's
3729      * discretion in their own module fixup phase.  It is tristate, if
3730      * the user doesn't specify, the result is 2 (which the module may
3731      * interpret to its own customary behavior.)  It won't be touched
3732      * if the value is no longer undefined (2), so any module changing
3733      * the value prior to the fixup phase OVERRIDES the user's choice.
3734      */
3735     if ((r->used_path_info == AP_REQ_DEFAULT_PATH_INFO)
3736         && (conf->accept_path_info != 3)) {
3737         r->used_path_info = conf->accept_path_info;
3738     }
3739
3740     return OK;
3741 }
3742
3743 static int default_handler(request_rec *r)
3744 {
3745     conn_rec *c = r->connection;
3746     apr_bucket_brigade *bb;
3747     apr_bucket *e;
3748     core_dir_config *d;
3749     int errstatus;
3750     apr_file_t *fd = NULL;
3751     apr_status_t status;
3752     /* XXX if/when somebody writes a content-md5 filter we either need to
3753      *     remove this support or coordinate when to use the filter vs.
3754      *     when to use this code
3755      *     The current choice of when to compute the md5 here matches the 1.3
3756      *     support fairly closely (unlike 1.3, we don't handle computing md5
3757      *     when the charset is translated).
3758      */
3759     int bld_content_md5;
3760
3761     d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
3762                                                 &core_module);
3763     bld_content_md5 = (d->content_md5 & 1)
3764                       && r->output_filters->frec->ftype != AP_FTYPE_RESOURCE;
3765
3766     ap_allow_standard_methods(r, MERGE_ALLOW, M_GET, M_OPTIONS, M_POST, -1);
3767
3768     /* If filters intend to consume the request body, they must
3769      * register an InputFilter to slurp the contents of the POST
3770      * data from the POST input stream.  It no longer exists when
3771      * the output filters are invoked by the default handler.
3772      */
3773     if ((errstatus = ap_discard_request_body(r)) != OK) {
3774         return errstatus;
3775     }
3776
3777     if (r->method_number == M_GET || r->method_number == M_POST) {
3778         if (r->finfo.filetype == APR_NOFILE) {
3779             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3780                           "File does not exist: %s", r->filename);
3781             return HTTP_NOT_FOUND;
3782         }
3783
3784         /* Don't try to serve a dir.  Some OSs do weird things with
3785          * raw I/O on a dir.
3786          */
3787         if (r->finfo.filetype == APR_DIR) {
3788             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3789                           "Attempt to serve directory: %s", r->filename);
3790             return HTTP_NOT_FOUND;
3791         }
3792
3793         if ((r->used_path_info != AP_REQ_ACCEPT_PATH_INFO) &&
3794             r->path_info && *r->path_info)
3795         {
3796             /* default to reject */
3797             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3798                           "File does not exist: %s",
3799                           apr_pstrcat(r->pool, r->filename, r->path_info, NULL));
3800             return HTTP_NOT_FOUND;
3801         }
3802
3803         /* We understood the (non-GET) method, but it might not be legal for
3804            this particular resource. Check to see if the 'deliver_script'
3805            flag is set. If so, then we go ahead and deliver the file since
3806            it isn't really content (only GET normally returns content).
3807
3808            Note: based on logic further above, the only possible non-GET
3809            method at this point is POST. In the future, we should enable
3810            script delivery for all methods.  */
3811         if (r->method_number != M_GET) {
3812             core_request_config *req_cfg;
3813
3814             req_cfg = ap_get_module_config(r->request_config, &core_module);
3815             if (!req_cfg->deliver_script) {
3816                 /* The flag hasn't been set for this request. Punt. */
3817                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3818                               "This resource does not accept the %s method.",
3819                               r->method);
3820                 return HTTP_METHOD_NOT_ALLOWED;
3821             }
3822         }
3823
3824
3825         if ((status = apr_file_open(&fd, r->filename, APR_READ | APR_BINARY
3826 #if APR_HAS_SENDFILE
3827                             | AP_SENDFILE_ENABLED(d->enable_sendfile)
3828 #endif
3829                                     , 0, r->pool)) != APR_SUCCESS) {
3830             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
3831                           "file permissions deny server access: %s", r->filename);
3832             return HTTP_FORBIDDEN;
3833         }
3834
3835         ap_update_mtime(r, r->finfo.mtime);
3836         ap_set_last_modified(r);
3837         ap_set_etag(r);
3838         apr_table_setn(r->headers_out, "Accept-Ranges", "bytes");
3839         ap_set_content_length(r, r->finfo.size);
3840         if (bld_content_md5) {
3841             apr_table_setn(r->headers_out, "Content-MD5",
3842                            ap_md5digest(r->pool, fd));
3843         }
3844
3845         bb = apr_brigade_create(r->pool, c->bucket_alloc);
3846
3847         if ((errstatus = ap_meets_conditions(r)) != OK) {
3848             apr_file_close(fd);
3849             r->status = errstatus;
3850         }
3851         else {
3852             e = apr_brigade_insert_file(bb, fd, 0, r->finfo.size, r->pool);
3853
3854 #if APR_HAS_MMAP
3855             if (d->enable_mmap == ENABLE_MMAP_OFF) {
3856                 (void)apr_bucket_file_enable_mmap(e, 0);
3857             }
3858 #endif
3859         }
3860
3861         e = apr_bucket_eos_create(c->bucket_alloc);
3862         APR_BRIGADE_INSERT_TAIL(bb, e);
3863
3864         status = ap_pass_brigade(r->output_filters, bb);
3865         if (status == APR_SUCCESS
3866             || r->status != HTTP_OK
3867             || c->aborted) {
3868             return OK;
3869         }
3870         else {
3871             /* no way to know what type of error occurred */
3872             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r,
3873                           "default_handler: ap_pass_brigade returned %i",
3874                           status);
3875             return HTTP_INTERNAL_SERVER_ERROR;
3876         }
3877     }
3878     else {              /* unusual method (not GET or POST) */
3879         if (r->method_number == M_INVALID) {
3880             /* See if this looks like an undecrypted SSL handshake attempt.
3881              * It's safe to look a couple bytes into the_request if it exists, as it's
3882              * always allocated at least MIN_LINE_ALLOC (80) bytes.
3883              */
3884             if (r->the_request
3885                 && r->the_request[0] == 0x16                                
3886                 && (r->the_request[1] == 0x2 || r->the_request[1] == 0x3)) {
3887                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3888                               "Invalid method in request %s - possible attempt to establish SSL connection on non-SSL port", r->the_request);
3889             } else {
3890                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3891                               "Invalid method in request %s", r->the_request);
3892             }
3893             return HTTP_NOT_IMPLEMENTED;
3894         }
3895
3896         if (r->method_number == M_OPTIONS) {
3897             return ap_send_http_options(r);
3898         }
3899         return HTTP_METHOD_NOT_ALLOWED;
3900     }
3901 }
3902
3903 /* Optional function coming from mod_logio, used for logging of output
3904  * traffic
3905  */
3906 APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *ap__logio_add_bytes_out;
3907 APR_OPTIONAL_FN_TYPE(authz_some_auth_required) *ap__authz_ap_some_auth_required;
3908
3909 /* Insist that at least one module will undertake to provide system
3910  * security by dropping startup privileges.
3911  */
3912 static int sys_privileges = 0;
3913 AP_DECLARE(int) ap_sys_privileges_handlers(int inc)
3914 {
3915     sys_privileges += inc;
3916     return sys_privileges;
3917 }
3918
3919 static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
3920 {
3921     ap_mutex_init(pconf);
3922
3923     return APR_SUCCESS;
3924 }
3925
3926 static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
3927 {
3928     ap__logio_add_bytes_out = APR_RETRIEVE_OPTIONAL_FN(ap_logio_add_bytes_out);
3929     ident_lookup = APR_RETRIEVE_OPTIONAL_FN(ap_ident_lookup);
3930     ap__authz_ap_some_auth_required = APR_RETRIEVE_OPTIONAL_FN(authz_some_auth_required);
3931     authn_ap_auth_type = APR_RETRIEVE_OPTIONAL_FN(authn_ap_auth_type);
3932     authn_ap_auth_name = APR_RETRIEVE_OPTIONAL_FN(authn_ap_auth_name);
3933     access_compat_ap_satisfies = APR_RETRIEVE_OPTIONAL_FN(access_compat_ap_satisfies);
3934
3935     set_banner(pconf);
3936     ap_setup_make_content_type(pconf);
3937     ap_setup_auth_internal(ptemp);
3938     if (!sys_privileges) {
3939         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL,
3940                      "Server MUST relinquish startup privileges before "
3941                      "accepting connections.  Please ensure mod_unixd "
3942                      "or other system security module is loaded.");
3943         return !OK;
3944     }
3945     return OK;
3946 }
3947
3948 static void core_insert_filter(request_rec *r)
3949 {
3950     core_dir_config *conf = (core_dir_config *)
3951                             ap_get_module_config(r->per_dir_config,
3952                                                  &core_module);
3953     const char *filter, *filters = conf->output_filters;
3954
3955     if (filters) {
3956         while (*filters && (filter = ap_getword(r->pool, &filters, ';'))) {
3957             ap_add_output_filter(filter, NULL, r, r->connection);
3958         }
3959     }
3960
3961     filters = conf->input_filters;
3962     if (filters) {
3963         while (*filters && (filter = ap_getword(r->pool, &filters, ';'))) {
3964             ap_add_input_filter(filter, NULL, r, r->connection);
3965         }
3966     }
3967 }
3968
3969 static apr_size_t num_request_notes = AP_NUM_STD_NOTES;
3970
3971 static apr_status_t reset_request_notes(void *dummy)
3972 {
3973     num_request_notes = AP_NUM_STD_NOTES;
3974     return APR_SUCCESS;
3975 }
3976
3977 AP_DECLARE(apr_size_t) ap_register_request_note(void)
3978 {
3979     apr_pool_cleanup_register(apr_hook_global_pool, NULL, reset_request_notes,
3980                               apr_pool_cleanup_null);
3981     return num_request_notes++;
3982 }
3983
3984 AP_DECLARE(void **) ap_get_request_note(request_rec *r, apr_size_t note_num)
3985 {
3986     core_request_config *req_cfg;
3987
3988     if (note_num >= num_request_notes) {
3989         return NULL;
3990     }
3991
3992     req_cfg = (core_request_config *)
3993         ap_get_module_config(r->request_config, &core_module);
3994
3995     if (!req_cfg) {
3996         return NULL;
3997     }
3998
3999     return &(req_cfg->notes[note_num]);
4000 }
4001
4002 static int core_create_req(request_rec *r)
4003 {
4004     /* Alloc the config struct and the array of request notes in
4005      * a single block for efficiency
4006      */
4007     core_request_config *req_cfg;
4008
4009     req_cfg = apr_pcalloc(r->pool, sizeof(core_request_config) +
4010                           sizeof(void *) * num_request_notes);
4011     req_cfg->notes = (void **)((char *)req_cfg + sizeof(core_request_config));
4012
4013     /* ### temporarily enable script delivery as the default */
4014     req_cfg->deliver_script = 1;
4015
4016     if (r->main) {
4017         core_request_config *main_req_cfg = (core_request_config *)
4018             ap_get_module_config(r->main->request_config, &core_module);
4019         req_cfg->bb = main_req_cfg->bb;
4020     }
4021     else {
4022         req_cfg->bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
4023     }
4024
4025     ap_set_module_config(r->request_config, &core_module, req_cfg);
4026
4027     return OK;
4028 }
4029
4030 static int core_create_proxy_req(request_rec *r, request_rec *pr)
4031 {
4032     return core_create_req(pr);
4033 }
4034
4035 static conn_rec *core_create_conn(apr_pool_t *ptrans, server_rec *server,
4036                                   apr_socket_t *csd, long id, void *sbh,
4037                                   apr_bucket_alloc_t *alloc)
4038 {
4039     apr_status_t rv;
4040     conn_rec *c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
4041
4042     c->sbh = sbh;
4043     (void)ap_update_child_status(c->sbh, SERVER_BUSY_READ, (request_rec *)NULL);
4044
4045     /* Got a connection structure, so initialize what fields we can
4046      * (the rest are zeroed out by pcalloc).
4047      */
4048     c->conn_config = ap_create_conn_config(ptrans);
4049     c->notes = apr_table_make(ptrans, 5);
4050
4051     c->pool = ptrans;
4052     if ((rv = apr_socket_addr_get(&c->local_addr, APR_LOCAL, csd))
4053         != APR_SUCCESS) {
4054         ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
4055                      "apr_socket_addr_get(APR_LOCAL)");
4056         apr_socket_close(csd);
4057         return NULL;
4058     }
4059
4060     apr_sockaddr_ip_get(&c->local_ip, c->local_addr);
4061     if ((rv = apr_socket_addr_get(&c->remote_addr, APR_REMOTE, csd))
4062         != APR_SUCCESS) {
4063         ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
4064                      "apr_socket_addr_get(APR_REMOTE)");
4065         apr_socket_close(csd);
4066         return NULL;
4067     }
4068
4069     apr_sockaddr_ip_get(&c->remote_ip, c->remote_addr);
4070     c->base_server = server;
4071
4072     c->id = id;
4073     c->bucket_alloc = alloc;
4074
4075     c->cs = (conn_state_t *)apr_pcalloc(ptrans, sizeof(conn_state_t));
4076     APR_RING_INIT(&(c->cs->timeout_list), conn_state_t, timeout_list);
4077     c->cs->expiration_time = 0;
4078     c->cs->state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
4079     c->cs->c = c;
4080     c->cs->p = ptrans;
4081     c->cs->bucket_alloc = alloc;
4082     c->clogging_input_filters = 0;
4083
4084     return c;
4085 }
4086
4087 static int core_pre_connection(conn_rec *c, void *csd)
4088 {
4089     core_net_rec *net = apr_palloc(c->pool, sizeof(*net));
4090     apr_status_t rv;
4091
4092     /* The Nagle algorithm says that we should delay sending partial
4093      * packets in hopes of getting more data.  We don't want to do
4094      * this; we are not telnet.  There are bad interactions between
4095      * persistent connections and Nagle's algorithm that have very severe
4096      * performance penalties.  (Failing to disable Nagle is not much of a
4097      * problem with simple HTTP.)
4098      */
4099     rv = apr_socket_opt_set(csd, APR_TCP_NODELAY, 1);
4100     if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
4101         /* expected cause is that the client disconnected already,
4102          * hence the debug level
4103          */
4104         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c,
4105                       "apr_socket_opt_set(APR_TCP_NODELAY)");
4106     }
4107
4108     /* The core filter requires the timeout mode to be set, which
4109      * incidentally sets the socket to be nonblocking.  If this
4110      * is not initialized correctly, Linux - for example - will
4111      * be initially blocking, while Solaris will be non blocking
4112      * and any initial read will fail.
4113      */
4114     rv = apr_socket_timeout_set(csd, c->base_server->timeout);
4115     if (rv != APR_SUCCESS) {
4116         /* expected cause is that the client disconnected already */
4117         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c,
4118                       "apr_socket_timeout_set");
4119     }
4120
4121     net->c = c;
4122     net->in_ctx = NULL;
4123     net->out_ctx = NULL;
4124     net->client_socket = csd;
4125
4126     ap_set_module_config(net->c->conn_config, &core_module, csd);
4127     ap_add_input_filter_handle(ap_core_input_filter_handle, net, NULL, net->c);
4128     ap_add_output_filter_handle(ap_core_output_filter_handle, net, NULL, net->c);
4129     return DONE;
4130 }
4131
4132 static void register_hooks(apr_pool_t *p)
4133 {
4134     errorlog_hash = apr_hash_make(p);
4135     ap_register_log_hooks(p);
4136
4137     /* create_connection and pre_connection should always be hooked
4138      * APR_HOOK_REALLY_LAST by core to give other modules the opportunity
4139      * to install alternate network transports and stop other functions 
4140      * from being run.
4141      */
4142     ap_hook_create_connection(core_create_conn, NULL, NULL,
4143                               APR_HOOK_REALLY_LAST);
4144     ap_hook_pre_connection(core_pre_connection, NULL, NULL,
4145                            APR_HOOK_REALLY_LAST);
4146
4147     ap_hook_pre_config(core_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
4148     ap_hook_post_config(core_post_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
4149     ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST);
4150     ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST);
4151     ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST);
4152     ap_hook_child_init(ap_logs_child_init,NULL,NULL,APR_HOOK_MIDDLE);
4153     ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST);
4154     /* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */
4155     ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
4156     ap_hook_fixups(core_override_type,NULL,NULL,APR_HOOK_REALLY_FIRST);
4157     ap_hook_create_request(core_create_req, NULL, NULL, APR_HOOK_MIDDLE);
4158     APR_OPTIONAL_HOOK(proxy, create_req, core_create_proxy_req, NULL, NULL,
4159                       APR_HOOK_MIDDLE);
4160     ap_hook_pre_mpm(ap_create_scoreboard, NULL, NULL, APR_HOOK_MIDDLE);
4161
4162     /* register the core's insert_filter hook and register core-provided
4163      * filters
4164      */
4165     ap_hook_insert_filter(core_insert_filter, NULL, NULL, APR_HOOK_MIDDLE);
4166
4167     ap_core_input_filter_handle =
4168         ap_register_input_filter("CORE_IN", ap_core_input_filter,
4169                                  NULL, AP_FTYPE_NETWORK);
4170     ap_content_length_filter_handle =
4171         ap_register_output_filter("CONTENT_LENGTH", ap_content_length_filter,
4172                                   NULL, AP_FTYPE_PROTOCOL);
4173     ap_core_output_filter_handle =
4174         ap_register_output_filter("CORE", ap_core_output_filter,
4175                                   NULL, AP_FTYPE_NETWORK);
4176     ap_subreq_core_filter_handle =
4177         ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter,
4178                                   NULL, AP_FTYPE_CONTENT_SET);
4179     ap_old_write_func =
4180         ap_register_output_filter("OLD_WRITE", ap_old_write_filter,
4181                                   NULL, AP_FTYPE_RESOURCE - 10);
4182 }
4183
4184 AP_DECLARE_MODULE(core) = {
4185     MPM20_MODULE_STUFF,
4186     AP_PLATFORM_REWRITE_ARGS_HOOK, /* hook to run before apache parses args */
4187     create_core_dir_config,       /* create per-directory config structure */
4188     merge_core_dir_configs,       /* merge per-directory config structures */
4189     create_core_server_config,    /* create per-server config structure */
4190     merge_core_server_configs,    /* merge per-server config structures */
4191     core_cmds,                    /* command apr_table_t */
4192     register_hooks                /* register hooks */
4193 };
4194