]> granicus.if.org Git - apache/blob - server/core.c
Fix some typos
[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_runtime_dir(cmd_parms *cmd, void *dummy, const char *arg)
2779 {
2780     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2781
2782     if (err != NULL) {
2783         return err;
2784     }
2785
2786     if ((apr_filepath_merge((char**)&ap_runtime_dir, NULL,
2787                             ap_server_root_relative(cmd->pool, arg),
2788                             APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS)
2789         || !ap_is_directory(cmd->temp_pool, ap_runtime_dir)) {
2790         return "DefaultRuntimeDir must be a valid directory, absolute or relative to ServerRoot";
2791     }
2792
2793     return NULL;
2794 }
2795
2796 static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg)
2797 {
2798     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
2799
2800     if (err != NULL) {
2801         return err;
2802     }
2803
2804     cmd->server->timeout = apr_time_from_sec(atoi(arg));
2805     return NULL;
2806 }
2807
2808 static const char *set_allow2f(cmd_parms *cmd, void *d_, const char *arg)
2809 {
2810     core_dir_config *d = d_;
2811
2812     if (0 == strcasecmp(arg, "on")) {
2813         d->allow_encoded_slashes = 1;
2814         d->decode_encoded_slashes = 1; /* for compatibility with 2.0 & 2.2 */
2815     } else if (0 == strcasecmp(arg, "off")) {
2816         d->allow_encoded_slashes = 0;
2817         d->decode_encoded_slashes = 0;
2818     } else if (0 == strcasecmp(arg, "nodecode")) {
2819         d->allow_encoded_slashes = 1;
2820         d->decode_encoded_slashes = 0;
2821     } else {
2822         return apr_pstrcat(cmd->pool,
2823                            cmd->cmd->name, " must be On, Off, or NoDecode",
2824                            NULL);
2825     }
2826     return NULL;
2827 }
2828
2829 static const char *set_hostname_lookups(cmd_parms *cmd, void *d_,
2830                                         const char *arg)
2831 {
2832     core_dir_config *d = d_;
2833
2834     if (!strcasecmp(arg, "on")) {
2835         d->hostname_lookups = HOSTNAME_LOOKUP_ON;
2836     }
2837     else if (!strcasecmp(arg, "off")) {
2838         d->hostname_lookups = HOSTNAME_LOOKUP_OFF;
2839     }
2840     else if (!strcasecmp(arg, "double")) {
2841         d->hostname_lookups = HOSTNAME_LOOKUP_DOUBLE;
2842     }
2843     else {
2844         return "parameter must be 'on', 'off', or 'double'";
2845     }
2846
2847     return NULL;
2848 }
2849
2850 static const char *set_serverpath(cmd_parms *cmd, void *dummy,
2851                                   const char *arg)
2852 {
2853     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
2854
2855     if (err != NULL) {
2856         return err;
2857     }
2858
2859     cmd->server->path = arg;
2860     cmd->server->pathlen = (int)strlen(arg);
2861     return NULL;
2862 }
2863
2864 static const char *set_content_md5(cmd_parms *cmd, void *d_, int arg)
2865 {
2866     core_dir_config *d = d_;
2867
2868     d->content_md5 = arg ? AP_CONTENT_MD5_ON : AP_CONTENT_MD5_OFF;
2869     return NULL;
2870 }
2871
2872 static const char *set_accept_path_info(cmd_parms *cmd, void *d_, const char *arg)
2873 {
2874     core_dir_config *d = d_;
2875
2876     if (strcasecmp(arg, "on") == 0) {
2877         d->accept_path_info = AP_REQ_ACCEPT_PATH_INFO;
2878     }
2879     else if (strcasecmp(arg, "off") == 0) {
2880         d->accept_path_info = AP_REQ_REJECT_PATH_INFO;
2881     }
2882     else if (strcasecmp(arg, "default") == 0) {
2883         d->accept_path_info = AP_REQ_DEFAULT_PATH_INFO;
2884     }
2885     else {
2886         return "AcceptPathInfo must be set to on, off or default";
2887     }
2888
2889     return NULL;
2890 }
2891
2892 static const char *set_use_canonical_name(cmd_parms *cmd, void *d_,
2893                                           const char *arg)
2894 {
2895     core_dir_config *d = d_;
2896
2897     if (strcasecmp(arg, "on") == 0) {
2898         d->use_canonical_name = USE_CANONICAL_NAME_ON;
2899     }
2900     else if (strcasecmp(arg, "off") == 0) {
2901         d->use_canonical_name = USE_CANONICAL_NAME_OFF;
2902     }
2903     else if (strcasecmp(arg, "dns") == 0) {
2904         d->use_canonical_name = USE_CANONICAL_NAME_DNS;
2905     }
2906     else {
2907         return "parameter must be 'on', 'off', or 'dns'";
2908     }
2909
2910     return NULL;
2911 }
2912
2913 static const char *set_use_canonical_phys_port(cmd_parms *cmd, void *d_,
2914                                           const char *arg)
2915 {
2916     core_dir_config *d = d_;
2917
2918     if (strcasecmp(arg, "on") == 0) {
2919         d->use_canonical_phys_port = USE_CANONICAL_PHYS_PORT_ON;
2920     }
2921     else if (strcasecmp(arg, "off") == 0) {
2922         d->use_canonical_phys_port = USE_CANONICAL_PHYS_PORT_OFF;
2923     }
2924     else {
2925         return "parameter must be 'on' or 'off'";
2926     }
2927
2928     return NULL;
2929 }
2930
2931 static const char *include_config (cmd_parms *cmd, void *dummy,
2932                                    const char *name)
2933 {
2934     ap_directive_t *conftree = NULL;
2935     const char *conffile, *error;
2936     unsigned *recursion;
2937     int optional = cmd->cmd->cmd_data ? 1 : 0;
2938     void *data;
2939
2940     apr_pool_userdata_get(&data, "ap_include_sentinel", cmd->pool);
2941     if (data) {
2942         recursion = data;
2943     }
2944     else {
2945         data = recursion = apr_palloc(cmd->pool, sizeof(*recursion));
2946         *recursion = 0;
2947         apr_pool_userdata_setn(data, "ap_include_sentinel", NULL, cmd->pool);
2948     }
2949
2950     if (++*recursion > AP_MAX_INCLUDE_DEPTH) {
2951         *recursion = 0;
2952         return apr_psprintf(cmd->pool, "Exceeded maximum include depth of %u, "
2953                             "There appears to be a recursion.",
2954                             AP_MAX_INCLUDE_DEPTH);
2955     }
2956
2957     conffile = ap_server_root_relative(cmd->pool, name);
2958     if (!conffile) {
2959         *recursion = 0;
2960         return apr_pstrcat(cmd->pool, "Invalid Include path ",
2961                            name, NULL);
2962     }
2963
2964     error = ap_process_fnmatch_configs(cmd->server, conffile, &conftree,
2965                                        cmd->pool, cmd->temp_pool,
2966                                        optional);
2967     if (error) {
2968         *recursion = 0;
2969         return error;
2970     }
2971
2972     *(ap_directive_t **)dummy = conftree;
2973
2974     /* recursion level done */
2975     if (*recursion) {
2976         --*recursion;
2977     }
2978
2979     return NULL;
2980 }
2981
2982 static const char *set_loglevel(cmd_parms *cmd, void *config_, const char *arg_)
2983 {
2984     char *level_str;
2985     int level;
2986     module *module;
2987     char *arg = apr_pstrdup(cmd->temp_pool, arg_);
2988     struct ap_logconf *log;
2989     const char *err;
2990
2991     if (cmd->path) {
2992         core_dir_config *dconf = config_;
2993         if (!dconf->log) {
2994             dconf->log = ap_new_log_config(cmd->pool, NULL);
2995         }
2996         log = dconf->log;
2997     }
2998     else {
2999         log = &cmd->server->log;
3000     }
3001
3002     if (arg == NULL)
3003         return "LogLevel requires level keyword or module loglevel specifier";
3004
3005     level_str = ap_strrchr(arg, ':');
3006
3007     if (level_str == NULL) {
3008         err = ap_parse_log_level(arg, &log->level);
3009         if (err != NULL)
3010             return err;
3011         ap_reset_module_loglevels(log, APLOG_NO_MODULE);
3012         ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, cmd->server,
3013                      "Setting LogLevel for all modules to %s", arg);
3014         return NULL;
3015     }
3016
3017     *level_str++ = '\0';
3018     if (!*level_str) {
3019         return apr_psprintf(cmd->temp_pool, "Module specifier '%s' must be "
3020                             "followed by a log level keyword", arg);
3021     }
3022
3023     err = ap_parse_log_level(level_str, &level);
3024     if (err != NULL)
3025         return apr_psprintf(cmd->temp_pool, "%s:%s: %s", arg, level_str, err);
3026
3027     if ((module = find_module(cmd->server, arg)) == NULL) {
3028         char *name = apr_psprintf(cmd->temp_pool, "%s_module", arg);
3029         ap_log_error(APLOG_MARK, APLOG_TRACE6, 0, cmd->server,
3030                      "Cannot find module '%s', trying '%s'", arg, name);
3031         module = find_module(cmd->server, name);
3032     }
3033
3034     if (module == NULL) {
3035         return apr_psprintf(cmd->temp_pool, "Cannot find module %s", arg);
3036     }
3037
3038     ap_set_module_loglevel(cmd->pool, log, module->module_index, level);
3039     ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, cmd->server,
3040                  "Setting LogLevel for module %s to %s", module->name,
3041                  level_str);
3042
3043     return NULL;
3044 }
3045
3046 AP_DECLARE(const char *) ap_psignature(const char *prefix, request_rec *r)
3047 {
3048     char sport[20];
3049     core_dir_config *conf;
3050
3051     conf = (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
3052     if ((conf->server_signature == srv_sig_off)
3053             || (conf->server_signature == srv_sig_unset)) {
3054         return "";
3055     }
3056
3057     apr_snprintf(sport, sizeof sport, "%u", (unsigned) ap_get_server_port(r));
3058
3059     if (conf->server_signature == srv_sig_withmail) {
3060         return apr_pstrcat(r->pool, prefix, "<address>",
3061                            ap_get_server_banner(),
3062                            " Server at <a href=\"",
3063                            ap_is_url(r->server->server_admin) ? "" : "mailto:",
3064                            ap_escape_html(r->pool, r->server->server_admin),
3065                            "\">",
3066                            ap_escape_html(r->pool, ap_get_server_name(r)),
3067                            "</a> Port ", sport,
3068                            "</address>\n", NULL);
3069     }
3070
3071     return apr_pstrcat(r->pool, prefix, "<address>", ap_get_server_banner(),
3072                        " Server at ",
3073                        ap_escape_html(r->pool, ap_get_server_name(r)),
3074                        " Port ", sport,
3075                        "</address>\n", NULL);
3076 }
3077
3078 /*
3079  * Handle a request to include the server's OS platform in the Server
3080  * response header field (the ServerTokens directive).  Unfortunately
3081  * this requires a new global in order to communicate the setting back to
3082  * http_main so it can insert the information in the right place in the
3083  * string.
3084  */
3085
3086 static char *server_banner = NULL;
3087 static int banner_locked = 0;
3088 static const char *server_description = NULL;
3089
3090 enum server_token_type {
3091     SrvTk_MAJOR,         /* eg: Apache/2 */
3092     SrvTk_MINOR,         /* eg. Apache/2.0 */
3093     SrvTk_MINIMAL,       /* eg: Apache/2.0.41 */
3094     SrvTk_OS,            /* eg: Apache/2.0.41 (UNIX) */
3095     SrvTk_FULL,          /* eg: Apache/2.0.41 (UNIX) PHP/4.2.2 FooBar/1.2b */
3096     SrvTk_PRODUCT_ONLY  /* eg: Apache */
3097 };
3098 static enum server_token_type ap_server_tokens = SrvTk_FULL;
3099
3100 static apr_status_t reset_banner(void *dummy)
3101 {
3102     banner_locked = 0;
3103     ap_server_tokens = SrvTk_FULL;
3104     server_banner = NULL;
3105     server_description = NULL;
3106     return APR_SUCCESS;
3107 }
3108
3109 AP_DECLARE(void) ap_get_server_revision(ap_version_t *version)
3110 {
3111     version->major = AP_SERVER_MAJORVERSION_NUMBER;
3112     version->minor = AP_SERVER_MINORVERSION_NUMBER;
3113     version->patch = AP_SERVER_PATCHLEVEL_NUMBER;
3114     version->add_string = AP_SERVER_ADD_STRING;
3115 }
3116
3117 AP_DECLARE(const char *) ap_get_server_description(void)
3118 {
3119     return server_description ? server_description :
3120         AP_SERVER_BASEVERSION " (" PLATFORM ")";
3121 }
3122
3123 AP_DECLARE(const char *) ap_get_server_banner(void)
3124 {
3125     return server_banner ? server_banner : AP_SERVER_BASEVERSION;
3126 }
3127
3128 AP_DECLARE(void) ap_add_version_component(apr_pool_t *pconf, const char *component)
3129 {
3130     if (! banner_locked) {
3131         /*
3132          * If the version string is null, register our cleanup to reset the
3133          * pointer on pool destruction. We also know that, if NULL,
3134          * we are adding the original SERVER_BASEVERSION string.
3135          */
3136         if (server_banner == NULL) {
3137             apr_pool_cleanup_register(pconf, NULL, reset_banner,
3138                                       apr_pool_cleanup_null);
3139             server_banner = apr_pstrdup(pconf, component);
3140         }
3141         else {
3142             /*
3143              * Tack the given component identifier to the end of
3144              * the existing string.
3145              */
3146             server_banner = apr_pstrcat(pconf, server_banner, " ",
3147                                         component, NULL);
3148         }
3149     }
3150     server_description = apr_pstrcat(pconf, server_description, " ",
3151                                      component, NULL);
3152 }
3153
3154 /*
3155  * This routine adds the real server base identity to the banner string,
3156  * and then locks out changes until the next reconfig.
3157  */
3158 static void set_banner(apr_pool_t *pconf)
3159 {
3160     if (ap_server_tokens == SrvTk_PRODUCT_ONLY) {
3161         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT);
3162     }
3163     else if (ap_server_tokens == SrvTk_MINIMAL) {
3164         ap_add_version_component(pconf, AP_SERVER_BASEVERSION);
3165     }
3166     else if (ap_server_tokens == SrvTk_MINOR) {
3167         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MINORREVISION);
3168     }
3169     else if (ap_server_tokens == SrvTk_MAJOR) {
3170         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MAJORVERSION);
3171     }
3172     else {
3173         ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ")");
3174     }
3175
3176     /*
3177      * Lock the server_banner string if we're not displaying
3178      * the full set of tokens
3179      */
3180     if (ap_server_tokens != SrvTk_FULL) {
3181         banner_locked++;
3182     }
3183     server_description = AP_SERVER_BASEVERSION " (" PLATFORM ")";
3184 }
3185
3186 static const char *set_serv_tokens(cmd_parms *cmd, void *dummy,
3187                                    const char *arg1, const char *arg2)
3188 {
3189     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3190
3191     if (err != NULL) {
3192         return err;
3193     }
3194
3195     if (!strcasecmp(arg1, "OS")) {
3196         ap_server_tokens = SrvTk_OS;
3197     }
3198     else if (!strcasecmp(arg1, "Min") || !strcasecmp(arg1, "Minimal")) {
3199         ap_server_tokens = SrvTk_MINIMAL;
3200     }
3201     else if (!strcasecmp(arg1, "Major")) {
3202         ap_server_tokens = SrvTk_MAJOR;
3203     }
3204     else if (!strcasecmp(arg1, "Minor") ) {
3205         ap_server_tokens = SrvTk_MINOR;
3206     }
3207     else if (!strcasecmp(arg1, "Prod") || !strcasecmp(arg1, "ProductOnly")) {
3208         ap_server_tokens = SrvTk_PRODUCT_ONLY;
3209     }
3210     else {
3211         ap_server_tokens = SrvTk_FULL;
3212     }
3213
3214     return NULL;
3215 }
3216
3217 static const char *set_limit_req_line(cmd_parms *cmd, void *dummy,
3218                                       const char *arg)
3219 {
3220     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
3221     int lim;
3222
3223     if (err != NULL) {
3224         return err;
3225     }
3226
3227     lim = atoi(arg);
3228     if (lim < 0) {
3229         return apr_pstrcat(cmd->temp_pool, "LimitRequestLine \"", arg,
3230                            "\" must be a non-negative integer", NULL);
3231     }
3232
3233     cmd->server->limit_req_line = lim;
3234     return NULL;
3235 }
3236
3237 static const char *set_limit_req_fieldsize(cmd_parms *cmd, void *dummy,
3238                                            const char *arg)
3239 {
3240     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
3241     int lim;
3242
3243     if (err != NULL) {
3244         return err;
3245     }
3246
3247     lim = atoi(arg);
3248     if (lim < 0) {
3249         return apr_pstrcat(cmd->temp_pool, "LimitRequestFieldsize \"", arg,
3250                           "\" must be a non-negative integer",
3251                           NULL);
3252     }
3253
3254     cmd->server->limit_req_fieldsize = lim;
3255     return NULL;
3256 }
3257
3258 static const char *set_limit_req_fields(cmd_parms *cmd, void *dummy,
3259                                         const char *arg)
3260 {
3261     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
3262     int lim;
3263
3264     if (err != NULL) {
3265         return err;
3266     }
3267
3268     lim = atoi(arg);
3269     if (lim < 0) {
3270         return apr_pstrcat(cmd->temp_pool, "LimitRequestFields \"", arg,
3271                            "\" must be a non-negative integer (0 = no limit)",
3272                            NULL);
3273     }
3274
3275     cmd->server->limit_req_fields = lim;
3276     return NULL;
3277 }
3278
3279 static const char *set_limit_req_body(cmd_parms *cmd, void *conf_,
3280                                       const char *arg)
3281 {
3282     core_dir_config *conf = conf_;
3283     char *errp;
3284
3285     if (APR_SUCCESS != apr_strtoff(&conf->limit_req_body, arg, &errp, 10)) {
3286         return "LimitRequestBody argument is not parsable.";
3287     }
3288     if (*errp || conf->limit_req_body < 0) {
3289         return "LimitRequestBody requires a non-negative integer.";
3290     }
3291
3292     return NULL;
3293 }
3294
3295 static const char *set_limit_xml_req_body(cmd_parms *cmd, void *conf_,
3296                                           const char *arg)
3297 {
3298     core_dir_config *conf = conf_;
3299
3300     conf->limit_xml_body = atol(arg);
3301     if (conf->limit_xml_body < 0)
3302         return "LimitXMLRequestBody requires a non-negative integer.";
3303
3304     return NULL;
3305 }
3306
3307 static const char *set_max_ranges(cmd_parms *cmd, void *conf_, const char *arg)
3308 {
3309     core_dir_config *conf = conf_;
3310     int val = 0;
3311
3312     if (!strcasecmp(arg, "none")) {
3313         val = AP_MAXRANGES_NORANGES;
3314     }
3315     else if (!strcasecmp(arg, "default")) {
3316         val = AP_MAXRANGES_DEFAULT;
3317     }
3318     else if (!strcasecmp(arg, "unlimited")) {
3319         val = AP_MAXRANGES_UNLIMITED;
3320     }
3321     else {
3322         val = atoi(arg);
3323         if (val <= 0)
3324             return "MaxRanges requires 'none', 'default', 'unlimited' or "
3325                    "a positive integer";
3326     }
3327
3328     conf->max_ranges = val;
3329
3330     return NULL;
3331 }
3332
3333 static const char *set_max_overlaps(cmd_parms *cmd, void *conf_, const char *arg)
3334 {
3335     core_dir_config *conf = conf_;
3336     int val = 0;
3337
3338     if (!strcasecmp(arg, "none")) {
3339         val = AP_MAXRANGES_NORANGES;
3340     }
3341     else if (!strcasecmp(arg, "default")) {
3342         val = AP_MAXRANGES_DEFAULT;
3343     }
3344     else if (!strcasecmp(arg, "unlimited")) {
3345         val = AP_MAXRANGES_UNLIMITED;
3346     }
3347     else {
3348         val = atoi(arg);
3349         if (val <= 0)
3350             return "MaxRangeOverlaps requires 'none', 'default', 'unlimited' or "
3351             "a positive integer";
3352     }
3353
3354     conf->max_overlaps = val;
3355
3356     return NULL;
3357 }
3358
3359 static const char *set_max_reversals(cmd_parms *cmd, void *conf_, const char *arg)
3360 {
3361     core_dir_config *conf = conf_;
3362     int val = 0;
3363
3364     if (!strcasecmp(arg, "none")) {
3365         val = AP_MAXRANGES_NORANGES;
3366     }
3367     else if (!strcasecmp(arg, "default")) {
3368         val = AP_MAXRANGES_DEFAULT;
3369     }
3370     else if (!strcasecmp(arg, "unlimited")) {
3371         val = AP_MAXRANGES_UNLIMITED;
3372     }
3373     else {
3374         val = atoi(arg);
3375         if (val <= 0)
3376             return "MaxRangeReversals requires 'none', 'default', 'unlimited' or "
3377             "a positive integer";
3378     }
3379
3380     conf->max_reversals = val;
3381
3382     return NULL;
3383 }
3384
3385 AP_DECLARE(apr_size_t) ap_get_limit_xml_body(const request_rec *r)
3386 {
3387     core_dir_config *conf;
3388
3389     conf = ap_get_core_module_config(r->per_dir_config);
3390     if (conf->limit_xml_body == AP_LIMIT_UNSET)
3391         return AP_DEFAULT_LIMIT_XML_BODY;
3392
3393     return (apr_size_t)conf->limit_xml_body;
3394 }
3395
3396 #if !defined (RLIMIT_CPU) || !(defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)) || !defined (RLIMIT_NPROC)
3397 static const char *no_set_limit(cmd_parms *cmd, void *conf_,
3398                                 const char *arg, const char *arg2)
3399 {
3400     ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server, APLOGNO(00118)
3401                 "%s not supported on this platform", cmd->cmd->name);
3402
3403     return NULL;
3404 }
3405 #endif
3406
3407 #ifdef RLIMIT_CPU
3408 static const char *set_limit_cpu(cmd_parms *cmd, void *conf_,
3409                                  const char *arg, const char *arg2)
3410 {
3411     core_dir_config *conf = conf_;
3412
3413     ap_unixd_set_rlimit(cmd, &conf->limit_cpu, arg, arg2, RLIMIT_CPU);
3414     return NULL;
3415 }
3416 #endif
3417
3418 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)
3419 static const char *set_limit_mem(cmd_parms *cmd, void *conf_,
3420                                  const char *arg, const char * arg2)
3421 {
3422     core_dir_config *conf = conf_;
3423
3424 #if defined(RLIMIT_AS)
3425     ap_unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2 ,RLIMIT_AS);
3426 #elif defined(RLIMIT_DATA)
3427     ap_unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_DATA);
3428 #elif defined(RLIMIT_VMEM)
3429     ap_unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_VMEM);
3430 #endif
3431
3432     return NULL;
3433 }
3434 #endif
3435
3436 #ifdef RLIMIT_NPROC
3437 static const char *set_limit_nproc(cmd_parms *cmd, void *conf_,
3438                                    const char *arg, const char * arg2)
3439 {
3440     core_dir_config *conf = conf_;
3441
3442     ap_unixd_set_rlimit(cmd, &conf->limit_nproc, arg, arg2, RLIMIT_NPROC);
3443     return NULL;
3444 }
3445 #endif
3446
3447 static const char *set_recursion_limit(cmd_parms *cmd, void *dummy,
3448                                        const char *arg1, const char *arg2)
3449 {
3450     core_server_config *conf =
3451         ap_get_core_module_config(cmd->server->module_config);
3452     int limit = atoi(arg1);
3453
3454     if (limit <= 0) {
3455         return "The recursion limit must be greater than zero.";
3456     }
3457     if (limit < 4) {
3458         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(00119)
3459                      "Limiting internal redirects to very low numbers may "
3460                      "cause normal requests to fail.");
3461     }
3462
3463     conf->redirect_limit = limit;
3464
3465     if (arg2) {
3466         limit = atoi(arg2);
3467
3468         if (limit <= 0) {
3469             return "The recursion limit must be greater than zero.";
3470         }
3471         if (limit < 4) {
3472             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(00120)
3473                          "Limiting the subrequest depth to a very low level may"
3474                          " cause normal requests to fail.");
3475         }
3476     }
3477
3478     conf->subreq_limit = limit;
3479
3480     return NULL;
3481 }
3482
3483 static void log_backtrace(const request_rec *r)
3484 {
3485     const request_rec *top = r;
3486
3487     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00121)
3488                   "r->uri = %s", r->uri ? r->uri : "(unexpectedly NULL)");
3489
3490     while (top && (top->prev || top->main)) {
3491         if (top->prev) {
3492             top = top->prev;
3493             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00122)
3494                           "redirected from r->uri = %s",
3495                           top->uri ? top->uri : "(unexpectedly NULL)");
3496         }
3497
3498         if (!top->prev && top->main) {
3499             top = top->main;
3500             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00123)
3501                           "subrequested from r->uri = %s",
3502                           top->uri ? top->uri : "(unexpectedly NULL)");
3503         }
3504     }
3505 }
3506
3507 /*
3508  * check whether redirect limit is reached
3509  */
3510 AP_DECLARE(int) ap_is_recursion_limit_exceeded(const request_rec *r)
3511 {
3512     core_server_config *conf =
3513         ap_get_core_module_config(r->server->module_config);
3514     const request_rec *top = r;
3515     int redirects = 0, subreqs = 0;
3516     int rlimit = conf->redirect_limit
3517                  ? conf->redirect_limit
3518                  : AP_DEFAULT_MAX_INTERNAL_REDIRECTS;
3519     int slimit = conf->subreq_limit
3520                  ? conf->subreq_limit
3521                  : AP_DEFAULT_MAX_SUBREQ_DEPTH;
3522
3523
3524     while (top->prev || top->main) {
3525         if (top->prev) {
3526             if (++redirects >= rlimit) {
3527                 /* uuh, too much. */
3528                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00124)
3529                               "Request exceeded the limit of %d internal "
3530                               "redirects due to probable configuration error. "
3531                               "Use 'LimitInternalRecursion' to increase the "
3532                               "limit if necessary. Use 'LogLevel debug' to get "
3533                               "a backtrace.", rlimit);
3534
3535                 /* post backtrace */
3536                 log_backtrace(r);
3537
3538                 /* return failure */
3539                 return 1;
3540             }
3541
3542             top = top->prev;
3543         }
3544
3545         if (!top->prev && top->main) {
3546             if (++subreqs >= slimit) {
3547                 /* uuh, too much. */
3548                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00125)
3549                               "Request exceeded the limit of %d subrequest "
3550                               "nesting levels due to probable configuration "
3551                               "error. Use 'LimitInternalRecursion' to increase "
3552                               "the limit if necessary. Use 'LogLevel debug' to "
3553                               "get a backtrace.", slimit);
3554
3555                 /* post backtrace */
3556                 log_backtrace(r);
3557
3558                 /* return failure */
3559                 return 1;
3560             }
3561
3562             top = top->main;
3563         }
3564     }
3565
3566     /* recursion state: ok */
3567     return 0;
3568 }
3569
3570 static const char *set_trace_enable(cmd_parms *cmd, void *dummy,
3571                                     const char *arg1)
3572 {
3573     core_server_config *conf =
3574         ap_get_core_module_config(cmd->server->module_config);
3575
3576     if (strcasecmp(arg1, "on") == 0) {
3577         conf->trace_enable = AP_TRACE_ENABLE;
3578     }
3579     else if (strcasecmp(arg1, "off") == 0) {
3580         conf->trace_enable = AP_TRACE_DISABLE;
3581     }
3582     else if (strcasecmp(arg1, "extended") == 0) {
3583         conf->trace_enable = AP_TRACE_EXTENDED;
3584     }
3585     else {
3586         return "TraceEnable must be one of 'on', 'off', or 'extended'";
3587     }
3588
3589     return NULL;
3590 }
3591
3592 static apr_hash_t *errorlog_hash;
3593
3594 static int log_constant_item(const ap_errorlog_info *info, const char *arg,
3595                              char *buf, int buflen)
3596 {
3597     char *end = apr_cpystrn(buf, arg, buflen);
3598     return end - buf;
3599 }
3600
3601 static char *parse_errorlog_misc_string(apr_pool_t *p,
3602                                         ap_errorlog_format_item *it,
3603                                         const char **sa)
3604 {
3605     const char *s;
3606     char scratch[MAX_STRING_LEN];
3607     char *d = scratch;
3608     /*
3609      * non-leading white space terminates this string to allow the next field
3610      * separator to be inserted
3611      */
3612     int at_start = 1;
3613
3614     it->func = log_constant_item;
3615     s = *sa;
3616
3617     while (*s && *s != '%' && (*s != ' ' || at_start) && d < scratch + MAX_STRING_LEN) {
3618         if (*s != '\\') {
3619             if (*s != ' ') {
3620                 at_start = 0;
3621             }
3622             *d++ = *s++;
3623         }
3624         else {
3625             s++;
3626             switch (*s) {
3627             case 'r':
3628                 *d++ = '\r';
3629                 s++;
3630                 break;
3631             case 'n':
3632                 *d++ = '\n';
3633                 s++;
3634                 break;
3635             case 't':
3636                 *d++ = '\t';
3637                 s++;
3638                 break;
3639             case '\0':
3640                 /* handle end of string */
3641                 *d++ = '\\';
3642                 break;
3643             default:
3644                 /* copy next char verbatim */
3645                 *d++ = *s++;
3646                 break;
3647             }
3648         }
3649     }
3650     *d = '\0';
3651     it->arg = apr_pstrdup(p, scratch);
3652
3653     *sa = s;
3654     return NULL;
3655 }
3656
3657 static char *parse_errorlog_item(apr_pool_t *p, ap_errorlog_format_item *it,
3658                                  const char **sa)
3659 {
3660     const char *s = *sa;
3661     ap_errorlog_handler *handler;
3662     int i;
3663
3664     if (*s != '%') {
3665         if (*s == ' ') {
3666             it->flags |= AP_ERRORLOG_FLAG_FIELD_SEP;
3667         }
3668         return parse_errorlog_misc_string(p, it, sa);
3669     }
3670
3671     ++s;
3672
3673     if (*s == ' ') {
3674         /* percent-space (% ) is a field separator */
3675         it->flags |= AP_ERRORLOG_FLAG_FIELD_SEP;
3676         *sa = ++s;
3677         /* recurse */
3678         return parse_errorlog_item(p, it, sa);
3679     }
3680     else if (*s == '%') {
3681         it->arg = "%";
3682         it->func = log_constant_item;
3683         *sa = ++s;
3684         return NULL;
3685     }
3686
3687     while (*s) {
3688         switch (*s) {
3689         case '{':
3690             ++s;
3691             it->arg = ap_getword(p, &s, '}');
3692             break;
3693         case '+':
3694             ++s;
3695             it->flags |= AP_ERRORLOG_FLAG_REQUIRED;
3696             break;
3697         case '-':
3698             ++s;
3699             it->flags |= AP_ERRORLOG_FLAG_NULL_AS_HYPHEN;
3700             break;
3701         case '0':
3702         case '1':
3703         case '2':
3704         case '3':
3705         case '4':
3706         case '5':
3707         case '6':
3708         case '7':
3709         case '8':
3710         case '9':
3711             i = *s - '0';
3712             while (apr_isdigit(*++s))
3713                 i = i * 10 + (*s) - '0';
3714             it->min_loglevel = i;
3715             break;
3716         case 'M':
3717             it->func = NULL;
3718             it->flags |= AP_ERRORLOG_FLAG_MESSAGE;
3719             *sa = ++s;
3720             return NULL;
3721         default:
3722             handler = (ap_errorlog_handler *)apr_hash_get(errorlog_hash, s, 1);
3723             if (!handler) {
3724                 char dummy[2];
3725
3726                 dummy[0] = *s;
3727                 dummy[1] = '\0';
3728                 return apr_pstrcat(p, "Unrecognized error log format directive %",
3729                                dummy, NULL);
3730             }
3731             it->func = handler->func;
3732             *sa = ++s;
3733             return NULL;
3734         }
3735     }
3736
3737     return "Ran off end of error log format parsing args to some directive";
3738 }
3739
3740 static apr_array_header_t *parse_errorlog_string(apr_pool_t *p,
3741                                                  const char *s,
3742                                                  const char **err,
3743                                                  int is_main_fmt)
3744 {
3745     apr_array_header_t *a = apr_array_make(p, 30,
3746                                            sizeof(ap_errorlog_format_item));
3747     char *res;
3748     int seen_msg_fmt = 0;
3749
3750     while (s && *s) {
3751         ap_errorlog_format_item *item =
3752             (ap_errorlog_format_item *)apr_array_push(a);
3753         memset(item, 0, sizeof(*item));
3754         res = parse_errorlog_item(p, item, &s);
3755         if (res) {
3756             *err = res;
3757             return NULL;
3758         }
3759         if (item->flags & AP_ERRORLOG_FLAG_MESSAGE) {
3760             if (!is_main_fmt) {
3761                 *err = "%M cannot be used in once-per-request or "
3762                        "once-per-connection formats";
3763                 return NULL;
3764             }
3765             seen_msg_fmt = 1;
3766         }
3767         if (is_main_fmt && item->flags & AP_ERRORLOG_FLAG_REQUIRED) {
3768             *err = "The '+' flag cannot be used in the main error log format";
3769             return NULL;
3770         }
3771         if (!is_main_fmt && item->min_loglevel) {
3772             *err = "The loglevel cannot be used as a condition in "
3773                    "once-per-request or once-per-connection formats";
3774             return NULL;
3775         }
3776         if (item->min_loglevel > APLOG_TRACE8) {
3777             *err = "The specified loglevel modifier is out of range";
3778             return NULL;
3779         }
3780     }
3781
3782     if (is_main_fmt && !seen_msg_fmt) {
3783         *err = "main ErrorLogFormat must contain message format string '%M'";
3784         return NULL;
3785     }
3786
3787     return a;
3788 }
3789
3790 static const char *set_errorlog_format(cmd_parms *cmd, void *dummy,
3791                                        const char *arg1, const char *arg2)
3792 {
3793     const char *err_string = NULL;
3794     core_server_config *conf =
3795         ap_get_core_module_config(cmd->server->module_config);
3796
3797     if (!arg2) {
3798         conf->error_log_format = parse_errorlog_string(cmd->pool, arg1,
3799                                                        &err_string, 1);
3800     }
3801     else if (!strcasecmp(arg1, "connection")) {
3802         if (!conf->error_log_conn) {
3803             conf->error_log_conn = apr_array_make(cmd->pool, 5,
3804                                                   sizeof(apr_array_header_t *));
3805         }
3806
3807         if (*arg2) {
3808             apr_array_header_t **e;
3809             e = (apr_array_header_t **) apr_array_push(conf->error_log_conn);
3810             *e = parse_errorlog_string(cmd->pool, arg2, &err_string, 0);
3811         }
3812     }
3813     else if (!strcasecmp(arg1, "request")) {
3814         if (!conf->error_log_req) {
3815             conf->error_log_req = apr_array_make(cmd->pool, 5,
3816                                                  sizeof(apr_array_header_t *));
3817         }
3818
3819         if (*arg2) {
3820             apr_array_header_t **e;
3821             e = (apr_array_header_t **) apr_array_push(conf->error_log_req);
3822             *e = parse_errorlog_string(cmd->pool, arg2, &err_string, 0);
3823         }
3824     }
3825     else {
3826         err_string = "ErrorLogFormat type must be one of request, connection";
3827     }
3828
3829     return err_string;
3830 }
3831
3832 AP_DECLARE(void) ap_register_errorlog_handler(apr_pool_t *p, char *tag,
3833                                               ap_errorlog_handler_fn_t *handler,
3834                                               int flags)
3835 {
3836     ap_errorlog_handler *log_struct = apr_palloc(p, sizeof(*log_struct));
3837     log_struct->func = handler;
3838     log_struct->flags = flags;
3839
3840     apr_hash_set(errorlog_hash, tag, 1, (const void *)log_struct);
3841 }
3842
3843
3844 /* Note --- ErrorDocument will now work from .htaccess files.
3845  * The AllowOverride of Fileinfo allows webmasters to turn it off
3846  */
3847
3848 static const command_rec core_cmds[] = {
3849
3850 /* Old access config file commands */
3851
3852 AP_INIT_RAW_ARGS("<Directory", dirsection, NULL, RSRC_CONF,
3853   "Container for directives affecting resources located in the specified "
3854   "directories"),
3855 AP_INIT_RAW_ARGS("<Location", urlsection, NULL, RSRC_CONF,
3856   "Container for directives affecting resources accessed through the "
3857   "specified URL paths"),
3858 AP_INIT_RAW_ARGS("<VirtualHost", virtualhost_section, NULL, RSRC_CONF,
3859   "Container to map directives to a particular virtual host, takes one or "
3860   "more host addresses"),
3861 AP_INIT_RAW_ARGS("<Files", filesection, NULL, OR_ALL,
3862   "Container for directives affecting files matching specified patterns"),
3863 AP_INIT_RAW_ARGS("<Limit", ap_limit_section, NULL, OR_LIMIT | OR_AUTHCFG,
3864   "Container for authentication directives when accessed using specified HTTP "
3865   "methods"),
3866 AP_INIT_RAW_ARGS("<LimitExcept", ap_limit_section, (void*)1,
3867                  OR_LIMIT | OR_AUTHCFG,
3868   "Container for authentication directives to be applied when any HTTP "
3869   "method other than those specified is used to access the resource"),
3870 AP_INIT_TAKE1("<IfModule", start_ifmod, NULL, EXEC_ON_READ | OR_ALL,
3871   "Container for directives based on existence of specified modules"),
3872 AP_INIT_TAKE1("<IfDefine", start_ifdefine, NULL, EXEC_ON_READ | OR_ALL,
3873   "Container for directives based on existence of command line defines"),
3874 AP_INIT_RAW_ARGS("<DirectoryMatch", dirsection, (void*)1, RSRC_CONF,
3875   "Container for directives affecting resources located in the "
3876   "specified directories"),
3877 AP_INIT_RAW_ARGS("<LocationMatch", urlsection, (void*)1, RSRC_CONF,
3878   "Container for directives affecting resources accessed through the "
3879   "specified URL paths"),
3880 AP_INIT_RAW_ARGS("<FilesMatch", filesection, (void*)1, OR_ALL,
3881   "Container for directives affecting files matching specified patterns"),
3882 #ifdef GPROF
3883 AP_INIT_TAKE1("GprofDir", set_gprof_dir, NULL, RSRC_CONF,
3884   "Directory to plop gmon.out files"),
3885 #endif
3886 AP_INIT_TAKE1("AddDefaultCharset", set_add_default_charset, NULL, OR_FILEINFO,
3887   "The name of the default charset to add to any Content-Type without one or 'Off' to disable"),
3888 AP_INIT_TAKE1("AcceptPathInfo", set_accept_path_info, NULL, OR_FILEINFO,
3889   "Set to on or off for PATH_INFO to be accepted by handlers, or default for the per-handler preference"),
3890 AP_INIT_TAKE12("Define", set_define, NULL, EXEC_ON_READ|ACCESS_CONF|RSRC_CONF,
3891               "Define a variable, optionally to a value.  Same as passing -D to the command line."),
3892 AP_INIT_TAKE1("UnDefine", unset_define, NULL, EXEC_ON_READ|ACCESS_CONF|RSRC_CONF,
3893               "Undefine the existence of a variable. Undo a Define."),
3894 AP_INIT_RAW_ARGS("Error", generate_error, NULL, OR_ALL,
3895                  "Generate error message from within configuration"),
3896 AP_INIT_RAW_ARGS("<If", ifsection, COND_IF, OR_ALL,
3897   "Container for directives to be conditionally applied"),
3898 AP_INIT_RAW_ARGS("<ElseIf", ifsection, COND_ELSEIF, OR_ALL,
3899   "Container for directives to be conditionally applied"),
3900 AP_INIT_RAW_ARGS("<Else", ifsection, COND_ELSE, OR_ALL,
3901   "Container for directives to be conditionally applied"),
3902
3903 /* Old resource config file commands */
3904
3905 AP_INIT_RAW_ARGS("AccessFileName", set_access_name, NULL, RSRC_CONF,
3906   "Name(s) of per-directory config files (default: .htaccess)"),
3907 AP_INIT_TAKE1("DocumentRoot", set_document_root, NULL, RSRC_CONF,
3908   "Root directory of the document tree"),
3909 AP_INIT_TAKE2("ErrorDocument", set_error_document, NULL, OR_FILEINFO,
3910   "Change responses for HTTP errors"),
3911 AP_INIT_RAW_ARGS("AllowOverride", set_override, NULL, ACCESS_CONF,
3912   "Controls what groups of directives can be configured by per-directory "
3913   "config files"),
3914 AP_INIT_TAKE_ARGV("AllowOverrideList", set_override_list, NULL, ACCESS_CONF,
3915   "Controls what individual directives can be configured by per-directory "
3916   "config files"),
3917 AP_INIT_RAW_ARGS("Options", set_options, NULL, OR_OPTIONS,
3918   "Set a number of attributes for a given directory"),
3919 AP_INIT_TAKE1("DefaultType", set_default_type, NULL, OR_FILEINFO,
3920   "the default media type for otherwise untyped files (DEPRECATED)"),
3921 AP_INIT_RAW_ARGS("FileETag", set_etag_bits, NULL, OR_FILEINFO,
3922   "Specify components used to construct a file's ETag"),
3923 AP_INIT_TAKE1("EnableMMAP", set_enable_mmap, NULL, OR_FILEINFO,
3924   "Controls whether memory-mapping may be used to read files"),
3925 AP_INIT_TAKE1("EnableSendfile", set_enable_sendfile, NULL, OR_FILEINFO,
3926   "Controls whether sendfile may be used to transmit files"),
3927
3928 /* Old server config file commands */
3929
3930 AP_INIT_TAKE1("Protocol", set_protocol, NULL, RSRC_CONF,
3931   "Set the Protocol for httpd to use."),
3932 AP_INIT_TAKE2("AcceptFilter", set_accf_map, NULL, RSRC_CONF,
3933   "Set the Accept Filter to use for a protocol"),
3934 AP_INIT_TAKE1("Port", ap_set_deprecated, NULL, RSRC_CONF,
3935   "Port was replaced with Listen in Apache 2.0"),
3936 AP_INIT_TAKE1("HostnameLookups", set_hostname_lookups, NULL,
3937   ACCESS_CONF|RSRC_CONF,
3938   "\"on\" to enable, \"off\" to disable reverse DNS lookups, or \"double\" to "
3939   "enable double-reverse DNS lookups"),
3940 AP_INIT_TAKE1("ServerAdmin", set_server_string_slot,
3941   (void *)APR_OFFSETOF(server_rec, server_admin), RSRC_CONF,
3942   "The email address of the server administrator"),
3943 AP_INIT_TAKE1("ServerName", server_hostname_port, NULL, RSRC_CONF,
3944   "The hostname and port of the server"),
3945 AP_INIT_TAKE1("ServerSignature", set_signature_flag, NULL, OR_ALL,
3946   "En-/disable server signature (on|off|email)"),
3947 AP_INIT_TAKE1("ServerRoot", set_server_root, NULL, RSRC_CONF | EXEC_ON_READ,
3948   "Common directory of server-related files (logs, confs, etc.)"),
3949 AP_INIT_TAKE1("DefaultRuntimeDir", set_runtime_dir, NULL, RSRC_CONF | EXEC_ON_READ,
3950   "Common directory for run-time files (shared memory, locks, etc.)"),
3951 AP_INIT_TAKE1("ErrorLog", set_server_string_slot,
3952   (void *)APR_OFFSETOF(server_rec, error_fname), RSRC_CONF,
3953   "The filename of the error log"),
3954 AP_INIT_TAKE12("ErrorLogFormat", set_errorlog_format, NULL, RSRC_CONF,
3955   "Format string for the ErrorLog"),
3956 AP_INIT_RAW_ARGS("ServerAlias", set_server_alias, NULL, RSRC_CONF,
3957   "A name or names alternately used to access the server"),
3958 AP_INIT_TAKE1("ServerPath", set_serverpath, NULL, RSRC_CONF,
3959   "The pathname the server can be reached at"),
3960 AP_INIT_TAKE1("Timeout", set_timeout, NULL, RSRC_CONF,
3961   "Timeout duration (sec)"),
3962 AP_INIT_FLAG("ContentDigest", set_content_md5, NULL, OR_OPTIONS,
3963   "whether or not to send a Content-MD5 header with each request"),
3964 AP_INIT_TAKE1("UseCanonicalName", set_use_canonical_name, NULL,
3965   RSRC_CONF|ACCESS_CONF,
3966   "How to work out the ServerName : Port when constructing URLs"),
3967 AP_INIT_TAKE1("UseCanonicalPhysicalPort", set_use_canonical_phys_port, NULL,
3968   RSRC_CONF|ACCESS_CONF,
3969   "Whether to use the physical Port when constructing URLs"),
3970 /* TODO: RlimitFoo should all be part of mod_cgi, not in the core */
3971 /* TODO: ListenBacklog in MPM */
3972 AP_INIT_TAKE1("Include", include_config, NULL,
3973   (RSRC_CONF | ACCESS_CONF | EXEC_ON_READ),
3974   "Name(s) of the config file(s) to be included; fails if the wildcard does "
3975   "not match at least one file"),
3976 AP_INIT_TAKE1("IncludeOptional", include_config, (void*)1,
3977   (RSRC_CONF | ACCESS_CONF | EXEC_ON_READ),
3978   "Name or pattern of the config file(s) to be included; ignored if the file "
3979   "does not exist or the pattern does not match any files"),
3980 AP_INIT_ITERATE("LogLevel", set_loglevel, NULL, RSRC_CONF|ACCESS_CONF,
3981   "Level of verbosity in error logging"),
3982 AP_INIT_TAKE1("NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF,
3983   "A numeric IP address:port, or the name of a host"),
3984 AP_INIT_TAKE12("ServerTokens", set_serv_tokens, NULL, RSRC_CONF,
3985   "Determine tokens displayed in the Server: header - Min(imal), "
3986   "Major, Minor, Prod, OS or Full"),
3987 AP_INIT_TAKE1("LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF,
3988   "Limit on maximum size of an HTTP request line"),
3989 AP_INIT_TAKE1("LimitRequestFieldsize", set_limit_req_fieldsize, NULL,
3990   RSRC_CONF,
3991   "Limit on maximum size of an HTTP request header field"),
3992 AP_INIT_TAKE1("LimitRequestFields", set_limit_req_fields, NULL, RSRC_CONF,
3993   "Limit (0 = unlimited) on max number of header fields in a request message"),
3994 AP_INIT_TAKE1("LimitRequestBody", set_limit_req_body,
3995   (void*)APR_OFFSETOF(core_dir_config, limit_req_body), OR_ALL,
3996   "Limit (in bytes) on maximum size of request message body"),
3997 AP_INIT_TAKE1("LimitXMLRequestBody", set_limit_xml_req_body, NULL, OR_ALL,
3998               "Limit (in bytes) on maximum size of an XML-based request "
3999               "body"),
4000 AP_INIT_RAW_ARGS("Mutex", ap_set_mutex, NULL, RSRC_CONF,
4001                  "mutex (or \"default\") and mechanism"),
4002
4003 AP_INIT_TAKE1("MaxRanges", set_max_ranges, NULL, RSRC_CONF|ACCESS_CONF,
4004               "Maximum number of Ranges in a request before returning the entire "
4005               "resource, or 0 for unlimited"),
4006 AP_INIT_TAKE1("MaxRangeOverlaps", set_max_overlaps, NULL, RSRC_CONF|ACCESS_CONF,
4007               "Maximum number of overlaps in Ranges in a request before returning the entire "
4008               "resource, or 0 for unlimited"),
4009 AP_INIT_TAKE1("MaxRangeReversals", set_max_reversals, NULL, RSRC_CONF|ACCESS_CONF,
4010               "Maximum number of reversals in Ranges in a request before returning the entire "
4011               "resource, or 0 for unlimited"),
4012 /* System Resource Controls */
4013 #ifdef RLIMIT_CPU
4014 AP_INIT_TAKE12("RLimitCPU", set_limit_cpu,
4015   (void*)APR_OFFSETOF(core_dir_config, limit_cpu),
4016   OR_ALL, "Soft/hard limits for max CPU usage in seconds"),
4017 #else
4018 AP_INIT_TAKE12("RLimitCPU", no_set_limit, NULL,
4019   OR_ALL, "Soft/hard limits for max CPU usage in seconds"),
4020 #endif
4021 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined (RLIMIT_AS)
4022 AP_INIT_TAKE12("RLimitMEM", set_limit_mem,
4023   (void*)APR_OFFSETOF(core_dir_config, limit_mem),
4024   OR_ALL, "Soft/hard limits for max memory usage per process"),
4025 #else
4026 AP_INIT_TAKE12("RLimitMEM", no_set_limit, NULL,
4027   OR_ALL, "Soft/hard limits for max memory usage per process"),
4028 #endif
4029 #ifdef RLIMIT_NPROC
4030 AP_INIT_TAKE12("RLimitNPROC", set_limit_nproc,
4031   (void*)APR_OFFSETOF(core_dir_config, limit_nproc),
4032   OR_ALL, "soft/hard limits for max number of processes per uid"),
4033 #else
4034 AP_INIT_TAKE12("RLimitNPROC", no_set_limit, NULL,
4035    OR_ALL, "soft/hard limits for max number of processes per uid"),
4036 #endif
4037
4038 /* internal recursion stopper */
4039 AP_INIT_TAKE12("LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF,
4040               "maximum recursion depth of internal redirects and subrequests"),
4041
4042 AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower,
4043        (void *)APR_OFFSETOF(core_dir_config, mime_type), OR_FILEINFO,
4044      "a mime type that overrides other configured type"),
4045 AP_INIT_TAKE1("SetHandler", ap_set_string_slot_lower,
4046        (void *)APR_OFFSETOF(core_dir_config, handler), OR_FILEINFO,
4047    "a handler name that overrides any other configured handler"),
4048 AP_INIT_TAKE1("SetOutputFilter", ap_set_string_slot,
4049        (void *)APR_OFFSETOF(core_dir_config, output_filters), OR_FILEINFO,
4050    "filter (or ; delimited list of filters) to be run on the request content"),
4051 AP_INIT_TAKE1("SetInputFilter", ap_set_string_slot,
4052        (void *)APR_OFFSETOF(core_dir_config, input_filters), OR_FILEINFO,
4053    "filter (or ; delimited list of filters) to be run on the request body"),
4054 AP_INIT_TAKE1("AllowEncodedSlashes", set_allow2f, NULL, RSRC_CONF,
4055              "Allow URLs containing '/' encoded as '%2F'"),
4056
4057 /* scoreboard.c directives */
4058 AP_INIT_TAKE1("ScoreBoardFile", ap_set_scoreboard, NULL, RSRC_CONF,
4059               "A file for Apache to maintain runtime process management information"),
4060 AP_INIT_FLAG("ExtendedStatus", ap_set_extended_status, NULL, RSRC_CONF,
4061              "\"On\" to track extended status information, \"Off\" to disable"),
4062 AP_INIT_FLAG("SeeRequestTail", ap_set_reqtail, NULL, RSRC_CONF,
4063              "For extended status, \"On\" to see the last 63 chars of "
4064              "the request line, \"Off\" (default) to see the first 63"),
4065
4066 /*
4067  * These are default configuration directives that mpms can/should
4068  * pay attention to.
4069  * XXX These are not for all platforms, and even some Unix MPMs might not want
4070  * some directives.
4071  */
4072 AP_INIT_TAKE1("PidFile",  ap_mpm_set_pidfile, NULL, RSRC_CONF,
4073               "A file for logging the server process ID"),
4074 AP_INIT_TAKE1("MaxRequestsPerChild", ap_mpm_set_max_requests, NULL, RSRC_CONF,
4075               "Maximum number of connections a particular child serves before "
4076               "dying. (DEPRECATED, use MaxConnectionsPerChild)"),
4077 AP_INIT_TAKE1("MaxConnectionsPerChild", ap_mpm_set_max_requests, NULL, RSRC_CONF,
4078               "Maximum number of connections a particular child serves before dying."),
4079 AP_INIT_TAKE1("CoreDumpDirectory", ap_mpm_set_coredumpdir, NULL, RSRC_CONF,
4080               "The location of the directory Apache changes to before dumping core"),
4081 AP_INIT_TAKE1("MaxMemFree", ap_mpm_set_max_mem_free, NULL, RSRC_CONF,
4082               "Maximum number of 1k blocks a particular child's allocator may hold."),
4083 AP_INIT_TAKE1("ThreadStackSize", ap_mpm_set_thread_stacksize, NULL, RSRC_CONF,
4084               "Size in bytes of stack used by threads handling client connections"),
4085 #if AP_ENABLE_EXCEPTION_HOOK
4086 AP_INIT_TAKE1("EnableExceptionHook", ap_mpm_set_exception_hook, NULL, RSRC_CONF,
4087               "Controls whether exception hook may be called after a crash"),
4088 #endif
4089 AP_INIT_TAKE1("TraceEnable", set_trace_enable, NULL, RSRC_CONF,
4090               "'on' (default), 'off' or 'extended' to trace request body content"),
4091 { NULL }
4092 };
4093
4094 /*****************************************************************
4095  *
4096  * Core handlers for various phases of server operation...
4097  */
4098
4099 AP_DECLARE_NONSTD(int) ap_core_translate(request_rec *r)
4100 {
4101     apr_status_t rv;
4102     char *path;
4103
4104     /* XXX this seems too specific, this should probably become
4105      * some general-case test
4106      */
4107     if (r->proxyreq) {
4108         return HTTP_FORBIDDEN;
4109     }
4110     if (!r->uri || ((r->uri[0] != '/') && strcmp(r->uri, "*"))) {
4111         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00126)
4112                      "Invalid URI in request %s", r->the_request);
4113         return HTTP_BAD_REQUEST;
4114     }
4115
4116     if (r->server->path
4117         && !strncmp(r->uri, r->server->path, r->server->pathlen)
4118         && (r->server->path[r->server->pathlen - 1] == '/'
4119             || r->uri[r->server->pathlen] == '/'
4120             || r->uri[r->server->pathlen] == '\0'))
4121     {
4122         path = r->uri + r->server->pathlen;
4123     }
4124     else {
4125         path = r->uri;
4126     }
4127     /*
4128      * Make sure that we do not mess up the translation by adding two
4129      * /'s in a row.  This happens under windows when the document
4130      * root ends with a /
4131      */
4132     /* skip all leading /'s (e.g. http://localhost///foo)
4133      * so we are looking at only the relative path.
4134      */
4135     while (*path == '/') {
4136         ++path;
4137     }
4138     if ((rv = apr_filepath_merge(&r->filename, ap_document_root(r), path,
4139                                  APR_FILEPATH_TRUENAME
4140                                | APR_FILEPATH_SECUREROOT, r->pool))
4141                 != APR_SUCCESS) {
4142         ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00127)
4143                      "Cannot map %s to file", r->the_request);
4144         return HTTP_FORBIDDEN;
4145     }
4146     r->canonical_filename = r->filename;
4147
4148     return OK;
4149 }
4150
4151 /*****************************************************************
4152  *
4153  * Test the filesystem name through directory_walk and file_walk
4154  */
4155 static int core_map_to_storage(request_rec *r)
4156 {
4157     int access_status;
4158
4159     if ((access_status = ap_directory_walk(r))) {
4160         return access_status;
4161     }
4162
4163     if ((access_status = ap_file_walk(r))) {
4164         return access_status;
4165     }
4166
4167     return OK;
4168 }
4169
4170
4171 static int do_nothing(request_rec *r) { return OK; }
4172
4173
4174 static int core_override_type(request_rec *r)
4175 {
4176     core_dir_config *conf =
4177         (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
4178
4179     /* Check for overrides with ForceType / SetHandler
4180      */
4181     if (conf->mime_type && strcmp(conf->mime_type, "none"))
4182         ap_set_content_type(r, (char*) conf->mime_type);
4183
4184     if (conf->handler && strcmp(conf->handler, "none"))
4185         r->handler = conf->handler;
4186
4187     /* Deal with the poor soul who is trying to force path_info to be
4188      * accepted within the core_handler, where they will let the subreq
4189      * address its contents.  This is toggled by the user in the very
4190      * beginning of the fixup phase (here!), so modules should override the user's
4191      * discretion in their own module fixup phase.  It is tristate, if
4192      * the user doesn't specify, the result is AP_REQ_DEFAULT_PATH_INFO.
4193      * (which the module may interpret to its own customary behavior.)
4194      * It won't be touched if the value is no longer AP_ACCEPT_PATHINFO_UNSET,
4195      * so any module changing the value prior to the fixup phase
4196      * OVERRIDES the user's choice.
4197      */
4198     if ((r->used_path_info == AP_REQ_DEFAULT_PATH_INFO)
4199         && (conf->accept_path_info != AP_ACCEPT_PATHINFO_UNSET)) {
4200         /* No module knew better, and the user coded AcceptPathInfo */
4201         r->used_path_info = conf->accept_path_info;
4202     }
4203
4204     return OK;
4205 }
4206
4207 static int default_handler(request_rec *r)
4208 {
4209     conn_rec *c = r->connection;
4210     apr_bucket_brigade *bb;
4211     apr_bucket *e;
4212     core_dir_config *d;
4213     int errstatus;
4214     apr_file_t *fd = NULL;
4215     apr_status_t status;
4216     /* XXX if/when somebody writes a content-md5 filter we either need to
4217      *     remove this support or coordinate when to use the filter vs.
4218      *     when to use this code
4219      *     The current choice of when to compute the md5 here matches the 1.3
4220      *     support fairly closely (unlike 1.3, we don't handle computing md5
4221      *     when the charset is translated).
4222      */
4223     int bld_content_md5;
4224
4225     d = (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
4226     bld_content_md5 = (d->content_md5 == AP_CONTENT_MD5_ON)
4227                       && r->output_filters->frec->ftype != AP_FTYPE_RESOURCE;
4228
4229     ap_allow_standard_methods(r, MERGE_ALLOW, M_GET, M_OPTIONS, M_POST, -1);
4230
4231     /* If filters intend to consume the request body, they must
4232      * register an InputFilter to slurp the contents of the POST
4233      * data from the POST input stream.  It no longer exists when
4234      * the output filters are invoked by the default handler.
4235      */
4236     if ((errstatus = ap_discard_request_body(r)) != OK) {
4237         return errstatus;
4238     }
4239
4240     if (r->method_number == M_GET || r->method_number == M_POST) {
4241         if (r->finfo.filetype == APR_NOFILE) {
4242             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00128)
4243                           "File does not exist: %s", r->filename);
4244             return HTTP_NOT_FOUND;
4245         }
4246
4247         /* Don't try to serve a dir.  Some OSs do weird things with
4248          * raw I/O on a dir.
4249          */
4250         if (r->finfo.filetype == APR_DIR) {
4251             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00129)
4252                           "Attempt to serve directory: %s", r->filename);
4253             return HTTP_NOT_FOUND;
4254         }
4255
4256         if ((r->used_path_info != AP_REQ_ACCEPT_PATH_INFO) &&
4257             r->path_info && *r->path_info)
4258         {
4259             /* default to reject */
4260             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00130)
4261                           "File does not exist: %s",
4262                           apr_pstrcat(r->pool, r->filename, r->path_info, NULL));
4263             return HTTP_NOT_FOUND;
4264         }
4265
4266         /* We understood the (non-GET) method, but it might not be legal for
4267            this particular resource. Check to see if the 'deliver_script'
4268            flag is set. If so, then we go ahead and deliver the file since
4269            it isn't really content (only GET normally returns content).
4270
4271            Note: based on logic further above, the only possible non-GET
4272            method at this point is POST. In the future, we should enable
4273            script delivery for all methods.  */
4274         if (r->method_number != M_GET) {
4275             core_request_config *req_cfg;
4276
4277             req_cfg = ap_get_core_module_config(r->request_config);
4278             if (!req_cfg->deliver_script) {
4279                 /* The flag hasn't been set for this request. Punt. */
4280                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00131)
4281                               "This resource does not accept the %s method.",
4282                               r->method);
4283                 return HTTP_METHOD_NOT_ALLOWED;
4284             }
4285         }
4286
4287
4288         if ((status = apr_file_open(&fd, r->filename, APR_READ | APR_BINARY
4289 #if APR_HAS_SENDFILE
4290                             | AP_SENDFILE_ENABLED(d->enable_sendfile)
4291 #endif
4292                                     , 0, r->pool)) != APR_SUCCESS) {
4293             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00132)
4294                           "file permissions deny server access: %s", r->filename);
4295             return HTTP_FORBIDDEN;
4296         }
4297
4298         ap_update_mtime(r, r->finfo.mtime);
4299         ap_set_last_modified(r);
4300         ap_set_etag(r);
4301         ap_set_accept_ranges(r);
4302         ap_set_content_length(r, r->finfo.size);
4303         if (bld_content_md5) {
4304             apr_table_setn(r->headers_out, "Content-MD5",
4305                            ap_md5digest(r->pool, fd));
4306         }
4307
4308         bb = apr_brigade_create(r->pool, c->bucket_alloc);
4309
4310         if ((errstatus = ap_meets_conditions(r)) != OK) {
4311             apr_file_close(fd);
4312             r->status = errstatus;
4313         }
4314         else {
4315             e = apr_brigade_insert_file(bb, fd, 0, r->finfo.size, r->pool);
4316
4317 #if APR_HAS_MMAP
4318             if (d->enable_mmap == ENABLE_MMAP_OFF) {
4319                 (void)apr_bucket_file_enable_mmap(e, 0);
4320             }
4321 #endif
4322         }
4323
4324         e = apr_bucket_eos_create(c->bucket_alloc);
4325         APR_BRIGADE_INSERT_TAIL(bb, e);
4326
4327         status = ap_pass_brigade(r->output_filters, bb);
4328         if (status == APR_SUCCESS
4329             || r->status != HTTP_OK
4330             || c->aborted) {
4331             return OK;
4332         }
4333         else {
4334             /* no way to know what type of error occurred */
4335             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00133)
4336                           "default_handler: ap_pass_brigade returned %i",
4337                           status);
4338             return HTTP_INTERNAL_SERVER_ERROR;
4339         }
4340     }
4341     else {              /* unusual method (not GET or POST) */
4342         if (r->method_number == M_INVALID) {
4343             /* See if this looks like an undecrypted SSL handshake attempt.
4344              * It's safe to look a couple bytes into the_request if it exists, as it's
4345              * always allocated at least MIN_LINE_ALLOC (80) bytes.
4346              */
4347             if (r->the_request
4348                 && r->the_request[0] == 0x16
4349                 && (r->the_request[1] == 0x2 || r->the_request[1] == 0x3)) {
4350                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00134)
4351                               "Invalid method in request %s - possible attempt to establish SSL connection on non-SSL port", r->the_request);
4352             } else {
4353                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00135)
4354                               "Invalid method in request %s", r->the_request);
4355             }
4356             return HTTP_NOT_IMPLEMENTED;
4357         }
4358
4359         if (r->method_number == M_OPTIONS) {
4360             return ap_send_http_options(r);
4361         }
4362         return HTTP_METHOD_NOT_ALLOWED;
4363     }
4364 }
4365
4366 /* Optional function coming from mod_logio, used for logging of output
4367  * traffic
4368  */
4369 APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *ap__logio_add_bytes_out;
4370 APR_OPTIONAL_FN_TYPE(authz_some_auth_required) *ap__authz_ap_some_auth_required;
4371
4372 /* Insist that at least one module will undertake to provide system
4373  * security by dropping startup privileges.
4374  */
4375 static int sys_privileges = 0;
4376 AP_DECLARE(int) ap_sys_privileges_handlers(int inc)
4377 {
4378     sys_privileges += inc;
4379     return sys_privileges;
4380 }
4381
4382 static int check_errorlog_dir(apr_pool_t *p, server_rec *s)
4383 {
4384     if (!s->error_fname || s->error_fname[0] == '|'
4385         || strcmp(s->error_fname, "syslog") == 0) {
4386         return APR_SUCCESS;
4387     }
4388     else {
4389         char *abs = ap_server_root_relative(p, s->error_fname);
4390         char *dir = ap_make_dirstr_parent(p, abs);
4391         apr_finfo_t finfo;
4392         apr_status_t rv = apr_stat(&finfo, dir, APR_FINFO_TYPE, p);
4393         if (rv == APR_SUCCESS && finfo.filetype != APR_DIR)
4394             rv = APR_ENOTDIR;
4395         if (rv != APR_SUCCESS) {
4396             const char *desc = "main error log";
4397             if (s->defn_name)
4398                 desc = apr_psprintf(p, "error log of vhost defined at %s:%d",
4399                                     s->defn_name, s->defn_line_number);
4400             ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_EMERG, rv,
4401                           ap_server_conf, APLOGNO(02291)
4402                          "Cannot access directory '%s' for %s", dir, desc);
4403             return !OK;
4404         }
4405     }
4406     return OK;
4407 }
4408
4409 static int core_check_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
4410 {
4411     int rv = OK;
4412     while (s) {
4413         if (check_errorlog_dir(ptemp, s) != OK)
4414             rv = !OK;
4415         s = s->next;
4416     }
4417     return rv;
4418 }
4419
4420
4421 static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
4422 {
4423     ap_mutex_init(pconf);
4424
4425     if (!saved_server_config_defines)
4426         init_config_defines(pconf);
4427     apr_pool_cleanup_register(pconf, NULL, reset_config_defines,
4428                               apr_pool_cleanup_null);
4429
4430     mpm_common_pre_config(pconf);
4431
4432     return OK;
4433 }
4434
4435 static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
4436 {
4437     ap__logio_add_bytes_out = APR_RETRIEVE_OPTIONAL_FN(ap_logio_add_bytes_out);
4438     ident_lookup = APR_RETRIEVE_OPTIONAL_FN(ap_ident_lookup);
4439     ap__authz_ap_some_auth_required = APR_RETRIEVE_OPTIONAL_FN(authz_some_auth_required);
4440     authn_ap_auth_type = APR_RETRIEVE_OPTIONAL_FN(authn_ap_auth_type);
4441     authn_ap_auth_name = APR_RETRIEVE_OPTIONAL_FN(authn_ap_auth_name);
4442     access_compat_ap_satisfies = APR_RETRIEVE_OPTIONAL_FN(access_compat_ap_satisfies);
4443
4444     set_banner(pconf);
4445     ap_setup_make_content_type(pconf);
4446     ap_setup_auth_internal(ptemp);
4447     if (!sys_privileges) {
4448         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL, APLOGNO(00136)
4449                      "Server MUST relinquish startup privileges before "
4450                      "accepting connections.  Please ensure mod_unixd "
4451                      "or other system security module is loaded.");
4452         return !OK;
4453     }
4454     apr_pool_cleanup_register(pconf, NULL, ap_mpm_end_gen_helper,
4455                               apr_pool_cleanup_null);
4456     return OK;
4457 }
4458
4459 static void core_insert_filter(request_rec *r)
4460 {
4461     core_dir_config *conf = (core_dir_config *)
4462                             ap_get_core_module_config(r->per_dir_config);
4463     const char *filter, *filters = conf->output_filters;
4464
4465     if (filters) {
4466         while (*filters && (filter = ap_getword(r->pool, &filters, ';'))) {
4467             ap_add_output_filter(filter, NULL, r, r->connection);
4468         }
4469     }
4470
4471     filters = conf->input_filters;
4472     if (filters) {
4473         while (*filters && (filter = ap_getword(r->pool, &filters, ';'))) {
4474             ap_add_input_filter(filter, NULL, r, r->connection);
4475         }
4476     }
4477 }
4478
4479 static apr_size_t num_request_notes = AP_NUM_STD_NOTES;
4480
4481 static apr_status_t reset_request_notes(void *dummy)
4482 {
4483     num_request_notes = AP_NUM_STD_NOTES;
4484     return APR_SUCCESS;
4485 }
4486
4487 AP_DECLARE(apr_size_t) ap_register_request_note(void)
4488 {
4489     apr_pool_cleanup_register(apr_hook_global_pool, NULL, reset_request_notes,
4490                               apr_pool_cleanup_null);
4491     return num_request_notes++;
4492 }
4493
4494 AP_DECLARE(void **) ap_get_request_note(request_rec *r, apr_size_t note_num)
4495 {
4496     core_request_config *req_cfg;
4497
4498     if (note_num >= num_request_notes) {
4499         return NULL;
4500     }
4501
4502     req_cfg = (core_request_config *)
4503         ap_get_core_module_config(r->request_config);
4504
4505     if (!req_cfg) {
4506         return NULL;
4507     }
4508
4509     return &(req_cfg->notes[note_num]);
4510 }
4511
4512 AP_DECLARE(apr_socket_t *) ap_get_conn_socket(conn_rec *c)
4513 {
4514     return ap_get_core_module_config(c->conn_config);
4515 }
4516
4517 static int core_create_req(request_rec *r)
4518 {
4519     /* Alloc the config struct and the array of request notes in
4520      * a single block for efficiency
4521      */
4522     core_request_config *req_cfg;
4523
4524     req_cfg = apr_pcalloc(r->pool, sizeof(core_request_config) +
4525                           sizeof(void *) * num_request_notes);
4526     req_cfg->notes = (void **)((char *)req_cfg + sizeof(core_request_config));
4527
4528     /* ### temporarily enable script delivery as the default */
4529     req_cfg->deliver_script = 1;
4530
4531     if (r->main) {
4532         core_request_config *main_req_cfg = (core_request_config *)
4533             ap_get_core_module_config(r->main->request_config);
4534         req_cfg->bb = main_req_cfg->bb;
4535     }
4536     else {
4537         req_cfg->bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
4538     }
4539
4540     ap_set_core_module_config(r->request_config, req_cfg);
4541
4542     return OK;
4543 }
4544
4545 static int core_create_proxy_req(request_rec *r, request_rec *pr)
4546 {
4547     return core_create_req(pr);
4548 }
4549
4550 static conn_rec *core_create_conn(apr_pool_t *ptrans, server_rec *server,
4551                                   apr_socket_t *csd, long id, void *sbh,
4552                                   apr_bucket_alloc_t *alloc)
4553 {
4554     apr_status_t rv;
4555     conn_rec *c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
4556
4557     c->sbh = sbh;
4558     (void)ap_update_child_status(c->sbh, SERVER_BUSY_READ, (request_rec *)NULL);
4559
4560     /* Got a connection structure, so initialize what fields we can
4561      * (the rest are zeroed out by pcalloc).
4562      */
4563     c->conn_config = ap_create_conn_config(ptrans);
4564     c->notes = apr_table_make(ptrans, 5);
4565
4566     c->pool = ptrans;
4567     if ((rv = apr_socket_addr_get(&c->local_addr, APR_LOCAL, csd))
4568         != APR_SUCCESS) {
4569         ap_log_error(APLOG_MARK, APLOG_INFO, rv, server, APLOGNO(00137)
4570                      "apr_socket_addr_get(APR_LOCAL)");
4571         apr_socket_close(csd);
4572         return NULL;
4573     }
4574
4575     apr_sockaddr_ip_get(&c->local_ip, c->local_addr);
4576     if ((rv = apr_socket_addr_get(&c->client_addr, APR_REMOTE, csd))
4577         != APR_SUCCESS) {
4578         ap_log_error(APLOG_MARK, APLOG_INFO, rv, server, APLOGNO(00138)
4579                      "apr_socket_addr_get(APR_REMOTE)");
4580         apr_socket_close(csd);
4581         return NULL;
4582     }
4583
4584     apr_sockaddr_ip_get(&c->client_ip, c->client_addr);
4585     c->base_server = server;
4586
4587     c->id = id;
4588     c->bucket_alloc = alloc;
4589
4590     c->clogging_input_filters = 0;
4591
4592     return c;
4593 }
4594
4595 static int core_pre_connection(conn_rec *c, void *csd)
4596 {
4597     core_net_rec *net = apr_palloc(c->pool, sizeof(*net));
4598     apr_status_t rv;
4599
4600     /* The Nagle algorithm says that we should delay sending partial
4601      * packets in hopes of getting more data.  We don't want to do
4602      * this; we are not telnet.  There are bad interactions between
4603      * persistent connections and Nagle's algorithm that have very severe
4604      * performance penalties.  (Failing to disable Nagle is not much of a
4605      * problem with simple HTTP.)
4606      */
4607     rv = apr_socket_opt_set(csd, APR_TCP_NODELAY, 1);
4608     if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
4609         /* expected cause is that the client disconnected already,
4610          * hence the debug level
4611          */
4612         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00139)
4613                       "apr_socket_opt_set(APR_TCP_NODELAY)");
4614     }
4615
4616     /* The core filter requires the timeout mode to be set, which
4617      * incidentally sets the socket to be nonblocking.  If this
4618      * is not initialized correctly, Linux - for example - will
4619      * be initially blocking, while Solaris will be non blocking
4620      * and any initial read will fail.
4621      */
4622     rv = apr_socket_timeout_set(csd, c->base_server->timeout);
4623     if (rv != APR_SUCCESS) {
4624         /* expected cause is that the client disconnected already */
4625         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00140)
4626                       "apr_socket_timeout_set");
4627     }
4628
4629     net->c = c;
4630     net->in_ctx = NULL;
4631     net->out_ctx = NULL;
4632     net->client_socket = csd;
4633
4634     ap_set_core_module_config(net->c->conn_config, csd);
4635     ap_add_input_filter_handle(ap_core_input_filter_handle, net, NULL, net->c);
4636     ap_add_output_filter_handle(ap_core_output_filter_handle, net, NULL, net->c);
4637     return DONE;
4638 }
4639
4640 AP_DECLARE(int) ap_state_query(int query)
4641 {
4642     switch (query) {
4643     case AP_SQ_MAIN_STATE:
4644         return ap_main_state;
4645     case AP_SQ_RUN_MODE:
4646         return ap_run_mode;
4647     case AP_SQ_CONFIG_GEN:
4648         return ap_config_generation;
4649     default:
4650         return AP_SQ_NOT_SUPPORTED;
4651     }
4652 }
4653
4654 static apr_random_t *rng = NULL;
4655 #if APR_HAS_THREADS
4656 static apr_thread_mutex_t *rng_mutex = NULL;
4657 #endif
4658
4659 static void core_child_init(apr_pool_t *pchild, server_rec *s)
4660 {
4661     apr_proc_t proc;
4662 #if APR_HAS_THREADS
4663     int threaded_mpm;
4664     if (ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded_mpm) == APR_SUCCESS
4665         && threaded_mpm)
4666     {
4667         apr_thread_mutex_create(&rng_mutex, APR_THREAD_MUTEX_DEFAULT, pchild);
4668     }
4669 #endif
4670     /* The MPMs use plain fork() and not apr_proc_fork(), so we have to call
4671      * apr_random_after_fork() manually in the child
4672      */
4673     proc.pid = getpid();
4674     apr_random_after_fork(&proc);
4675 }
4676
4677 AP_CORE_DECLARE(void) ap_random_parent_after_fork(void)
4678 {
4679     /*
4680      * To ensure that the RNG state in the parent changes after the fork, we
4681      * pull some data from the RNG and discard it. This ensures that the RNG
4682      * states in the children are different even after the pid wraps around.
4683      * As we only use apr_random for insecure random bytes, pulling 2 bytes
4684      * should be enough.
4685      * XXX: APR should probably have some dedicated API to do this, but it
4686      * XXX: currently doesn't.
4687      */
4688     apr_uint16_t data;
4689     apr_random_insecure_bytes(rng, &data, sizeof(data));
4690 }
4691
4692 AP_CORE_DECLARE(void) ap_init_rng(apr_pool_t *p)
4693 {
4694     unsigned char seed[8];
4695     apr_status_t rv;
4696     rng = apr_random_standard_new(p);
4697     do {
4698         rv = apr_generate_random_bytes(seed, sizeof(seed));
4699         if (rv != APR_SUCCESS)
4700             goto error;
4701         apr_random_add_entropy(rng, seed, sizeof(seed));
4702         rv = apr_random_insecure_ready(rng);
4703     } while (rv == APR_ENOTENOUGHENTROPY);
4704     if (rv == APR_SUCCESS)
4705         return;
4706 error:
4707     ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, APLOGNO(00141)
4708                  "Could not initialize random number generator");
4709     exit(1);
4710 }
4711
4712 AP_DECLARE(void) ap_random_insecure_bytes(void *buf, apr_size_t size)
4713 {
4714 #if APR_HAS_THREADS
4715     if (rng_mutex)
4716         apr_thread_mutex_lock(rng_mutex);
4717 #endif
4718     /* apr_random_insecure_bytes can only fail with APR_ENOTENOUGHENTROPY,
4719      * and we have ruled that out during initialization. Therefore we don't
4720      * need to check the return code.
4721      */
4722     apr_random_insecure_bytes(rng, buf, size);
4723 #if APR_HAS_THREADS
4724     if (rng_mutex)
4725         apr_thread_mutex_unlock(rng_mutex);
4726 #endif
4727 }
4728
4729 /*
4730  * Finding a random number in a range.
4731  *      n' = a + n(b-a+1)/(M+1)
4732  * where:
4733  *      n' = random number in range
4734  *      a  = low end of range
4735  *      b  = high end of range
4736  *      n  = random number of 0..M
4737  *      M  = maxint
4738  * Algorithm 'borrowed' from PHP's rand() function.
4739  */
4740 #define RAND_RANGE(__n, __min, __max, __tmax) \
4741 (__n) = (__min) + (long) ((double) ((__max) - (__min) + 1.0) * ((__n) / ((__tmax) + 1.0)))
4742 AP_DECLARE(apr_uint32_t) ap_random_pick(apr_uint32_t min, apr_uint32_t max)
4743 {
4744     apr_uint32_t number;
4745     if (max < 16384) {
4746         apr_uint16_t num16;
4747         ap_random_insecure_bytes(&num16, sizeof(num16));
4748         RAND_RANGE(num16, min, max, APR_UINT16_MAX);
4749         number = num16;
4750     }
4751     else {
4752         ap_random_insecure_bytes(&number, sizeof(number));
4753         RAND_RANGE(number, min, max, APR_UINT32_MAX);
4754     }
4755     return number;
4756 }
4757
4758 static apr_status_t core_insert_network_bucket(conn_rec *c,
4759                                                apr_bucket_brigade *bb,
4760                                                apr_socket_t *socket)
4761 {
4762     apr_bucket *e = apr_bucket_socket_create(socket, c->bucket_alloc);
4763     APR_BRIGADE_INSERT_TAIL(bb, e);
4764     return APR_SUCCESS;
4765 }
4766
4767 static void core_dump_config(apr_pool_t *p, server_rec *s)
4768 {
4769     core_server_config *sconf = ap_get_core_module_config(s->module_config);
4770     apr_file_t *out = NULL;
4771     const char *tmp;
4772     const char **defines;
4773     int i;
4774     if (!ap_exists_config_define("DUMP_RUN_CFG"))
4775         return;
4776
4777     apr_file_open_stdout(&out, p);
4778     apr_file_printf(out, "ServerRoot: \"%s\"\n", ap_server_root);
4779     tmp = ap_server_root_relative(p, sconf->ap_document_root);
4780     apr_file_printf(out, "Main DocumentRoot: \"%s\"\n", tmp);
4781     if (s->error_fname[0] != '|' && strcmp(s->error_fname, "syslog") != 0)
4782         tmp = ap_server_root_relative(p, s->error_fname);
4783     else
4784         tmp = s->error_fname;
4785     apr_file_printf(out, "Main ErrorLog: \"%s\"\n", tmp);
4786     if (ap_scoreboard_fname) {
4787         tmp = ap_server_root_relative(p, ap_scoreboard_fname);
4788         apr_file_printf(out, "ScoreBoardFile: \"%s\"\n", tmp);
4789     }
4790     ap_dump_mutexes(p, s, out);
4791     ap_mpm_dump_pidfile(p, out);
4792
4793     defines = (const char **)ap_server_config_defines->elts;
4794     for (i = 0; i < ap_server_config_defines->nelts; i++) {
4795         const char *name = defines[i];
4796         const char *val = NULL;
4797         if (server_config_defined_vars)
4798            val = apr_table_get(server_config_defined_vars, name);
4799         if (val)
4800             apr_file_printf(out, "Define: %s=%s\n", name, val);
4801         else
4802             apr_file_printf(out, "Define: %s\n", name);
4803     }
4804 }
4805
4806 static void register_hooks(apr_pool_t *p)
4807 {
4808     errorlog_hash = apr_hash_make(p);
4809     ap_register_log_hooks(p);
4810     ap_register_config_hooks(p);
4811     ap_expr_init(p);
4812
4813     /* create_connection and pre_connection should always be hooked
4814      * APR_HOOK_REALLY_LAST by core to give other modules the opportunity
4815      * to install alternate network transports and stop other functions
4816      * from being run.
4817      */
4818     ap_hook_create_connection(core_create_conn, NULL, NULL,
4819                               APR_HOOK_REALLY_LAST);
4820     ap_hook_pre_connection(core_pre_connection, NULL, NULL,
4821                            APR_HOOK_REALLY_LAST);
4822
4823     ap_hook_pre_config(core_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
4824     ap_hook_post_config(core_post_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
4825     ap_hook_check_config(core_check_config,NULL,NULL,APR_HOOK_FIRST);
4826     ap_hook_test_config(core_dump_config,NULL,NULL,APR_HOOK_FIRST);
4827     ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST);
4828     ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST);
4829     ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST);
4830     ap_hook_child_init(core_child_init,NULL,NULL,APR_HOOK_REALLY_FIRST);
4831     ap_hook_child_init(ap_logs_child_init,NULL,NULL,APR_HOOK_MIDDLE);
4832     ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST);
4833     /* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */
4834     ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
4835     ap_hook_fixups(core_override_type,NULL,NULL,APR_HOOK_REALLY_FIRST);
4836     ap_hook_create_request(core_create_req, NULL, NULL, APR_HOOK_MIDDLE);
4837     APR_OPTIONAL_HOOK(proxy, create_req, core_create_proxy_req, NULL, NULL,
4838                       APR_HOOK_MIDDLE);
4839     ap_hook_pre_mpm(ap_create_scoreboard, NULL, NULL, APR_HOOK_MIDDLE);
4840     ap_hook_child_status(ap_core_child_status, NULL, NULL, APR_HOOK_MIDDLE);
4841     ap_hook_insert_network_bucket(core_insert_network_bucket, NULL, NULL,
4842                                   APR_HOOK_REALLY_LAST);
4843
4844     /* register the core's insert_filter hook and register core-provided
4845      * filters
4846      */
4847     ap_hook_insert_filter(core_insert_filter, NULL, NULL, APR_HOOK_MIDDLE);
4848
4849     ap_core_input_filter_handle =
4850         ap_register_input_filter("CORE_IN", ap_core_input_filter,
4851                                  NULL, AP_FTYPE_NETWORK);
4852     ap_content_length_filter_handle =
4853         ap_register_output_filter("CONTENT_LENGTH", ap_content_length_filter,
4854                                   NULL, AP_FTYPE_PROTOCOL);
4855     ap_core_output_filter_handle =
4856         ap_register_output_filter("CORE", ap_core_output_filter,
4857                                   NULL, AP_FTYPE_NETWORK);
4858     ap_subreq_core_filter_handle =
4859         ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter,
4860                                   NULL, AP_FTYPE_CONTENT_SET);
4861     ap_old_write_func =
4862         ap_register_output_filter("OLD_WRITE", ap_old_write_filter,
4863                                   NULL, AP_FTYPE_RESOURCE - 10);
4864 }
4865
4866 AP_DECLARE_MODULE(core) = {
4867     MPM20_MODULE_STUFF,
4868     AP_PLATFORM_REWRITE_ARGS_HOOK, /* hook to run before apache parses args */
4869     create_core_dir_config,       /* create per-directory config structure */
4870     merge_core_dir_configs,       /* merge per-directory config structures */
4871     create_core_server_config,    /* create per-server config structure */
4872     merge_core_server_configs,    /* merge per-server config structures */
4873     core_cmds,                    /* command apr_table_t */
4874     register_hooks                /* register hooks */
4875 };
4876