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