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