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