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