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