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