1 /* $MirOS: src/usr.sbin/httpd/src/main/http_core.c,v 1.7 2008/12/03 11:22:59 tg Exp $ */
2 /* $OpenBSD: http_core.c,v 1.22 2007/08/24 11:31:29 mbalmer Exp $ */
3
4 /* ====================================================================
5 * The Apache Software License, Version 1.1
6 *
7 * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
8 * reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 *
22 * 3. The end-user documentation included with the redistribution,
23 * if any, must include the following acknowledgment:
24 * "This product includes software developed by the
25 * Apache Software Foundation (http://www.apache.org/)."
26 * Alternately, this acknowledgment may appear in the software itself,
27 * if and wherever such third-party acknowledgments normally appear.
28 *
29 * 4. The names "Apache" and "Apache Software Foundation" must
30 * not be used to endorse or promote products derived from this
31 * software without prior written permission. For written
32 * permission, please contact apache@apache.org.
33 *
34 * 5. Products derived from this software may not be called "Apache",
35 * nor may "Apache" appear in their name, without prior written
36 * permission of the Apache Software Foundation.
37 *
38 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
39 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
40 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
42 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
44 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
45 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
46 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
47 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
48 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 * SUCH DAMAGE.
50 * ====================================================================
51 *
52 * This software consists of voluntary contributions made by many
53 * individuals on behalf of the Apache Software Foundation. For more
54 * information on the Apache Software Foundation, please see
55 * <http://www.apache.org/>.
56 *
57 * Portions of this software are based upon public domain software
58 * originally written at the National Center for Supercomputing Applications,
59 * University of Illinois, Urbana-Champaign.
60 */
61
62 #define CORE_PRIVATE
63 #include "httpd.h"
64 #include "http_config.h"
65 #include "http_core.h"
66 #include "http_protocol.h" /* For index_of_response(). Grump. */
67 #include "http_request.h"
68 #include "http_conf_globals.h"
69 #include "http_vhost.h"
70 #include "http_main.h" /* For the default_handler below... */
71 #include "http_log.h"
72 #include "rfc1413.h"
73 #include "util_md5.h"
74 #include "scoreboard.h"
75 #include "fnmatch.h"
76 #include "sa_len.h"
77
78 #include <sys/mman.h>
79
80 __RCSID("$MirOS: src/usr.sbin/httpd/src/main/http_core.c,v 1.7 2008/12/03 11:22:59 tg Exp $");
81
82 /* mmap support for static files based on ideas from John Heidemann's
83 * patch against 1.0.5. See
84 * <http://www.isi.edu/~johnh/SOFTWARE/APACHE/index.html>.
85 */
86
87 /* Files have to be at least this big before they're mmap()d. This is to deal
88 * with systems where the expense of doing an mmap() and an munmap() outweighs
89 * the benefit for small files. It shouldn't be set lower than 1.
90 */
91 #ifndef MMAP_THRESHOLD
92 #define MMAP_THRESHOLD 1
93 #endif
94 #ifndef MMAP_LIMIT
95 #define MMAP_LIMIT (4*1024*1024)
96 #endif
97
98 /* Server core module... This module provides support for really basic
99 * server operations, including options and commands which control the
100 * operation of other modules. Consider this the bureaucracy module.
101 *
102 * The core module also defines handlers, etc., do handle just enough
103 * to allow a server with the core module ONLY to actually serve documents
104 * (though it slaps DefaultType on all of 'em); this was useful in testing,
105 * but may not be worth preserving.
106 *
107 * This file could almost be mod_core.c, except for the stuff which affects
108 * the http_conf_globals.
109 */
110
create_core_dir_config(pool * a,char * dir)111 static void *create_core_dir_config(pool *a, char *dir)
112 {
113 core_dir_config *conf;
114
115 conf = (core_dir_config *)ap_pcalloc(a, sizeof(core_dir_config));
116 if (!dir || dir[strlen(dir) - 1] == '/') {
117 conf->d = dir;
118 }
119 else if (strncmp(dir, "proxy:", 6) == 0) {
120 conf->d = ap_pstrdup(a, dir);
121 }
122 else {
123 conf->d = ap_pstrcat(a, dir, "/", NULL);
124 }
125 conf->d_is_fnmatch = conf->d ? (ap_is_fnmatch(conf->d) != 0) : 0;
126 conf->d_components = conf->d ? ap_count_dirs(conf->d) : 0;
127
128 conf->opts = dir ? OPT_UNSET : OPT_UNSET|OPT_ALL;
129 conf->opts_add = conf->opts_remove = OPT_NONE;
130 conf->override = dir ? OR_UNSET : OR_UNSET|OR_ALL;
131
132 conf->content_md5 = 2;
133
134 conf->use_canonical_name = USE_CANONICAL_NAME_UNSET;
135
136 conf->hostname_lookups = HOSTNAME_LOOKUP_UNSET;
137 conf->do_rfc1413 = DEFAULT_RFC1413 | 2; /* set bit 1 to indicate default */
138 conf->satisfy = SATISFY_NOSPEC;
139
140 conf->limit_cpu = NULL;
141 #ifdef RLIMIT_TIME
142 conf->limit_time = NULL;
143 #endif
144 conf->limit_mem = NULL;
145 conf->limit_nproc = NULL;
146 conf->limit_nofile = NULL;
147
148 conf->limit_req_body = 0;
149 conf->sec = ap_make_array(a, 2, sizeof(void *));
150
151 conf->server_signature = srv_sig_unset;
152
153 conf->add_default_charset = ADD_DEFAULT_CHARSET_UNSET;
154 conf->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
155
156 /*
157 * Flag for use of inodes in ETags.
158 */
159 conf->etag_bits = ETAG_UNSET;
160 conf->etag_add = ETAG_UNSET;
161 conf->etag_remove = ETAG_UNSET;
162
163 return (void *)conf;
164 }
165
merge_core_dir_configs(pool * a,void * basev,void * newv)166 static void *merge_core_dir_configs(pool *a, void *basev, void *newv)
167 {
168 core_dir_config *base = (core_dir_config *)basev;
169 core_dir_config *new = (core_dir_config *)newv;
170 core_dir_config *conf;
171 int i;
172
173 conf = (core_dir_config *)ap_palloc(a, sizeof(core_dir_config));
174 memcpy((char *)conf, (const char *)base, sizeof(core_dir_config));
175 if (base->response_code_strings) {
176 conf->response_code_strings =
177 ap_palloc(a, sizeof(*conf->response_code_strings)
178 * RESPONSE_CODES);
179 memcpy(conf->response_code_strings, base->response_code_strings,
180 sizeof(*conf->response_code_strings) * RESPONSE_CODES);
181 }
182
183 conf->d = new->d;
184 conf->d_is_fnmatch = new->d_is_fnmatch;
185 conf->d_components = new->d_components;
186 conf->r = new->r;
187
188 if (new->opts & OPT_UNSET) {
189 /* there was no explicit setting of new->opts, so we merge
190 * preserve the invariant (opts_add & opts_remove) == 0
191 */
192 conf->opts_add = (conf->opts_add & ~new->opts_remove) | new->opts_add;
193 conf->opts_remove = (conf->opts_remove & ~new->opts_add)
194 | new->opts_remove;
195 conf->opts = (conf->opts & ~conf->opts_remove) | conf->opts_add;
196 if ((base->opts & OPT_INCNOEXEC) && (new->opts & OPT_INCLUDES)) {
197 conf->opts = (conf->opts & ~OPT_INCNOEXEC) | OPT_INCLUDES;
198 }
199 }
200 else {
201 /* otherwise we just copy, because an explicit opts setting
202 * overrides all earlier +/- modifiers
203 */
204 conf->opts = new->opts;
205 conf->opts_add = new->opts_add;
206 conf->opts_remove = new->opts_remove;
207 }
208
209 if (!(new->override & OR_UNSET)) {
210 conf->override = new->override;
211 }
212 if (new->ap_default_type) {
213 conf->ap_default_type = new->ap_default_type;
214 }
215
216 if (new->ap_auth_type) {
217 conf->ap_auth_type = new->ap_auth_type;
218 }
219 if (new->ap_auth_name) {
220 conf->ap_auth_name = new->ap_auth_name;
221 }
222 if (new->ap_auth_nonce) {
223 conf->ap_auth_nonce = new->ap_auth_nonce;
224 }
225 if (new->ap_requires) {
226 conf->ap_requires = new->ap_requires;
227 }
228
229 if (new->response_code_strings) {
230 if (conf->response_code_strings == NULL) {
231 conf->response_code_strings = ap_palloc(a,
232 sizeof(*conf->response_code_strings) * RESPONSE_CODES);
233 memcpy(conf->response_code_strings, new->response_code_strings,
234 sizeof(*conf->response_code_strings) * RESPONSE_CODES);
235 }
236 else {
237 for (i = 0; i < RESPONSE_CODES; ++i) {
238 if (new->response_code_strings[i] != NULL) {
239 conf->response_code_strings[i]
240 = new->response_code_strings[i];
241 }
242 }
243 }
244 }
245 if (new->hostname_lookups != HOSTNAME_LOOKUP_UNSET) {
246 conf->hostname_lookups = new->hostname_lookups;
247 }
248 if ((new->do_rfc1413 & 2) == 0) {
249 conf->do_rfc1413 = new->do_rfc1413;
250 }
251 if ((new->content_md5 & 2) == 0) {
252 conf->content_md5 = new->content_md5;
253 }
254 if (new->use_canonical_name != USE_CANONICAL_NAME_UNSET) {
255 conf->use_canonical_name = new->use_canonical_name;
256 }
257
258 if (new->limit_cpu) {
259 conf->limit_cpu = new->limit_cpu;
260 }
261 #ifdef RLIMIT_TIME
262 if (new->limit_time) {
263 conf->limit_time = new->limit_time;
264 }
265 #endif
266 if (new->limit_mem) {
267 conf->limit_mem = new->limit_mem;
268 }
269 if (new->limit_nproc) {
270 conf->limit_nproc = new->limit_nproc;
271 }
272 if (new->limit_nofile) {
273 conf->limit_nofile = new->limit_nofile;
274 }
275
276 if (new->limit_req_body) {
277 conf->limit_req_body = new->limit_req_body;
278 }
279 conf->sec = ap_append_arrays(a, base->sec, new->sec);
280
281 if (new->satisfy != SATISFY_NOSPEC) {
282 conf->satisfy = new->satisfy;
283 }
284
285
286 if (new->server_signature != srv_sig_unset) {
287 conf->server_signature = new->server_signature;
288 }
289
290 if (new->add_default_charset != ADD_DEFAULT_CHARSET_UNSET) {
291 conf->add_default_charset = new->add_default_charset;
292 if (new->add_default_charset_name) {
293 conf->add_default_charset_name = new->add_default_charset_name;
294 }
295 }
296
297 /*
298 * Now merge the setting of the FileETag directive.
299 */
300 if (new->etag_bits == ETAG_UNSET) {
301 conf->etag_add =
302 (conf->etag_add & (~ new->etag_remove)) | new->etag_add;
303 conf->etag_remove =
304 (conf->opts_remove & (~ new->etag_add)) | new->etag_remove;
305 conf->etag_bits =
306 (conf->etag_bits & (~ conf->etag_remove)) | conf->etag_add;
307 }
308 else {
309 conf->etag_bits = new->etag_bits;
310 conf->etag_add = new->etag_add;
311 conf->etag_remove = new->etag_remove;
312 }
313 if (conf->etag_bits != ETAG_NONE) {
314 conf->etag_bits &= (~ ETAG_NONE);
315 }
316
317 if (new->cgi_command_args != AP_FLAG_UNSET) {
318 conf->cgi_command_args = new->cgi_command_args;
319 }
320 ap_server_strip_chroot(conf->d, 0);
321
322 return (void*)conf;
323 }
324
create_core_server_config(pool * a,server_rec * s)325 static void *create_core_server_config(pool *a, server_rec *s)
326 {
327 core_server_config *conf;
328 int is_virtual = s->is_virtual;
329
330 conf = (core_server_config *)ap_pcalloc(a, sizeof(core_server_config));
331 #ifdef GPROF
332 conf->gprof_dir = NULL;
333 #endif
334 conf->access_name = is_virtual ? NULL : DEFAULT_ACCESS_FNAME;
335 conf->ap_document_root = is_virtual ? NULL : DOCUMENT_LOCATION;
336 conf->sec = ap_make_array(a, 40, sizeof(void *));
337 conf->sec_url = ap_make_array(a, 40, sizeof(void *));
338
339 /* recursion stopper */
340 conf->redirect_limit = 0;
341 conf->subreq_limit = 0;
342 conf->recursion_limit_set = 0;
343
344 return (void *)conf;
345 }
346
merge_core_server_configs(pool * p,void * basev,void * virtv)347 static void *merge_core_server_configs(pool *p, void *basev, void *virtv)
348 {
349 core_server_config *base = (core_server_config *)basev;
350 core_server_config *virt = (core_server_config *)virtv;
351 core_server_config *conf;
352
353 conf = (core_server_config *)ap_pcalloc(p, sizeof(core_server_config));
354 *conf = *virt;
355 if (!conf->access_name) {
356 conf->access_name = base->access_name;
357 }
358 if (!conf->ap_document_root) {
359 conf->ap_document_root = base->ap_document_root;
360 }
361 conf->sec = ap_append_arrays(p, base->sec, virt->sec);
362 conf->sec_url = ap_append_arrays(p, base->sec_url, virt->sec_url);
363
364 conf->redirect_limit = virt->recursion_limit_set
365 ? virt->redirect_limit
366 : base->redirect_limit;
367
368 conf->subreq_limit = virt->recursion_limit_set
369 ? virt->subreq_limit
370 : base->subreq_limit;
371
372 return conf;
373 }
374
375 /* Add per-directory configuration entry (for <directory> section);
376 * these are part of the core server config.
377 */
378
ap_add_per_dir_conf(server_rec * s,void * dir_config)379 CORE_EXPORT(void) ap_add_per_dir_conf(server_rec *s, void *dir_config)
380 {
381 core_server_config *sconf = ap_get_module_config(s->module_config,
382 &core_module);
383 void **new_space = (void **)ap_push_array(sconf->sec);
384
385 *new_space = dir_config;
386 }
387
ap_add_per_url_conf(server_rec * s,void * url_config)388 CORE_EXPORT(void) ap_add_per_url_conf(server_rec *s, void *url_config)
389 {
390 core_server_config *sconf = ap_get_module_config(s->module_config,
391 &core_module);
392 void **new_space = (void **)ap_push_array(sconf->sec_url);
393
394 *new_space = url_config;
395 }
396
ap_add_file_conf(core_dir_config * conf,void * url_config)397 CORE_EXPORT(void) ap_add_file_conf(core_dir_config *conf, void *url_config)
398 {
399 void **new_space = (void **)ap_push_array(conf->sec);
400
401 *new_space = url_config;
402 }
403
404 /* core_reorder_directories reorders the directory sections such that the
405 * 1-component sections come first, then the 2-component, and so on, finally
406 * followed by the "special" sections. A section is "special" if it's a regex,
407 * or if it doesn't start with / -- consider proxy: matching. All movements
408 * are in-order to preserve the ordering of the sections from the config files.
409 * See directory_walk().
410 */
411
412 #define IS_SPECIAL(entry_core) \
413 ((entry_core)->r != NULL || (entry_core)->d[0] != '/')
414
415 /* We need to do a stable sort, qsort isn't stable. So to make it stable
416 * we'll be maintaining the original index into the list, and using it
417 * as the minor key during sorting. The major key is the number of
418 * components (where a "special" section has infinite components).
419 */
420 struct reorder_sort_rec {
421 void *elt;
422 int orig_index;
423 };
424
reorder_sorter(const void * va,const void * vb)425 static int reorder_sorter(const void *va, const void *vb)
426 {
427 const struct reorder_sort_rec *a = va;
428 const struct reorder_sort_rec *b = vb;
429 core_dir_config *core_a;
430 core_dir_config *core_b;
431
432 core_a = (core_dir_config *)ap_get_module_config(a->elt, &core_module);
433 core_b = (core_dir_config *)ap_get_module_config(b->elt, &core_module);
434 if (IS_SPECIAL(core_a)) {
435 if (!IS_SPECIAL(core_b)) {
436 return 1;
437 }
438 }
439 else if (IS_SPECIAL(core_b)) {
440 return -1;
441 }
442 else {
443 /* we know they're both not special */
444 if (core_a->d_components < core_b->d_components) {
445 return -1;
446 }
447 else if (core_a->d_components > core_b->d_components) {
448 return 1;
449 }
450 }
451 /* Either they're both special, or they're both not special and have the
452 * same number of components. In any event, we now have to compare
453 * the minor key. */
454 return a->orig_index - b->orig_index;
455 }
456
ap_core_reorder_directories(pool * p,server_rec * s)457 CORE_EXPORT(void) ap_core_reorder_directories(pool *p, server_rec *s)
458 {
459 core_server_config *sconf;
460 array_header *sec;
461 struct reorder_sort_rec *sortbin;
462 int nelts;
463 void **elts;
464 int i;
465 pool *tmp;
466
467 sconf = ap_get_module_config(s->module_config, &core_module);
468 sec = sconf->sec;
469 nelts = sec->nelts;
470 elts = (void **)sec->elts;
471
472 /* we have to allocate tmp space to do a stable sort */
473 tmp = ap_make_sub_pool(p);
474 sortbin = ap_palloc(tmp, sec->nelts * sizeof(*sortbin));
475 for (i = 0; i < nelts; ++i) {
476 sortbin[i].orig_index = i;
477 sortbin[i].elt = elts[i];
478 }
479
480 qsort(sortbin, nelts, sizeof(*sortbin), reorder_sorter);
481
482 /* and now copy back to the original array */
483 for (i = 0; i < nelts; ++i) {
484 elts[i] = sortbin[i].elt;
485 }
486
487 ap_destroy_pool(tmp);
488 }
489
490 /*****************************************************************
491 *
492 * There are some elements of the core config structures in which
493 * other modules have a legitimate interest (this is ugly, but necessary
494 * to preserve NCSA back-compatibility). So, we have a bunch of accessors
495 * here...
496 */
497
ap_allow_options(request_rec * r)498 API_EXPORT(int) ap_allow_options(request_rec *r)
499 {
500 core_dir_config *conf =
501 (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
502
503 return conf->opts;
504 }
505
ap_allow_overrides(request_rec * r)506 API_EXPORT(int) ap_allow_overrides(request_rec *r)
507 {
508 core_dir_config *conf;
509 conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
510 &core_module);
511
512 return conf->override;
513 }
514
ap_auth_type(request_rec * r)515 API_EXPORT(const char *) ap_auth_type(request_rec *r)
516 {
517 core_dir_config *conf;
518
519 conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
520 &core_module);
521 return conf->ap_auth_type;
522 }
523
ap_auth_name(request_rec * r)524 API_EXPORT(const char *) ap_auth_name(request_rec *r)
525 {
526 core_dir_config *conf;
527
528 conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
529 &core_module);
530 return conf->ap_auth_name;
531 }
532
ap_auth_nonce(request_rec * r)533 API_EXPORT(const char *) ap_auth_nonce(request_rec *r)
534 {
535 core_dir_config *conf;
536 conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
537 &core_module);
538 if (conf->ap_auth_nonce)
539 return conf->ap_auth_nonce;
540
541 /* Ideally we'd want to mix in some per-directory style
542 * information; as we are likely to want to detect replay
543 * across those boundaries and some randomness. But that
544 * is harder due to the adhoc nature of .htaccess memory
545 * structures, restarts and forks.
546 *
547 * But then again - you should use AuthDigestRealmSeed in your config
548 * file if you care. So the adhoc value should do.
549 */
550 return ap_psprintf(r->pool,"%pp%pp%pp%pp%pp",
551 (void *)&(((struct sockaddr_in *)&r->connection->local_addr)->sin_addr ),
552 (void *)ap_user_name,
553 (void *)ap_listeners,
554 (void *)ap_server_argv0,
555 (void *)ap_pid_fname);
556 }
557
ap_default_type(request_rec * r)558 API_EXPORT(const char *) ap_default_type(request_rec *r)
559 {
560 core_dir_config *conf;
561
562 conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
563 &core_module);
564 return conf->ap_default_type
565 ? conf->ap_default_type
566 : DEFAULT_CONTENT_TYPE;
567 }
568
ap_document_root(request_rec * r)569 API_EXPORT(const char *) ap_document_root(request_rec *r) /* Don't use this! */
570 {
571 core_server_config *conf;
572
573 conf = (core_server_config *)ap_get_module_config(r->server->module_config,
574 &core_module);
575 return conf->ap_document_root;
576 }
577
ap_requires(request_rec * r)578 API_EXPORT(const array_header *) ap_requires(request_rec *r)
579 {
580 core_dir_config *conf;
581
582 conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
583 &core_module);
584 return conf->ap_requires;
585 }
586
ap_satisfies(request_rec * r)587 API_EXPORT(int) ap_satisfies(request_rec *r)
588 {
589 core_dir_config *conf;
590
591 conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
592 &core_module);
593
594 return conf->satisfy;
595 }
596
597 /* Should probably just get rid of this... the only code that cares is
598 * part of the core anyway (and in fact, it isn't publicised to other
599 * modules).
600 */
601
ap_response_code_string(request_rec * r,int error_index)602 API_EXPORT(char *) ap_response_code_string(request_rec *r, int error_index)
603 {
604 core_dir_config *conf;
605
606 conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
607 &core_module);
608
609 if (conf->response_code_strings == NULL) {
610 return NULL;
611 }
612 return conf->response_code_strings[error_index];
613 }
614
615
616 /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
617 /* Note: the function returns its result in conn->double_reverse:
618 * +1: forward lookup of the previously reverse-looked-up
619 * hostname in conn->remote_host succeeded, and at
620 * least one of its IP addresses matches the client.
621 * -1: forward lookup of conn->remote_host failed, or
622 * none of the addresses found matches the client connection
623 * (possible DNS spoof in the reverse zone!)
624 * If do_double_reverse() returns -1, then it also invalidates
625 * conn->remote_host to prevent an invalid name from appearing
626 * in the log files. Conn->remote_host is set to "", because
627 * a setting of NULL would allow another reverse lookup,
628 * depending on the flags given to ap_get_remote_host().
629 */
do_double_reverse(conn_rec * conn)630 static ap_inline void do_double_reverse (conn_rec *conn)
631 {
632 struct addrinfo hints, *res, *res0;
633 char hostbuf1[128], hostbuf2[128]; /* INET6_ADDRSTRLEN(=46) is enough */
634 int ok = 0;
635
636 if (conn->double_reverse) {
637 /* already done */
638 return;
639 }
640 if (conn->remote_host == NULL || conn->remote_host[0] == '\0') {
641 /* single reverse failed, so don't bother */
642 conn->double_reverse = -1;
643 conn->remote_host = ""; /* prevent another lookup */
644 return;
645 }
646 memset(&hints, 0, sizeof(hints));
647 hints.ai_family = PF_UNSPEC;
648 hints.ai_socktype = SOCK_STREAM;
649 if (getaddrinfo(conn->remote_host, NULL, &hints, &res0)) {
650 conn->double_reverse = -1;
651 return;
652 }
653 for (res = res0; res; res = res->ai_next) {
654 if (res->ai_addr->sa_family != conn->remote_addr.ss_family ||
655 !(res->ai_family == AF_INET
656 #ifdef INET6
657 || res->ai_family == AF_INET6
658 #endif
659 )
660 )
661 continue;
662 #ifndef HAVE_SOCKADDR_LEN
663 if (res->ai_addrlen != SA_LEN((struct sockaddr *)&conn->remote_addr))
664 #else
665 if (res->ai_addr->sa_len != conn->remote_addr.ss_len)
666 #endif
667 continue;
668 if (getnameinfo(res->ai_addr, res->ai_addrlen,
669 hostbuf1, sizeof(hostbuf1), NULL, 0,
670 NI_NUMERICHOST))
671 continue;
672 if (getnameinfo(((struct sockaddr *)&conn->remote_addr), res->ai_addrlen,
673 hostbuf2, sizeof(hostbuf2), NULL, 0,
674 NI_NUMERICHOST))
675 continue;
676 if (strcmp(hostbuf1, hostbuf2) == 0){
677 ok = 1;
678 break;
679 }
680 }
681 conn->double_reverse = ok ? 1 : -1;
682 freeaddrinfo(res0);
683 }
684
ap_get_remote_host(conn_rec * conn,void * dir_config,int type)685 API_EXPORT(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
686 int type)
687 {
688 int hostname_lookups;
689 int old_stat = SERVER_DEAD; /* we shouldn't ever be in this state */
690 char hostnamebuf[MAXHOSTNAMELEN];
691
692 /* If we haven't checked the host name, and we want to */
693 if (dir_config) {
694 hostname_lookups =
695 ((core_dir_config *)ap_get_module_config(dir_config, &core_module))
696 ->hostname_lookups;
697 if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) {
698 hostname_lookups = HOSTNAME_LOOKUP_OFF;
699 }
700 }
701 else {
702 /* the default */
703 hostname_lookups = HOSTNAME_LOOKUP_OFF;
704 }
705
706 if (type != REMOTE_NOLOOKUP
707 && conn->remote_host == NULL
708 && (type == REMOTE_DOUBLE_REV
709 || hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
710 old_stat = ap_update_child_status(conn->child_num, SERVER_BUSY_DNS,
711 (request_rec*)NULL);
712 if (!getnameinfo((struct sockaddr *)&conn->remote_addr,
713 #ifndef SIN6_LEN
714 SA_LEN((struct sockaddr *)&conn->remote_addr),
715 #else
716 conn->remote_addr.ss_len,
717 #endif
718 hostnamebuf, sizeof(hostnamebuf), NULL, 0, 0)) {
719 conn->remote_host = ap_pstrdup(conn->pool, (void *)hostnamebuf);
720 ap_str_tolower(conn->remote_host);
721
722 if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
723 do_double_reverse(conn);
724 }
725 }
726 /* if failed, set it to the NULL string to indicate error */
727 if (conn->remote_host == NULL) {
728 conn->remote_host = "";
729 }
730 }
731 if (type == REMOTE_DOUBLE_REV) {
732 do_double_reverse(conn);
733 if (conn->double_reverse == -1) {
734 return NULL;
735 }
736 }
737 if (old_stat != SERVER_DEAD) {
738 (void)ap_update_child_status(conn->child_num, old_stat,
739 (request_rec*)NULL);
740 }
741
742 /*
743 * Return the desired information; either the remote DNS name, if found,
744 * or either NULL (if the hostname was requested) or the IP address
745 * (if any identifier was requested).
746 */
747 if (conn->remote_host != NULL && conn->remote_host[0] != '\0') {
748 return conn->remote_host;
749 }
750 else {
751 if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) {
752 return NULL;
753 }
754 else {
755 return conn->remote_ip;
756 }
757 }
758 }
759
ap_get_remote_logname(request_rec * r)760 API_EXPORT(const char *) ap_get_remote_logname(request_rec *r)
761 {
762 core_dir_config *dir_conf;
763
764 if (r->connection->remote_logname != NULL) {
765 return r->connection->remote_logname;
766 }
767
768 /* If we haven't checked the identity, and we want to */
769 dir_conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
770 &core_module);
771
772 if (dir_conf->do_rfc1413 & 1) {
773 return ap_rfc1413(r->connection, r->server);
774 }
775 else {
776 return NULL;
777 }
778 }
779
780 /* There are two options regarding what the "name" of a server is. The
781 * "canonical" name as defined by ServerName and Port, or the "client's
782 * name" as supplied by a possible Host: header or full URI. We never
783 * trust the port passed in the client's headers, we always use the
784 * port of the actual socket.
785 *
786 * The DNS option to UseCanonicalName causes this routine to do a
787 * reverse lookup on the local IP address of the connectiona and use
788 * that for the ServerName. This makes its value more reliable while
789 * at the same time allowing Demon's magic virtual hosting to work.
790 * The assumption is that DNS lookups are sufficiently quick...
791 * -- fanf 1998-10-03
792 */
ap_get_server_name(request_rec * r)793 API_EXPORT(const char *) ap_get_server_name(request_rec *r)
794 {
795 conn_rec *conn = r->connection;
796 core_dir_config *d;
797 char hbuf[MAXHOSTNAMELEN];
798
799 d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
800 &core_module);
801
802 if (d->use_canonical_name == USE_CANONICAL_NAME_OFF) {
803 return r->hostname ? r->hostname : r->server->server_hostname;
804 }
805 if (d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
806 if (conn->local_host == NULL) {
807 int old_stat;
808 old_stat = ap_update_child_status(conn->child_num,
809 SERVER_BUSY_DNS, r);
810 if (getnameinfo((struct sockaddr *)&conn->local_addr,
811 #ifndef SIN6_LEN
812 SA_LEN((struct sockaddr *)&conn->local_addr),
813 #else
814 conn->local_addr.ss_len,
815 #endif
816 hbuf, sizeof(hbuf), NULL, 0, 0) == 0) {
817 conn->local_host = ap_pstrdup(conn->pool, hbuf);
818 } else {
819 conn->local_host = ap_pstrdup(conn->pool,
820 r->server->server_hostname);
821 }
822 ap_str_tolower(conn->local_host);
823 (void) ap_update_child_status(conn->child_num, old_stat, r);
824 }
825 return conn->local_host;
826 }
827 /* default */
828 return r->server->server_hostname;
829 }
830
ap_get_server_port(const request_rec * r)831 API_EXPORT(unsigned) ap_get_server_port(const request_rec *r)
832 {
833 unsigned port;
834 unsigned cport = ntohs(((struct sockaddr_in *)&r->connection->local_addr)->sin_port);
835 core_dir_config *d =
836 (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
837
838 if (d->use_canonical_name == USE_CANONICAL_NAME_OFF
839 || d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
840
841 /* With UseCanonicalName Off Apache will form self-referential
842 * URLs using the hostname and port supplied by the client if
843 * any are supplied (otherwise it will use the canonical name).
844 */
845 port = r->parsed_uri.port_str ? r->parsed_uri.port :
846 cport ? cport :
847 r->server->port ? r->server->port :
848 ap_default_port(r);
849 } else { /* d->use_canonical_name == USE_CANONICAL_NAME_ON */
850 port = r->server->port ? r->server->port :
851 cport ? cport :
852 ap_default_port(r);
853 }
854
855 /* default */
856 return port;
857 }
858
ap_construct_url(pool * p,const char * uri,request_rec * r)859 API_EXPORT(char *) ap_construct_url(pool *p, const char *uri,
860 request_rec *r)
861 {
862 unsigned port = ap_get_server_port(r);
863 const char *host = ap_get_server_name(r);
864
865 if (ap_is_default_port(port, r)) {
866 return ap_pstrcat(p, ap_http_method(r), "://", host, uri, NULL);
867 }
868 return ap_psprintf(p, "%s://%s:%u%s", ap_http_method(r), host, port, uri);
869 }
870
ap_get_limit_req_body(const request_rec * r)871 API_EXPORT(unsigned long) ap_get_limit_req_body(const request_rec *r)
872 {
873 core_dir_config *d =
874 (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
875
876 return d->limit_req_body;
877 }
878
879
880 /*****************************************************************
881 *
882 * Commands... this module handles almost all of the NCSA httpd.conf
883 * commands, but most of the old srm.conf is in the the modules.
884 */
885
886 static const char end_directory_section[] = "</Directory>";
887 static const char end_directorymatch_section[] = "</DirectoryMatch>";
888 static const char end_location_section[] = "</Location>";
889 static const char end_locationmatch_section[] = "</LocationMatch>";
890 static const char end_files_section[] = "</Files>";
891 static const char end_filesmatch_section[] = "</FilesMatch>";
892 static const char end_virtualhost_section[] = "</VirtualHost>";
893 static const char end_ifmodule_section[] = "</IfModule>";
894 static const char end_ifdefine_section[] = "</IfDefine>";
895
896
ap_check_cmd_context(cmd_parms * cmd,unsigned forbidden)897 API_EXPORT(const char *) ap_check_cmd_context(cmd_parms *cmd,
898 unsigned forbidden)
899 {
900 const char *gt = (cmd->cmd->name[0] == '<'
901 && cmd->cmd->name[strlen(cmd->cmd->name)-1] != '>')
902 ? ">" : "";
903
904 if ((forbidden & NOT_IN_VIRTUALHOST) && cmd->server->is_virtual) {
905 return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
906 " cannot occur within <VirtualHost> section", NULL);
907 }
908
909 if ((forbidden & NOT_IN_LIMIT) && cmd->limited != -1) {
910 return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
911 " cannot occur within <Limit> section", NULL);
912 }
913
914 if ((forbidden & NOT_IN_DIR_LOC_FILE) == NOT_IN_DIR_LOC_FILE
915 && cmd->path != NULL) {
916 return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
917 " cannot occur within <Directory/Location/Files> "
918 "section", NULL);
919 }
920
921 if (((forbidden & NOT_IN_DIRECTORY)
922 && (cmd->end_token == end_directory_section
923 || cmd->end_token == end_directorymatch_section))
924 || ((forbidden & NOT_IN_LOCATION)
925 && (cmd->end_token == end_location_section
926 || cmd->end_token == end_locationmatch_section))
927 || ((forbidden & NOT_IN_FILES)
928 && (cmd->end_token == end_files_section
929 || cmd->end_token == end_filesmatch_section))) {
930 return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
931 " cannot occur within <", cmd->end_token+2,
932 " section", NULL);
933 }
934
935 return NULL;
936 }
937
set_access_name(cmd_parms * cmd,void * dummy,char * arg)938 static const char *set_access_name(cmd_parms *cmd, void *dummy, char *arg)
939 {
940 void *sconf = cmd->server->module_config;
941 core_server_config *conf = ap_get_module_config(sconf, &core_module);
942
943 const char *err = ap_check_cmd_context(cmd,
944 NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
945 if (err != NULL) {
946 return err;
947 }
948
949 conf->access_name = ap_pstrdup(cmd->pool, arg);
950 return NULL;
951 }
952
953 #ifdef GPROF
set_gprof_dir(cmd_parms * cmd,void * dummy,char * arg)954 static const char *set_gprof_dir(cmd_parms *cmd, void *dummy, char *arg)
955 {
956 void *sconf = cmd->server->module_config;
957 core_server_config *conf = ap_get_module_config(sconf, &core_module);
958
959 const char *err = ap_check_cmd_context(cmd,
960 NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
961 if (err != NULL) {
962 return err;
963 }
964
965 conf->gprof_dir = ap_pstrdup(cmd->pool, arg);
966 return NULL;
967 }
968 #endif /*GPROF*/
969
set_add_default_charset(cmd_parms * cmd,core_dir_config * d,char * arg)970 static const char *set_add_default_charset(cmd_parms *cmd,
971 core_dir_config *d, char *arg)
972 {
973 const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
974 if (err != NULL) {
975 return err;
976 }
977 if (!strcasecmp(arg, "Off")) {
978 d->add_default_charset = ADD_DEFAULT_CHARSET_OFF;
979 }
980 else if (!strcasecmp(arg, "On")) {
981 d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
982 d->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
983 }
984 else {
985 d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
986 d->add_default_charset_name = arg;
987 }
988 return NULL;
989 }
set_accept_mutex(cmd_parms * cmd,void * dummy,char * arg)990 static const char *set_accept_mutex(cmd_parms *cmd, void *dummy, char *arg)
991 {
992 return ap_init_mutex_method(arg);
993 }
994
set_document_root(cmd_parms * cmd,void * dummy,char * arg)995 static const char *set_document_root(cmd_parms *cmd, void *dummy, char *arg)
996 {
997 void *sconf = cmd->server->module_config;
998 core_server_config *conf = ap_get_module_config(sconf, &core_module);
999
1000 const char *err = ap_check_cmd_context(cmd,
1001 NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1002 if (err != NULL) {
1003 return err;
1004 }
1005
1006 arg = ap_os_canonical_filename(cmd->pool, arg);
1007 if (ap_configtestonly && ap_docrootcheck && !ap_is_directory(arg)) {
1008 if (cmd->server->is_virtual) {
1009 fprintf(stderr, "Warning: DocumentRoot [%s] does not exist\n",
1010 arg);
1011 }
1012 else {
1013 return "DocumentRoot must be a directory";
1014 }
1015 }
1016 ap_server_strip_chroot(arg, 1);
1017 conf->ap_document_root = arg;
1018 return NULL;
1019 }
1020
ap_custom_response(request_rec * r,int status,char * string)1021 API_EXPORT(void) ap_custom_response(request_rec *r, int status, char *string)
1022 {
1023 core_dir_config *conf =
1024 ap_get_module_config(r->per_dir_config, &core_module);
1025 int idx;
1026
1027 ap_server_strip_chroot(conf->d, 0);
1028 if(conf->response_code_strings == NULL) {
1029 conf->response_code_strings =
1030 ap_pcalloc(r->pool,
1031 sizeof(*conf->response_code_strings) *
1032 RESPONSE_CODES);
1033 }
1034
1035 idx = ap_index_of_response(status);
1036
1037 conf->response_code_strings[idx] =
1038 ((ap_is_url(string) || (*string == '/')) && (*string != '"')) ?
1039 ap_pstrdup(r->pool, string) : ap_pstrcat(r->pool, "\"", string, NULL);
1040 }
1041
set_error_document(cmd_parms * cmd,core_dir_config * conf,char * line)1042 static const char *set_error_document(cmd_parms *cmd, core_dir_config *conf,
1043 char *line)
1044 {
1045 int error_number, index_number, idx500;
1046 char *w;
1047
1048 const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1049 if (err != NULL) {
1050 return err;
1051 }
1052
1053 /* 1st parameter should be a 3 digit number, which we recognize;
1054 * convert it into an array index
1055 */
1056
1057 w = ap_getword_conf_nc(cmd->pool, &line);
1058 error_number = atoi(w);
1059
1060 idx500 = ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);
1061
1062 if (error_number == HTTP_INTERNAL_SERVER_ERROR) {
1063 index_number = idx500;
1064 }
1065 else if ((index_number = ap_index_of_response(error_number)) == idx500) {
1066 return ap_pstrcat(cmd->pool, "Unsupported HTTP response code ",
1067 w, NULL);
1068 }
1069
1070 /* The entry should be ignored if it is a full URL for a 401 error */
1071
1072 if (error_number == 401 &&
1073 line[0] != '/' && line[0] != '"') { /* Ignore it... */
1074 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, cmd->server,
1075 "cannot use a full URL in a 401 ErrorDocument "
1076 "directive --- ignoring!");
1077 }
1078 else { /* Store it... */
1079 if (conf->response_code_strings == NULL) {
1080 conf->response_code_strings =
1081 ap_pcalloc(cmd->pool,
1082 sizeof(*conf->response_code_strings) * RESPONSE_CODES);
1083 }
1084 conf->response_code_strings[index_number] = ap_pstrdup(cmd->pool, line);
1085 }
1086
1087 return NULL;
1088 }
1089
1090 /* access.conf commands...
1091 *
1092 * The *only* thing that can appear in access.conf at top level is a
1093 * <Directory> section. NB we need to have a way to cut the srm_command_loop
1094 * invoked by dirsection (i.e., <Directory>) short when </Directory> is seen.
1095 * We do that by returning an error, which dirsection itself recognizes and
1096 * discards as harmless. Cheesy, but it works.
1097 */
1098
set_override(cmd_parms * cmd,core_dir_config * d,const char * l)1099 static const char *set_override(cmd_parms *cmd, core_dir_config *d,
1100 const char *l)
1101 {
1102 char *w;
1103
1104 const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1105 if (err != NULL) {
1106 return err;
1107 }
1108
1109 d->override = OR_NONE;
1110 while (l[0]) {
1111 w = ap_getword_conf(cmd->pool, &l);
1112 if (!strcasecmp(w, "Limit")) {
1113 d->override |= OR_LIMIT;
1114 }
1115 else if (!strcasecmp(w, "Options")) {
1116 d->override |= OR_OPTIONS;
1117 }
1118 else if (!strcasecmp(w, "FileInfo")) {
1119 d->override |= OR_FILEINFO;
1120 }
1121 else if (!strcasecmp(w, "AuthConfig")) {
1122 d->override |= OR_AUTHCFG;
1123 }
1124 else if (!strcasecmp(w, "Indexes")) {
1125 d->override |= OR_INDEXES;
1126 }
1127 else if (!strcasecmp(w, "None")) {
1128 d->override = OR_NONE;
1129 }
1130 else if (!strcasecmp(w, "All")) {
1131 d->override = OR_ALL;
1132 }
1133 else {
1134 return ap_pstrcat(cmd->pool, "Illegal override option ", w, NULL);
1135 }
1136 d->override &= ~OR_UNSET;
1137 }
1138
1139 return NULL;
1140 }
1141
set_options(cmd_parms * cmd,core_dir_config * d,const char * l)1142 static const char *set_options(cmd_parms *cmd, core_dir_config *d,
1143 const char *l)
1144 {
1145 allow_options_t opt;
1146 int first = 1;
1147 char action;
1148
1149 while (l[0]) {
1150 char *w = ap_getword_conf(cmd->pool, &l);
1151 action = '\0';
1152
1153 if (*w == '+' || *w == '-') {
1154 action = *(w++);
1155 }
1156 else if (first) {
1157 d->opts = OPT_NONE;
1158 first = 0;
1159 }
1160
1161 if (!strcasecmp(w, "Indexes")) {
1162 opt = OPT_INDEXES;
1163 }
1164 else if (!strcasecmp(w, "Includes")) {
1165 opt = OPT_INCLUDES;
1166 }
1167 else if (!strcasecmp(w, "IncludesNOEXEC")) {
1168 opt = (OPT_INCLUDES | OPT_INCNOEXEC);
1169 }
1170 else if (!strcasecmp(w, "FollowSymLinks")) {
1171 opt = OPT_SYM_LINKS;
1172 }
1173 else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
1174 opt = OPT_SYM_OWNER;
1175 }
1176 else if (!strcasecmp(w, "execCGI")) {
1177 opt = OPT_EXECCGI;
1178 }
1179 else if (!strcasecmp(w, "MultiViews")) {
1180 opt = OPT_MULTI;
1181 }
1182 else if (!strcasecmp(w, "RunScripts")) { /* AI backcompat. Yuck */
1183 opt = OPT_MULTI|OPT_EXECCGI;
1184 }
1185 else if (!strcasecmp(w, "None")) {
1186 opt = OPT_NONE;
1187 }
1188 else if (!strcasecmp(w, "All")) {
1189 opt = OPT_ALL;
1190 }
1191 else {
1192 return ap_pstrcat(cmd->pool, "Illegal option ", w, NULL);
1193 }
1194
1195 /* we ensure the invariant (d->opts_add & d->opts_remove) == 0 */
1196 if (action == '-') {
1197 d->opts_remove |= opt;
1198 d->opts_add &= ~opt;
1199 d->opts &= ~opt;
1200 }
1201 else if (action == '+') {
1202 d->opts_add |= opt;
1203 d->opts_remove &= ~opt;
1204 d->opts |= opt;
1205 }
1206 else {
1207 d->opts |= opt;
1208 }
1209 }
1210
1211 return NULL;
1212 }
1213
satisfy(cmd_parms * cmd,core_dir_config * c,char * arg)1214 static const char *satisfy(cmd_parms *cmd, core_dir_config *c, char *arg)
1215 {
1216 if (!strcasecmp(arg, "all")) {
1217 c->satisfy = SATISFY_ALL;
1218 }
1219 else if (!strcasecmp(arg, "any")) {
1220 c->satisfy = SATISFY_ANY;
1221 }
1222 else {
1223 return "Satisfy either 'any' or 'all'.";
1224 }
1225 return NULL;
1226 }
1227
require(cmd_parms * cmd,core_dir_config * c,char * arg)1228 static const char *require(cmd_parms *cmd, core_dir_config *c, char *arg)
1229 {
1230 require_line *r;
1231
1232 if (!c->ap_requires) {
1233 c->ap_requires = ap_make_array(cmd->pool, 2, sizeof(require_line));
1234 }
1235 r = (require_line *)ap_push_array(c->ap_requires);
1236 r->requirement = ap_pstrdup(cmd->pool, arg);
1237 r->method_mask = cmd->limited;
1238 return NULL;
1239 }
1240
ap_limit_section(cmd_parms * cmd,void * dummy,const char * arg)1241 CORE_EXPORT_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, void *dummy,
1242 const char *arg)
1243 {
1244 const char *limited_methods = ap_getword(cmd->pool, &arg, '>');
1245 void *tog = cmd->cmd->cmd_data;
1246 int limited = 0;
1247
1248 const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1249 if (err != NULL) {
1250 return err;
1251 }
1252
1253 /* XXX: NB: Currently, we have no way of checking
1254 * whether <Limit> or <LimitExcept> sections are closed properly.
1255 * (If we would add a srm_command_loop() here we might...)
1256 */
1257
1258 while (limited_methods[0]) {
1259 char *method = ap_getword_conf(cmd->pool, &limited_methods);
1260 int methnum = ap_method_number_of(method);
1261
1262 if (methnum == M_TRACE && !tog) {
1263 return "TRACE cannot be controlled by <Limit>";
1264 }
1265 else if (methnum == M_INVALID) {
1266 return ap_pstrcat(cmd->pool, "unknown method \"", method,
1267 "\" in <Limit", tog ? "Except>" : ">", NULL);
1268 }
1269 else {
1270 limited |= (1 << methnum);
1271 }
1272 }
1273
1274 /* Killing two features with one function,
1275 * if (tog == NULL) <Limit>, else <LimitExcept>
1276 */
1277 cmd->limited = tog ? ~limited : limited;
1278 return NULL;
1279 }
1280
endlimit_section(cmd_parms * cmd,void * dummy,void * dummy2)1281 static const char *endlimit_section(cmd_parms *cmd, void *dummy, void *dummy2)
1282 {
1283 void *tog = cmd->cmd->cmd_data;
1284
1285 if (cmd->limited == -1) {
1286 return tog ? "</LimitExcept> unexpected" : "</Limit> unexpected";
1287 }
1288
1289 cmd->limited = -1;
1290 return NULL;
1291 }
1292
1293 /*
1294 * When a section is not closed properly when end-of-file is reached,
1295 * then an error message should be printed:
1296 */
missing_endsection(cmd_parms * cmd,int nest)1297 static const char *missing_endsection(cmd_parms *cmd, int nest)
1298 {
1299 if (nest < 2) {
1300 return ap_psprintf(cmd->pool, "Missing %s directive at end-of-file",
1301 cmd->end_token);
1302 }
1303 return ap_psprintf(cmd->pool, "%d missing %s directives at end-of-file",
1304 nest, cmd->end_token);
1305 }
1306
1307 /* We use this in <DirectoryMatch> and <FilesMatch>, to ensure that
1308 * people don't get bitten by wrong-cased regex matches
1309 */
1310
1311 #define USE_ICASE 0
1312
end_nested_section(cmd_parms * cmd,void * dummy)1313 static const char *end_nested_section(cmd_parms *cmd, void *dummy)
1314 {
1315 if (cmd->end_token == NULL) {
1316 return ap_pstrcat(cmd->pool, cmd->cmd->name,
1317 " without matching <", cmd->cmd->name + 2,
1318 " section", NULL);
1319 }
1320 /*
1321 * This '!=' may look weird on a string comparison, but it's correct --
1322 * it's been set up so that checking for two pointers to the same datum
1323 * is valid here. And faster.
1324 */
1325 if (cmd->cmd->name != cmd->end_token) {
1326 return ap_pstrcat(cmd->pool, "Expected ", cmd->end_token, " but saw ",
1327 cmd->cmd->name, NULL);
1328 }
1329 return cmd->end_token;
1330 }
1331
1332 /*
1333 * Report a missing-'>' syntax error.
1334 */
unclosed_directive(cmd_parms * cmd)1335 static char *unclosed_directive(cmd_parms *cmd)
1336 {
1337 return ap_pstrcat(cmd->pool, cmd->cmd->name,
1338 "> directive missing closing '>'", NULL);
1339 }
1340
dirsection(cmd_parms * cmd,void * dummy,const char * arg)1341 static const char *dirsection(cmd_parms *cmd, void *dummy, const char *arg)
1342 {
1343 const char *errmsg;
1344 char *endp = strrchr(arg, '>');
1345 int old_overrides = cmd->override;
1346 char *old_path = cmd->path;
1347 core_dir_config *conf;
1348 void *new_dir_conf = ap_create_per_dir_config(cmd->pool);
1349 regex_t *r = NULL;
1350 const char *old_end_token;
1351 const command_rec *thiscmd = cmd->cmd;
1352
1353 const char *err = ap_check_cmd_context(cmd,
1354 NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1355 if (err != NULL) {
1356 return err;
1357 }
1358
1359 if (endp == NULL) {
1360 return unclosed_directive(cmd);
1361 }
1362
1363 *endp = '\0';
1364
1365 cmd->path = ap_getword_conf(cmd->pool, &arg);
1366 ap_server_strip_chroot(cmd->path, 1);
1367 cmd->override = OR_ALL|ACCESS_CONF;
1368
1369 if (thiscmd->cmd_data) { /* <DirectoryMatch> */
1370 r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1371 }
1372 else if (!strcmp(cmd->path, "~")) {
1373 cmd->path = ap_getword_conf(cmd->pool, &arg);
1374 ap_server_strip_chroot(cmd->path, 1);
1375 r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1376 }
1377 else {
1378 /* Ensure that the pathname is canonical */
1379 cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path);
1380 }
1381
1382 old_end_token = cmd->end_token;
1383 cmd->end_token = thiscmd->cmd_data ? end_directorymatch_section : end_directory_section;
1384 errmsg = ap_srm_command_loop(cmd, new_dir_conf);
1385 if (errmsg == NULL) {
1386 errmsg = missing_endsection(cmd, 1);
1387 }
1388 cmd->end_token = old_end_token;
1389 if (errmsg != (thiscmd->cmd_data
1390 ? end_directorymatch_section
1391 : end_directory_section)) {
1392 return errmsg;
1393 }
1394
1395 conf = (core_dir_config *)ap_get_module_config(new_dir_conf, &core_module);
1396 conf->r = r;
1397
1398 ap_add_per_dir_conf(cmd->server, new_dir_conf);
1399
1400 if (*arg != '\0') {
1401 return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1402 "> arguments not (yet) supported.", NULL);
1403 }
1404
1405 cmd->path = old_path;
1406 cmd->override = old_overrides;
1407
1408 return NULL;
1409 }
1410
urlsection(cmd_parms * cmd,void * dummy,const char * arg)1411 static const char *urlsection(cmd_parms *cmd, void *dummy, const char *arg)
1412 {
1413 const char *errmsg;
1414 char *endp = strrchr(arg, '>');
1415 int old_overrides = cmd->override;
1416 char *old_path = cmd->path;
1417 core_dir_config *conf;
1418 regex_t *r = NULL;
1419 const char *old_end_token;
1420 const command_rec *thiscmd = cmd->cmd;
1421
1422 void *new_url_conf = ap_create_per_dir_config(cmd->pool);
1423
1424 const char *err = ap_check_cmd_context(cmd,
1425 NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1426 if (err != NULL) {
1427 return err;
1428 }
1429
1430 if (endp == NULL) {
1431 return unclosed_directive(cmd);
1432 }
1433
1434 *endp = '\0';
1435
1436 cmd->path = ap_getword_conf(cmd->pool, &arg);
1437 ap_server_strip_chroot(cmd->path, 0);
1438 cmd->override = OR_ALL|ACCESS_CONF;
1439
1440 if (thiscmd->cmd_data) { /* <LocationMatch> */
1441 r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
1442 }
1443 else if (!strcmp(cmd->path, "~")) {
1444 cmd->path = ap_getword_conf(cmd->pool, &arg);
1445 ap_server_strip_chroot(cmd->path, 0);
1446 r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
1447 }
1448
1449 old_end_token = cmd->end_token;
1450 cmd->end_token = thiscmd->cmd_data ? end_locationmatch_section
1451 : end_location_section;
1452 errmsg = ap_srm_command_loop(cmd, new_url_conf);
1453 if (errmsg == NULL) {
1454 errmsg = missing_endsection(cmd, 1);
1455 }
1456 cmd->end_token = old_end_token;
1457 if (errmsg != (thiscmd->cmd_data
1458 ? end_locationmatch_section
1459 : end_location_section)) {
1460 return errmsg;
1461 }
1462
1463 conf = (core_dir_config *)ap_get_module_config(new_url_conf, &core_module);
1464 conf->d = ap_pstrdup(cmd->pool, cmd->path); /* No mangling, please */
1465 conf->d_is_fnmatch = ap_is_fnmatch(conf->d) != 0;
1466 conf->r = r;
1467
1468 ap_add_per_url_conf(cmd->server, new_url_conf);
1469
1470 if (*arg != '\0') {
1471 return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1472 "> arguments not (yet) supported.", NULL);
1473 }
1474
1475 cmd->path = old_path;
1476 cmd->override = old_overrides;
1477
1478 return NULL;
1479 }
1480
filesection(cmd_parms * cmd,core_dir_config * c,const char * arg)1481 static const char *filesection(cmd_parms *cmd, core_dir_config *c,
1482 const char *arg)
1483 {
1484 const char *errmsg;
1485 char *endp = strrchr(arg, '>');
1486 int old_overrides = cmd->override;
1487 char *old_path = cmd->path;
1488 core_dir_config *conf;
1489 regex_t *r = NULL;
1490 const char *old_end_token;
1491 const command_rec *thiscmd = cmd->cmd;
1492
1493 void *new_file_conf = ap_create_per_dir_config(cmd->pool);
1494
1495 const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_LOCATION);
1496 if (err != NULL) {
1497 return err;
1498 }
1499
1500 if (endp == NULL) {
1501 return unclosed_directive(cmd);
1502 }
1503
1504 *endp = '\0';
1505
1506 cmd->path = ap_getword_conf(cmd->pool, &arg);
1507 ap_server_strip_chroot(cmd->path, 1);
1508 /* Only if not an .htaccess file */
1509 if (!old_path) {
1510 cmd->override = OR_ALL|ACCESS_CONF;
1511 }
1512
1513 if (thiscmd->cmd_data) { /* <FilesMatch> */
1514 r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1515 }
1516 else if (!strcmp(cmd->path, "~")) {
1517 cmd->path = ap_getword_conf(cmd->pool, &arg);
1518 ap_server_strip_chroot(cmd->path, 1);
1519 r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1520 }
1521 else {
1522 /* Ensure that the pathname is canonical */
1523 cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path);
1524 }
1525
1526 old_end_token = cmd->end_token;
1527 cmd->end_token = thiscmd->cmd_data ? end_filesmatch_section : end_files_section;
1528 errmsg = ap_srm_command_loop(cmd, new_file_conf);
1529 if (errmsg == NULL) {
1530 errmsg = missing_endsection(cmd, 1);
1531 }
1532 cmd->end_token = old_end_token;
1533 if (errmsg != (thiscmd->cmd_data
1534 ? end_filesmatch_section
1535 : end_files_section)) {
1536 return errmsg;
1537 }
1538
1539 conf = (core_dir_config *)ap_get_module_config(new_file_conf,
1540 &core_module);
1541 conf->d = cmd->path;
1542 conf->d_is_fnmatch = ap_is_fnmatch(conf->d) != 0;
1543 conf->r = r;
1544
1545 ap_add_file_conf(c, new_file_conf);
1546
1547 if (*arg != '\0') {
1548 return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1549 "> arguments not (yet) supported.", NULL);
1550 }
1551
1552 cmd->path = old_path;
1553 cmd->override = old_overrides;
1554
1555 return NULL;
1556 }
1557
1558 /* XXX: NB: Currently, we have no way of checking
1559 * whether <IfModule> sections are closed properly.
1560 * Extra (redundant, unpaired) </IfModule> directives are
1561 * simply silently ignored.
1562 */
end_ifmod(cmd_parms * cmd,void * dummy)1563 static const char *end_ifmod(cmd_parms *cmd, void *dummy)
1564 {
1565 return NULL;
1566 }
1567
start_ifmod(cmd_parms * cmd,void * dummy,char * arg)1568 static const char *start_ifmod(cmd_parms *cmd, void *dummy, char *arg)
1569 {
1570 char *endp = strrchr(arg, '>');
1571 char l[MAX_STRING_LEN];
1572 int not = (arg[0] == '!');
1573 module *found;
1574 int nest = 1;
1575
1576 if (endp == NULL) {
1577 return unclosed_directive(cmd);
1578 }
1579
1580 *endp = '\0';
1581
1582 if (not) {
1583 arg++;
1584 }
1585
1586 found = ap_find_linked_module(arg);
1587
1588 if ((!not && found) || (not && !found)) {
1589 return NULL;
1590 }
1591
1592 while (nest && !(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) {
1593 if (!strncasecmp(l, "<IfModule", 9)) {
1594 nest++;
1595 }
1596 if (!strcasecmp(l, "</IfModule>")) {
1597 nest--;
1598 }
1599 }
1600
1601 if (nest) {
1602 cmd->end_token = end_ifmodule_section;
1603 return missing_endsection(cmd, nest);
1604 }
1605 return NULL;
1606 }
1607
ap_exists_config_define(char * name)1608 API_EXPORT(int) ap_exists_config_define(char *name)
1609 {
1610 char **defines;
1611 int i;
1612
1613 defines = (char **)ap_server_config_defines->elts;
1614 for (i = 0; i < ap_server_config_defines->nelts; i++) {
1615 if (strcmp(defines[i], name) == 0) {
1616 return 1;
1617 }
1618 }
1619 return 0;
1620 }
1621
end_ifdefine(cmd_parms * cmd,void * dummy)1622 static const char *end_ifdefine(cmd_parms *cmd, void *dummy)
1623 {
1624 return NULL;
1625 }
1626
start_ifdefine(cmd_parms * cmd,void * dummy,char * arg)1627 static const char *start_ifdefine(cmd_parms *cmd, void *dummy, char *arg)
1628 {
1629 char *endp;
1630 char l[MAX_STRING_LEN];
1631 int defined;
1632 int not = 0;
1633 int nest = 1;
1634
1635 endp = strrchr(arg, '>');
1636 if (endp == NULL) {
1637 return unclosed_directive(cmd);
1638 }
1639
1640 *endp = '\0';
1641
1642 if (arg[0] == '!') {
1643 not = 1;
1644 arg++;
1645 }
1646
1647 defined = ap_exists_config_define(arg);
1648
1649 if ((!not && defined) || (not && !defined)) {
1650 return NULL;
1651 }
1652
1653 while (nest && !(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) {
1654 if (!strncasecmp(l, "<IfDefine", 9)) {
1655 nest++;
1656 }
1657 if (!strcasecmp(l, "</IfDefine>")) {
1658 nest--;
1659 }
1660 }
1661 if (nest) {
1662 cmd->end_token = end_ifdefine_section;
1663 return missing_endsection(cmd, nest);
1664 }
1665 return NULL;
1666 }
1667
1668 /* httpd.conf commands... beginning with the <VirtualHost> business */
1669
virtualhost_section(cmd_parms * cmd,void * dummy,char * arg)1670 static const char *virtualhost_section(cmd_parms *cmd, void *dummy, char *arg)
1671 {
1672 server_rec *main_server = cmd->server, *s;
1673 const char *errmsg;
1674 char *endp = strrchr(arg, '>');
1675 pool *p = cmd->pool, *ptemp = cmd->temp_pool;
1676 const char *old_end_token;
1677
1678 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1679 if (err != NULL) {
1680 return err;
1681 }
1682
1683 if (endp == NULL) {
1684 return unclosed_directive(cmd);
1685 }
1686
1687 *endp = '\0';
1688
1689 /* FIXME: There's another feature waiting to happen here -- since you
1690 can now put multiple addresses/names on a single <VirtualHost>
1691 you might want to use it to group common definitions and then
1692 define other "subhosts" with their individual differences. But
1693 personally I'd rather just do it with a macro preprocessor. -djg */
1694 if (main_server->is_virtual) {
1695 return "<VirtualHost> doesn't nest!";
1696 }
1697
1698 errmsg = ap_init_virtual_host(p, arg, main_server, &s);
1699 if (errmsg) {
1700 return errmsg;
1701 }
1702
1703 s->next = main_server->next;
1704 main_server->next = s;
1705
1706 s->defn_name = cmd->config_file->name;
1707 s->defn_line_number = cmd->config_file->line_number;
1708
1709 old_end_token = cmd->end_token;
1710 cmd->end_token = end_virtualhost_section;
1711 cmd->server = s;
1712 errmsg = ap_srm_command_loop(cmd, s->lookup_defaults);
1713 cmd->server = main_server;
1714 if (errmsg == NULL) {
1715 errmsg = missing_endsection(cmd, 1);
1716 }
1717 cmd->end_token = old_end_token;
1718
1719 if (s->srm_confname) {
1720 ap_process_resource_config(s, s->srm_confname, p, ptemp);
1721 }
1722
1723 if (s->access_confname) {
1724 ap_process_resource_config(s, s->access_confname, p, ptemp);
1725 }
1726
1727 if (errmsg == end_virtualhost_section) {
1728 return NULL;
1729 }
1730 return errmsg;
1731 }
1732
set_server_alias(cmd_parms * cmd,void * dummy,const char * arg)1733 static const char *set_server_alias(cmd_parms *cmd, void *dummy,
1734 const char *arg)
1735 {
1736 if (!cmd->server->names) {
1737 return "ServerAlias only used in <VirtualHost>";
1738 }
1739 while (*arg) {
1740 char **item, *name = ap_getword_conf(cmd->pool, &arg);
1741 if (ap_is_matchexp(name)) {
1742 item = (char **)ap_push_array(cmd->server->wild_names);
1743 }
1744 else {
1745 item = (char **)ap_push_array(cmd->server->names);
1746 }
1747 *item = name;
1748 }
1749 return NULL;
1750 }
1751
add_module_command(cmd_parms * cmd,void * dummy,char * arg)1752 static const char *add_module_command(cmd_parms *cmd, void *dummy, char *arg)
1753 {
1754 module *modp;
1755 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1756 if (err != NULL) {
1757 return err;
1758 }
1759
1760 for (modp = top_module; modp; modp = modp->next) {
1761 if (modp->name != NULL && strcmp(modp->name, arg) == 0) {
1762 ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, cmd->server,
1763 "module %s is already added, skipping", arg);
1764 return NULL;
1765 }
1766 }
1767
1768 if (!ap_add_named_module(arg)) {
1769 return ap_pstrcat(cmd->pool, "Cannot add module via name '", arg,
1770 "': not in list of loaded modules", NULL);
1771 }
1772 return NULL;
1773 }
1774
clear_module_list_command(cmd_parms * cmd,void * dummy)1775 static const char *clear_module_list_command(cmd_parms *cmd, void *dummy)
1776 {
1777 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1778 if (err != NULL) {
1779 return err;
1780 }
1781
1782 ap_clear_module_list();
1783 return NULL;
1784 }
1785
set_server_string_slot(cmd_parms * cmd,void * dummy,char * arg)1786 static const char *set_server_string_slot(cmd_parms *cmd, void *dummy,
1787 char *arg)
1788 {
1789 /* This one's pretty generic... */
1790
1791 int offset = (int)(long)cmd->info;
1792 char *struct_ptr = (char *)cmd->server;
1793
1794 const char *err = ap_check_cmd_context(cmd,
1795 NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1796 if (err != NULL) {
1797 return err;
1798 }
1799
1800 *(char **)(struct_ptr + offset) = arg;
1801 return NULL;
1802 }
1803
server_type(cmd_parms * cmd,void * dummy,char * arg)1804 static const char *server_type(cmd_parms *cmd, void *dummy, char *arg)
1805 {
1806 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1807 if (err != NULL) {
1808 return err;
1809 }
1810
1811 if (!strcasecmp(arg, "inetd")) {
1812 ap_standalone = 0;
1813 }
1814 else if (!strcasecmp(arg, "standalone")) {
1815 ap_standalone = 1;
1816 }
1817 else {
1818 return "ServerType must be either 'inetd' or 'standalone'";
1819 }
1820
1821 return NULL;
1822 }
1823
server_port(cmd_parms * cmd,void * dummy,char * arg)1824 static const char *server_port(cmd_parms *cmd, void *dummy, char *arg)
1825 {
1826 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1827 int port;
1828
1829 if (err != NULL) {
1830 return err;
1831 }
1832 port = atoi(arg);
1833 if (port <= 0 || port >= 65536) { /* 65536 == 1<<16 */
1834 return ap_pstrcat(cmd->temp_pool, "The port number \"", arg,
1835 "\" is outside the appropriate range "
1836 "(i.e., 1..65535).", NULL);
1837 }
1838 cmd->server->port = port;
1839 return NULL;
1840 }
1841
set_signature_flag(cmd_parms * cmd,core_dir_config * d,char * arg)1842 static const char *set_signature_flag(cmd_parms *cmd, core_dir_config *d,
1843 char *arg)
1844 {
1845 const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1846 if (err != NULL) {
1847 return err;
1848 }
1849
1850 if (strcasecmp(arg, "On") == 0) {
1851 d->server_signature = srv_sig_on;
1852 }
1853 else if (strcasecmp(arg, "Off") == 0) {
1854 d->server_signature = srv_sig_off;
1855 }
1856 else if (strcasecmp(arg, "EMail") == 0) {
1857 d->server_signature = srv_sig_withmail;
1858 }
1859 else {
1860 return "ServerSignature: use one of: off | on | email";
1861 }
1862 return NULL;
1863 }
1864
set_send_buffer_size(cmd_parms * cmd,void * dummy,char * arg)1865 static const char *set_send_buffer_size(cmd_parms *cmd, void *dummy, char *arg)
1866 {
1867 int s = atoi(arg);
1868 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1869 if (err != NULL) {
1870 return err;
1871 }
1872
1873 if (s < 512 && s != 0) {
1874 return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
1875 }
1876 cmd->server->send_buffer_size = s;
1877 return NULL;
1878 }
1879
set_user(cmd_parms * cmd,void * dummy,char * arg)1880 static const char *set_user(cmd_parms *cmd, void *dummy, char *arg)
1881 {
1882 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1883 if (err != NULL) {
1884 return err;
1885 }
1886
1887 /*
1888 * This is, again, tricky. on restarts, we cannot use uname2id.
1889 * keep the old settings for the main server.
1890 * barf out on user directives in <VirtualHost> sections.
1891 */
1892
1893 if (!cmd->server->is_virtual) {
1894 if (!ap_server_is_chrooted()) {
1895 ap_user_name = arg;
1896 ap_user_id = ap_uname2id(arg);
1897 }
1898 cmd->server->server_uid = ap_user_id;
1899 }
1900 else {
1901 if (ap_suexec_enabled) {
1902 if (ap_server_is_chrooted()) {
1903 fprintf(stderr, "cannot look up uids once chrooted. Thus, User "
1904 "directives inside <VirtualHost> and restarts aren't "
1905 "possible together. Please stop httpd and start a new "
1906 "one\n");
1907 exit(1);
1908 } else
1909 cmd->server->server_uid = ap_uname2id(arg);
1910 }
1911 else {
1912 cmd->server->server_uid = ap_user_id;
1913 fprintf(stderr,
1914 "Warning: User directive in <VirtualHost> "
1915 "requires SUEXEC wrapper.\n");
1916 }
1917 }
1918 #if !defined (BIG_SECURITY_HOLE)
1919 if (cmd->server->server_uid == 0) {
1920 fprintf(stderr,
1921 "Error:\tApache has not been designed to serve pages while\n"
1922 "\trunning as root. There are known race conditions that\n"
1923 "\twill allow any local user to read any file on the system.\n"
1924 "\tIf you still desire to serve pages as root then\n"
1925 "\tadd -DBIG_SECURITY_HOLE to the EXTRA_CFLAGS line in your\n"
1926 "\tsrc/Configuration file and rebuild the server. It is\n"
1927 "\tstrongly suggested that you instead modify the User\n"
1928 "\tdirective in your httpd.conf file to list a non-root\n"
1929 "\tuser.\n");
1930 exit (1);
1931 }
1932 #endif
1933
1934 return NULL;
1935 }
1936
set_group(cmd_parms * cmd,void * dummy,char * arg)1937 static const char *set_group(cmd_parms *cmd, void *dummy, char *arg)
1938 {
1939 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1940 if (err != NULL) {
1941 return err;
1942 }
1943
1944 if (!cmd->server->is_virtual) {
1945 if (!ap_server_is_chrooted()) {
1946 ap_group_id = ap_gname2id(arg);
1947 }
1948 cmd->server->server_gid = ap_group_id;
1949 }
1950 else {
1951 if (ap_suexec_enabled) {
1952 if (ap_server_is_chrooted()) {
1953 fprintf(stderr, "cannot look up gids once chrooted. Thus, Group"
1954 " directives inside <VirtualHost> and restarts aren't "
1955 "possible together. Please stop httpd and start a new "
1956 "one\n");
1957 exit(1);
1958 } else
1959 cmd->server->server_gid = ap_gname2id(arg);
1960 }
1961 else {
1962 cmd->server->server_gid = ap_group_id;
1963 fprintf(stderr,
1964 "Warning: Group directive in <VirtualHost> requires "
1965 "SUEXEC wrapper.\n");
1966 }
1967 }
1968
1969 return NULL;
1970 }
1971
set_server_root(cmd_parms * cmd,void * dummy,char * arg)1972 static const char *set_server_root(cmd_parms *cmd, void *dummy, char *arg)
1973 {
1974 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1975
1976 if (err != NULL) {
1977 return err;
1978 }
1979
1980 arg = ap_os_canonical_filename(cmd->pool, arg);
1981
1982 /*
1983 * This is a bit tricky. On startup we are not chrooted here.
1984 * On restarts (graceful or not) we are (unless we're in unsecure mode).
1985 * if we would strip off the chroot prefix, nothing (not even "/")
1986 * would last.
1987 * it's pointless to test wether ServerRoot is a directory if we are
1988 * already chrooted into that.
1989 * Of course it's impossible to change ServerRoot without a full restart.
1990 * should we abort with an error if ap_server_root != arg?
1991 */
1992
1993 if (!ap_server_is_chrooted()) {
1994 if (!ap_is_directory(arg)) {
1995 return "ServerRoot must be a valid directory";
1996 }
1997 /* ServerRoot is never '/' terminated */
1998 while (strlen(ap_server_root) > 1 && ap_server_root[strlen(ap_server_root)-1] == '/')
1999 ap_server_root[strlen(ap_server_root)-1] = '\0';
2000 ap_cpystrn(ap_server_root, arg, sizeof(ap_server_root));
2001 }
2002 return NULL;
2003 }
2004
set_timeout(cmd_parms * cmd,void * dummy,char * arg)2005 static const char *set_timeout(cmd_parms *cmd, void *dummy, char *arg)
2006 {
2007 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2008 if (err != NULL) {
2009 return err;
2010 }
2011
2012 cmd->server->timeout = atoi(arg);
2013 return NULL;
2014 }
2015
set_keep_alive_timeout(cmd_parms * cmd,void * dummy,char * arg)2016 static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy,
2017 char *arg)
2018 {
2019 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2020 if (err != NULL) {
2021 return err;
2022 }
2023
2024 cmd->server->keep_alive_timeout = atoi(arg);
2025 return NULL;
2026 }
2027
set_keep_alive(cmd_parms * cmd,void * dummy,char * arg)2028 static const char *set_keep_alive(cmd_parms *cmd, void *dummy, char *arg)
2029 {
2030 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2031 if (err != NULL) {
2032 return err;
2033 }
2034
2035 /* We've changed it to On/Off, but used to use numbers
2036 * so we accept anything but "Off" or "0" as "On"
2037 */
2038 if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) {
2039 cmd->server->keep_alive = 0;
2040 }
2041 else {
2042 cmd->server->keep_alive = 1;
2043 }
2044 return NULL;
2045 }
2046
set_keep_alive_max(cmd_parms * cmd,void * dummy,char * arg)2047 static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy, char *arg)
2048 {
2049 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2050 if (err != NULL) {
2051 return err;
2052 }
2053
2054 cmd->server->keep_alive_max = atoi(arg);
2055 return NULL;
2056 }
2057
set_pidfile(cmd_parms * cmd,void * dummy,char * arg)2058 static const char *set_pidfile(cmd_parms *cmd, void *dummy, char *arg)
2059 {
2060 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2061 if (err != NULL) {
2062 return err;
2063 }
2064
2065 if (cmd->server->is_virtual) {
2066 return "PidFile directive not allowed in <VirtualHost>";
2067 }
2068 ap_pid_fname = arg;
2069 return NULL;
2070 }
2071
set_scoreboard(cmd_parms * cmd,void * dummy,char * arg)2072 static const char *set_scoreboard(cmd_parms *cmd, void *dummy, char *arg)
2073 {
2074 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2075 if (err != NULL) {
2076 return err;
2077 }
2078
2079 ap_scoreboard_fname = arg;
2080 return NULL;
2081 }
2082
set_lockfile(cmd_parms * cmd,void * dummy,char * arg)2083 static const char *set_lockfile(cmd_parms *cmd, void *dummy, char *arg)
2084 {
2085 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2086 if (err != NULL) {
2087 return err;
2088 }
2089
2090 ap_lock_fname = arg;
2091 return NULL;
2092 }
2093
set_idcheck(cmd_parms * cmd,core_dir_config * d,int arg)2094 static const char *set_idcheck(cmd_parms *cmd, core_dir_config *d, int arg)
2095 {
2096 const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2097 if (err != NULL) {
2098 return err;
2099 }
2100
2101 d->do_rfc1413 = arg != 0;
2102 return NULL;
2103 }
2104
set_hostname_lookups(cmd_parms * cmd,core_dir_config * d,char * arg)2105 static const char *set_hostname_lookups(cmd_parms *cmd, core_dir_config *d,
2106 char *arg)
2107 {
2108 const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2109 if (err != NULL) {
2110 return err;
2111 }
2112
2113 if (!strcasecmp(arg, "on")) {
2114 d->hostname_lookups = HOSTNAME_LOOKUP_ON;
2115 }
2116 else if (!strcasecmp(arg, "off")) {
2117 d->hostname_lookups = HOSTNAME_LOOKUP_OFF;
2118 }
2119 else if (!strcasecmp(arg, "double")) {
2120 d->hostname_lookups = HOSTNAME_LOOKUP_DOUBLE;
2121 }
2122 else {
2123 return "parameter must be 'on', 'off', or 'double'";
2124 }
2125 return NULL;
2126 }
2127
set_serverpath(cmd_parms * cmd,void * dummy,char * arg)2128 static const char *set_serverpath(cmd_parms *cmd, void *dummy, char *arg)
2129 {
2130 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2131 if (err != NULL) {
2132 return err;
2133 }
2134
2135 cmd->server->path = arg;
2136 cmd->server->pathlen = strlen(arg);
2137 return NULL;
2138 }
2139
set_content_md5(cmd_parms * cmd,core_dir_config * d,int arg)2140 static const char *set_content_md5(cmd_parms *cmd, core_dir_config *d, int arg)
2141 {
2142 const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2143 if (err != NULL) {
2144 return err;
2145 }
2146
2147 d->content_md5 = arg != 0;
2148 return NULL;
2149 }
2150
set_use_canonical_name(cmd_parms * cmd,core_dir_config * d,char * arg)2151 static const char *set_use_canonical_name(cmd_parms *cmd, core_dir_config *d,
2152 char *arg)
2153 {
2154 const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2155 if (err != NULL) {
2156 return err;
2157 }
2158
2159 if (strcasecmp(arg, "on") == 0) {
2160 d->use_canonical_name = USE_CANONICAL_NAME_ON;
2161 }
2162 else if (strcasecmp(arg, "off") == 0) {
2163 d->use_canonical_name = USE_CANONICAL_NAME_OFF;
2164 }
2165 else if (strcasecmp(arg, "dns") == 0) {
2166 d->use_canonical_name = USE_CANONICAL_NAME_DNS;
2167 }
2168 else {
2169 return "parameter must be 'on', 'off', or 'dns'";
2170 }
2171 return NULL;
2172 }
2173
set_daemons_to_start(cmd_parms * cmd,void * dummy,char * arg)2174 static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, char *arg)
2175 {
2176 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2177 if (err != NULL) {
2178 return err;
2179 }
2180
2181 ap_daemons_to_start = atoi(arg);
2182 return NULL;
2183 }
2184
set_min_free_servers(cmd_parms * cmd,void * dummy,char * arg)2185 static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, char *arg)
2186 {
2187 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2188 if (err != NULL) {
2189 return err;
2190 }
2191
2192 ap_daemons_min_free = atoi(arg);
2193 if (ap_daemons_min_free <= 0) {
2194 fprintf(stderr, "WARNING: detected MinSpareServers set to non-positive.\n");
2195 fprintf(stderr, "Resetting to 1 to avoid almost certain Apache failure.\n");
2196 fprintf(stderr, "Please read the documentation.\n");
2197 ap_daemons_min_free = 1;
2198 }
2199
2200 return NULL;
2201 }
2202
set_max_free_servers(cmd_parms * cmd,void * dummy,char * arg)2203 static const char *set_max_free_servers(cmd_parms *cmd, void *dummy, char *arg)
2204 {
2205 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2206 if (err != NULL) {
2207 return err;
2208 }
2209
2210 ap_daemons_max_free = atoi(arg);
2211 return NULL;
2212 }
2213
set_server_limit(cmd_parms * cmd,void * dummy,char * arg)2214 static const char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg)
2215 {
2216 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2217 if (err != NULL) {
2218 return err;
2219 }
2220
2221 ap_daemons_limit = atoi(arg);
2222 if (ap_daemons_limit > HARD_SERVER_LIMIT) {
2223 fprintf(stderr, "WARNING: MaxClients of %d exceeds compile time limit "
2224 "of %d servers,\n", ap_daemons_limit, HARD_SERVER_LIMIT);
2225 fprintf(stderr, " lowering MaxClients to %d. To increase, please "
2226 "see the\n", HARD_SERVER_LIMIT);
2227 fprintf(stderr, " HARD_SERVER_LIMIT define in src/include/httpd.h.\n");
2228 ap_daemons_limit = HARD_SERVER_LIMIT;
2229 }
2230 else if (ap_daemons_limit < 1) {
2231 fprintf(stderr, "WARNING: Require MaxClients > 0, setting to 1\n");
2232 ap_daemons_limit = 1;
2233 }
2234 return NULL;
2235 }
2236
set_child_rl_cpu(cmd_parms * cmd,void * dummy,char * arg)2237 static const char *set_child_rl_cpu(cmd_parms *cmd, void *dummy, char *arg)
2238 {
2239 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2240 if (err != NULL) {
2241 return err;
2242 }
2243
2244 ap_max_cpu_per_child = atoi(arg);
2245 return NULL;
2246 }
2247
set_child_rl_data(cmd_parms * cmd,void * dummy,char * arg)2248 static const char *set_child_rl_data(cmd_parms *cmd, void *dummy, char *arg)
2249 {
2250 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2251 if (err != NULL) {
2252 return err;
2253 }
2254
2255 ap_max_data_per_child = atoi(arg);
2256 return NULL;
2257 }
2258
set_child_rl_nofile(cmd_parms * cmd,void * dummy,char * arg)2259 static const char *set_child_rl_nofile(cmd_parms *cmd, void *dummy, char *arg)
2260 {
2261 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2262 if (err != NULL) {
2263 return err;
2264 }
2265
2266 ap_max_nofile_per_child = atoi(arg);
2267 return NULL;
2268 }
2269
set_child_rl_rss(cmd_parms * cmd,void * dummy,char * arg)2270 static const char *set_child_rl_rss(cmd_parms *cmd, void *dummy, char *arg)
2271 {
2272 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2273 if (err != NULL) {
2274 return err;
2275 }
2276
2277 ap_max_rss_per_child = atoi(arg);
2278 return NULL;
2279 }
2280
set_child_rl_stack(cmd_parms * cmd,void * dummy,char * arg)2281 static const char *set_child_rl_stack(cmd_parms *cmd, void *dummy, char *arg)
2282 {
2283 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2284 if (err != NULL) {
2285 return err;
2286 }
2287
2288 ap_max_stack_per_child = atoi(arg);
2289 return NULL;
2290 }
2291
2292 #ifdef RLIMIT_TIME
set_child_rl_time(cmd_parms * cmd,void * dummy,char * arg)2293 static const char *set_child_rl_time(cmd_parms *cmd, void *dummy, char *arg)
2294 {
2295 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2296 if (err != NULL) {
2297 return err;
2298 }
2299
2300 ap_max_time_per_child = atoi(arg);
2301 return NULL;
2302 }
2303 #endif
2304
set_max_requests(cmd_parms * cmd,void * dummy,char * arg)2305 static const char *set_max_requests(cmd_parms *cmd, void *dummy, char *arg)
2306 {
2307 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2308 if (err != NULL) {
2309 return err;
2310 }
2311
2312 ap_max_requests_per_child = atoi(arg);
2313 return NULL;
2314 }
2315
set_threads(cmd_parms * cmd,void * dummy,char * arg)2316 static const char *set_threads(cmd_parms *cmd, void *dummy, char *arg) {
2317 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2318 if (err != NULL) {
2319 return err;
2320 }
2321
2322 ap_threads_per_child = atoi(arg);
2323 if (ap_threads_per_child > HARD_SERVER_LIMIT) {
2324 fprintf(stderr, "WARNING: ThreadsPerChild of %d exceeds compile time limit "
2325 "of %d threads,\n", ap_threads_per_child, HARD_SERVER_LIMIT);
2326 fprintf(stderr, " lowering ThreadsPerChild to %d. To increase, please "
2327 "see the\n", HARD_SERVER_LIMIT);
2328 fprintf(stderr, " HARD_SERVER_LIMIT define in src/include/httpd.h.\n");
2329 ap_threads_per_child = HARD_SERVER_LIMIT;
2330 }
2331 else if (ap_threads_per_child < 1) {
2332 fprintf(stderr, "WARNING: Require ThreadsPerChild > 0, setting to 1\n");
2333 ap_threads_per_child = 1;
2334 }
2335
2336 return NULL;
2337 }
2338
set_excess_requests(cmd_parms * cmd,void * dummy,char * arg)2339 static const char *set_excess_requests(cmd_parms *cmd, void *dummy, char *arg)
2340 {
2341 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2342 if (err != NULL) {
2343 return err;
2344 }
2345
2346 ap_excess_requests_per_child = atoi(arg);
2347 return NULL;
2348 }
2349
2350
set_rlimit(cmd_parms * cmd,struct rlimit ** plimit,const char * arg,const char * arg2,int type)2351 static void set_rlimit(cmd_parms *cmd, struct rlimit **plimit, const char *arg,
2352 const char * arg2, int type)
2353 {
2354 char *str;
2355 struct rlimit *limit;
2356 /* If your platform doesn't define rlim_t then typedef it in ap_config.h */
2357 rlim_t cur = 0;
2358 rlim_t max = 0;
2359
2360 *plimit = (struct rlimit *)ap_pcalloc(cmd->pool, sizeof(**plimit));
2361 limit = *plimit;
2362 if ((getrlimit(type, limit)) != 0) {
2363 *plimit = NULL;
2364 ap_log_error(APLOG_MARK, APLOG_ERR, cmd->server,
2365 "%s: getrlimit failed", cmd->cmd->name);
2366 return;
2367 }
2368
2369 if ((str = ap_getword_conf(cmd->pool, &arg))) {
2370 if (!strcasecmp(str, "max")) {
2371 cur = limit->rlim_max;
2372 }
2373 else {
2374 cur = atol(str);
2375 }
2376 }
2377 else {
2378 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, cmd->server,
2379 "Invalid parameters for %s", cmd->cmd->name);
2380 return;
2381 }
2382
2383 if (arg2 && (str = ap_getword_conf(cmd->pool, &arg2))) {
2384 max = atol(str);
2385 }
2386
2387 /* if we aren't running as root, cannot increase max */
2388 if (geteuid()) {
2389 limit->rlim_cur = cur;
2390 if (max) {
2391 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, cmd->server,
2392 "Must be uid 0 to raise maximum %s", cmd->cmd->name);
2393 }
2394 }
2395 else {
2396 if (cur) {
2397 limit->rlim_cur = cur;
2398 }
2399 if (max) {
2400 limit->rlim_max = max;
2401 }
2402 }
2403 }
2404
set_limit_cpu(cmd_parms * cmd,core_dir_config * conf,char * arg,char * arg2)2405 static const char *set_limit_cpu(cmd_parms *cmd, core_dir_config *conf,
2406 char *arg, char *arg2)
2407 {
2408 set_rlimit(cmd, &conf->limit_cpu, arg, arg2, RLIMIT_CPU);
2409 return NULL;
2410 }
2411
2412 #ifdef RLIMIT_TIME
set_limit_time(cmd_parms * cmd,core_dir_config * conf,char * arg,char * arg2)2413 static const char *set_limit_time(cmd_parms *cmd, core_dir_config *conf,
2414 char *arg, char *arg2)
2415 {
2416 set_rlimit(cmd, &conf->limit_time, arg, arg2, RLIMIT_TIME);
2417 return NULL;
2418 }
2419 #endif
2420
set_limit_mem(cmd_parms * cmd,core_dir_config * conf,char * arg,char * arg2)2421 static const char *set_limit_mem(cmd_parms *cmd, core_dir_config *conf,
2422 char *arg, char * arg2)
2423 {
2424 set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_DATA);
2425 return NULL;
2426 }
2427
set_limit_nproc(cmd_parms * cmd,core_dir_config * conf,char * arg,char * arg2)2428 static const char *set_limit_nproc(cmd_parms *cmd, core_dir_config *conf,
2429 char *arg, char * arg2)
2430 {
2431 set_rlimit(cmd, &conf->limit_nproc, arg, arg2, RLIMIT_NPROC);
2432 return NULL;
2433 }
2434
set_limit_nofile(cmd_parms * cmd,core_dir_config * conf,char * arg,char * arg2)2435 static const char *set_limit_nofile(cmd_parms *cmd, core_dir_config *conf,
2436 char *arg, char * arg2)
2437 {
2438 set_rlimit(cmd, &conf->limit_nofile, arg, arg2, RLIMIT_NOFILE);
2439 return NULL;
2440 }
2441
set_bind_address(cmd_parms * cmd,void * dummy,char * arg)2442 static const char *set_bind_address(cmd_parms *cmd, void *dummy, char *arg)
2443 {
2444 struct sockaddr *sa;
2445 size_t sa_len;
2446 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2447 if (err != NULL) {
2448 return err;
2449 }
2450
2451 if (strcmp(arg, "*") == 0)
2452 arg = NULL;
2453
2454 sa = ap_get_virthost_addr(arg, NULL);
2455 #ifdef HAVE_SOCKADDR_LEN
2456 sa_len = sa->sa_len;
2457 #else
2458 sa_len = SA_LEN(sa);
2459 #endif
2460 memcpy(&ap_bind_address, &sa, sa_len);
2461 return NULL;
2462 }
2463
2464 /* Though the AcceptFilter functionality is not available across
2465 * all platforms - we still allow the config directive to appear
2466 * on all platforms and do intentionally not tie it to the compile
2467 * time flag SO_ACCEPTFILTER. This makes configuration files significantly
2468 * more portable; especially as an <IfModule http_core.c> or some
2469 * other construct is not possible.
2470 */
set_acceptfilter(cmd_parms * cmd,void * dummy,int flag)2471 static const char *set_acceptfilter(cmd_parms *cmd, void *dummy, int flag)
2472 {
2473 return NULL;
2474 }
2475
set_listener(cmd_parms * cmd,void * dummy,char * h,char * p)2476 static const char *set_listener(cmd_parms *cmd, void *dummy, char *h, char *p)
2477 {
2478 listen_rec *new;
2479 char *host, *port;
2480 struct addrinfo hints, *res;
2481 int error;
2482
2483 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2484 if (err != NULL) {
2485 return err;
2486 }
2487
2488 host = port = NULL;
2489 if (!p) {
2490 port = strrchr(h, ':');
2491 if (port != NULL) {
2492 if (port == h) {
2493 return "Missing IP address";
2494 }
2495 else if (port[1] == '\0') {
2496 return "Address must end in :<port-number>";
2497 }
2498 *(port++) = '\0';
2499 if (*h)
2500 host = h;
2501 } else {
2502 host = NULL;
2503 port = h;
2504 }
2505 } else {
2506 host = h;
2507 port = p;
2508 }
2509
2510 if (host && strcmp(host, "*") == 0)
2511 host = NULL;
2512
2513 new = ap_pcalloc(cmd->pool, sizeof(listen_rec));
2514
2515 memset(&hints, 0, sizeof(hints));
2516 hints.ai_family = host ? PF_UNSPEC : ap_default_family;
2517 hints.ai_flags = AI_PASSIVE;
2518 hints.ai_socktype = SOCK_STREAM;
2519 error = getaddrinfo(host, port, &hints, &res);
2520 if (error || !res) {
2521 fprintf(stderr, "could not resolve ");
2522 if (host)
2523 fprintf(stderr, "host \"%s\" ", host);
2524 if (port)
2525 fprintf(stderr, "port \"%s\" ", port);
2526 fprintf(stderr, "--- %s\n", gai_strerror(error));
2527 exit(1);
2528 }
2529 if (res->ai_next) {
2530 if (host)
2531 fprintf(stderr, "host \"%s\" ", host);
2532 if (port)
2533 fprintf(stderr, "port \"%s\" ", port);
2534 fprintf(stderr, "resolved to multiple addresses, ambiguous.\n");
2535 exit(1);
2536 }
2537
2538 memcpy(&new->local_addr, res->ai_addr, res->ai_addrlen);
2539
2540 new->fd = -1;
2541 new->used = 0;
2542 new->next = ap_listeners;
2543 ap_listeners = new;
2544 return NULL;
2545 }
2546
set_listenbacklog(cmd_parms * cmd,void * dummy,char * arg)2547 static const char *set_listenbacklog(cmd_parms *cmd, void *dummy, char *arg)
2548 {
2549 int b;
2550
2551 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2552 if (err != NULL) {
2553 return err;
2554 }
2555
2556 b = atoi(arg);
2557 if (b < 1) {
2558 return "ListenBacklog must be > 0";
2559 }
2560 ap_listenbacklog = b;
2561 return NULL;
2562 }
2563
set_coredumpdir(cmd_parms * cmd,void * dummy,char * arg)2564 static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, char *arg)
2565 {
2566 struct stat finfo;
2567 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2568 if (err != NULL) {
2569 return err;
2570 }
2571
2572 arg = ap_server_root_relative(cmd->pool, arg);
2573 if ((stat(arg, &finfo) == -1) || !S_ISDIR(finfo.st_mode)) {
2574 return ap_pstrcat(cmd->pool, "CoreDumpDirectory ", arg,
2575 " does not exist or is not a directory", NULL);
2576 }
2577 ap_cpystrn(ap_coredump_dir, arg, sizeof(ap_coredump_dir));
2578 return NULL;
2579 }
2580
include_config(cmd_parms * cmd,void * dummy,char * name)2581 static const char *include_config (cmd_parms *cmd, void *dummy, char *name)
2582 {
2583 name = ap_server_root_relative(cmd->pool, name);
2584
2585 ap_process_resource_config(cmd->server, name, cmd->pool, cmd->temp_pool);
2586
2587 return NULL;
2588 }
2589
set_loglevel(cmd_parms * cmd,void * dummy,const char * arg)2590 static const char *set_loglevel(cmd_parms *cmd, void *dummy, const char *arg)
2591 {
2592 char *str;
2593
2594 const char *err = ap_check_cmd_context(cmd,
2595 NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2596 if (err != NULL) {
2597 return err;
2598 }
2599
2600 if ((str = ap_getword_conf(cmd->pool, &arg))) {
2601 if (!strcasecmp(str, "emerg")) {
2602 cmd->server->loglevel = APLOG_EMERG;
2603 }
2604 else if (!strcasecmp(str, "alert")) {
2605 cmd->server->loglevel = APLOG_ALERT;
2606 }
2607 else if (!strcasecmp(str, "crit")) {
2608 cmd->server->loglevel = APLOG_CRIT;
2609 }
2610 else if (!strcasecmp(str, "error")) {
2611 cmd->server->loglevel = APLOG_ERR;
2612 }
2613 else if (!strcasecmp(str, "warn")) {
2614 cmd->server->loglevel = APLOG_WARNING;
2615 }
2616 else if (!strcasecmp(str, "notice")) {
2617 cmd->server->loglevel = APLOG_NOTICE;
2618 }
2619 else if (!strcasecmp(str, "info")) {
2620 cmd->server->loglevel = APLOG_INFO;
2621 }
2622 else if (!strcasecmp(str, "debug")) {
2623 cmd->server->loglevel = APLOG_DEBUG;
2624 }
2625 else {
2626 return "LogLevel requires level keyword: one of "
2627 "emerg/alert/crit/error/warn/notice/info/debug";
2628 }
2629 }
2630 else {
2631 return "LogLevel requires level keyword";
2632 }
2633
2634 return NULL;
2635 }
2636
ap_psignature(const char * prefix,request_rec * r)2637 API_EXPORT(const char *) ap_psignature(const char *prefix, request_rec *r)
2638 {
2639 char sport[20];
2640 core_dir_config *conf;
2641
2642 conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
2643 &core_module);
2644 if ((conf->server_signature == srv_sig_off)
2645 || (conf->server_signature == srv_sig_unset)) {
2646 return "";
2647 }
2648
2649 snprintf(sport, sizeof sport, "%u", (unsigned) ap_get_server_port(r));
2650
2651 if (conf->server_signature == srv_sig_withmail) {
2652 return ap_pstrcat(r->pool, prefix, "<address>" SERVER_BASEVERSION
2653 " Server at <a href=\"mailto:",
2654 r->server->server_admin, "\">",
2655 ap_escape_html(r->pool, ap_get_server_name(r)),
2656 "</a> Port ", sport,
2657 "</address>\n", NULL);
2658 }
2659 return ap_pstrcat(r->pool, prefix, "<address>" SERVER_BASEVERSION
2660 " Server at ",
2661 ap_escape_html(r->pool, ap_get_server_name(r)),
2662 " Port ", sport,
2663 "</address>\n", NULL);
2664 }
2665
2666 /*
2667 * Load an authorisation realm into our location configuration, applying the
2668 * usual rules that apply to realms.
2669 */
set_authname(cmd_parms * cmd,void * mconfig,char * word1)2670 static const char *set_authname(cmd_parms *cmd, void *mconfig, char *word1)
2671 {
2672 core_dir_config *aconfig = (core_dir_config *)mconfig;
2673
2674 aconfig->ap_auth_name = ap_escape_quotes(cmd->pool, word1);
2675 return NULL;
2676 }
2677
2678 /*
2679 * Load an authorisation nonce into our location configuration, and
2680 * force it to be in the 0-9/A-Z realm.
2681 */
set_authnonce(cmd_parms * cmd,void * mconfig,char * word1)2682 static const char *set_authnonce (cmd_parms *cmd, void *mconfig, char *word1)
2683 {
2684 core_dir_config *aconfig = (core_dir_config *)mconfig;
2685 size_t i;
2686
2687 aconfig->ap_auth_nonce = ap_escape_quotes(cmd->pool, word1);
2688
2689 if (strlen(aconfig->ap_auth_nonce) > 510)
2690 return "AuthDigestRealmSeed length limited to 510 chars for browser compatibility";
2691
2692 for(i=0;i<strlen(aconfig->ap_auth_nonce );i++)
2693 if (!ap_isalnum(aconfig->ap_auth_nonce [i]))
2694 return "AuthDigestRealmSeed limited to 0-9 and A-Z range for browser compatibility";
2695
2696 return NULL;
2697 }
2698
2699
set_protocol_req_check(cmd_parms * cmd,core_dir_config * d,int arg)2700 static const char *set_protocol_req_check(cmd_parms *cmd,
2701 core_dir_config *d, int arg)
2702 {
2703 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2704 if (err != NULL) {
2705 return err;
2706 }
2707
2708 ap_protocol_req_check = arg != 0;
2709 return NULL;
2710 }
2711
set_change_shmem_uid(cmd_parms * cmd,core_dir_config * d,int arg)2712 static const char *set_change_shmem_uid(cmd_parms *cmd,
2713 core_dir_config *d, int arg)
2714 {
2715 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2716 if (err != NULL) {
2717 return err;
2718 }
2719
2720 ap_change_shmem_uid = arg != 0;
2721 return NULL;
2722 }
2723
2724 /*
2725 * Handle a request to include the server's OS platform in the Server
2726 * response header field (the ServerTokens directive). Unfortunately
2727 * this requires a new global in order to communicate the setting back to
2728 * http_main so it can insert the information in the right place in the
2729 * string.
2730 */
set_serv_tokens(cmd_parms * cmd,void * dummy,char * arg)2731 static const char *set_serv_tokens(cmd_parms *cmd, void *dummy, char *arg)
2732 {
2733 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2734 if (err != NULL) {
2735 return err;
2736 }
2737
2738 if (!strcasecmp(arg, "OS")) {
2739 ap_server_tokens = SrvTk_OS;
2740 }
2741 else if (!strcasecmp(arg, "Min") || !strcasecmp(arg, "Minimal")) {
2742 ap_server_tokens = SrvTk_MIN;
2743 }
2744 else if (!strcasecmp(arg, "Full")) {
2745 ap_server_tokens = SrvTk_FULL;
2746 }
2747 else if (!strcasecmp(arg, "Prod") || !strcasecmp(arg, "ProductOnly")) {
2748 ap_server_tokens = SrvTk_PRODUCT_ONLY;
2749 }
2750 else {
2751 return ap_pstrcat(cmd->pool, "Unrecognised ServerTokens keyword: ",
2752 arg, NULL);
2753 }
2754 return NULL;
2755 }
2756
set_limit_req_line(cmd_parms * cmd,void * dummy,char * arg)2757 static const char *set_limit_req_line(cmd_parms *cmd, void *dummy, char *arg)
2758 {
2759 const char *err = ap_check_cmd_context(cmd,
2760 NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2761 int lim;
2762
2763 if (err != NULL) {
2764 return err;
2765 }
2766 lim = atoi(arg);
2767 if (lim < 0) {
2768 return ap_pstrcat(cmd->temp_pool, "LimitRequestLine \"", arg,
2769 "\" must be a non-negative integer", NULL);
2770 }
2771 if (lim > DEFAULT_LIMIT_REQUEST_LINE) {
2772 return ap_psprintf(cmd->temp_pool, "LimitRequestLine \"%s\" "
2773 "must not exceed the precompiled maximum of %d",
2774 arg, DEFAULT_LIMIT_REQUEST_LINE);
2775 }
2776 cmd->server->limit_req_line = lim;
2777 return NULL;
2778 }
2779
set_limit_req_fieldsize(cmd_parms * cmd,void * dummy,char * arg)2780 static const char *set_limit_req_fieldsize(cmd_parms *cmd, void *dummy,
2781 char *arg)
2782 {
2783 const char *err = ap_check_cmd_context(cmd,
2784 NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2785 int lim;
2786
2787 if (err != NULL) {
2788 return err;
2789 }
2790 lim = atoi(arg);
2791 if (lim < 0) {
2792 return ap_pstrcat(cmd->temp_pool, "LimitRequestFieldsize \"", arg,
2793 "\" must be a non-negative integer (0 = no limit)",
2794 NULL);
2795 }
2796 if (lim > DEFAULT_LIMIT_REQUEST_FIELDSIZE) {
2797 return ap_psprintf(cmd->temp_pool, "LimitRequestFieldsize \"%s\" "
2798 "must not exceed the precompiled maximum of %d",
2799 arg, DEFAULT_LIMIT_REQUEST_FIELDSIZE);
2800 }
2801 cmd->server->limit_req_fieldsize = lim;
2802 return NULL;
2803 }
2804
set_limit_req_fields(cmd_parms * cmd,void * dummy,char * arg)2805 static const char *set_limit_req_fields(cmd_parms *cmd, void *dummy, char *arg)
2806 {
2807 const char *err = ap_check_cmd_context(cmd,
2808 NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2809 int lim;
2810
2811 if (err != NULL) {
2812 return err;
2813 }
2814 lim = atoi(arg);
2815 if (lim < 0) {
2816 return ap_pstrcat(cmd->temp_pool, "LimitRequestFields \"", arg,
2817 "\" must be a non-negative integer (0 = no limit)",
2818 NULL);
2819 }
2820 cmd->server->limit_req_fields = lim;
2821 return NULL;
2822 }
2823
set_limit_req_body(cmd_parms * cmd,core_dir_config * conf,char * arg)2824 static const char *set_limit_req_body(cmd_parms *cmd, core_dir_config *conf,
2825 char *arg)
2826 {
2827 const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2828 if (err != NULL) {
2829 return err;
2830 }
2831
2832 /* WTF: If strtoul is not portable, then write a replacement.
2833 * Instead we have an idiotic define in httpd.h that prevents
2834 * it from being used even when it is available. Sheesh.
2835 */
2836 conf->limit_req_body = (unsigned long)ap_strtol(arg, (char **)NULL, 10);
2837 return NULL;
2838 }
2839
set_cgi_command_args(cmd_parms * cmd,void * mconfig,int arg)2840 static const char *set_cgi_command_args(cmd_parms *cmd,
2841 void *mconfig,
2842 int arg)
2843 {
2844 core_dir_config *cfg = (core_dir_config *)mconfig;
2845 cfg->cgi_command_args = arg ? AP_FLAG_ON : AP_FLAG_OFF;
2846 return NULL;
2847 }
2848
2849 /*
2850 * Note what data should be used when forming file ETag values.
2851 * It would be nicer to do this as an ITERATE, but then we couldn't
2852 * remember the +/- state properly.
2853 */
set_etag_bits(cmd_parms * cmd,void * mconfig,const char * args_p)2854 static const char *set_etag_bits(cmd_parms *cmd, void *mconfig,
2855 const char *args_p)
2856 {
2857 core_dir_config *cfg;
2858 etag_components_t bit;
2859 char action;
2860 char *token;
2861 const char *args;
2862 int valid;
2863 int first;
2864 int explicit;
2865
2866 cfg = (core_dir_config *) mconfig;
2867
2868 args = args_p;
2869 first = 1;
2870 explicit = 0;
2871 while (args[0] != '\0') {
2872 action = '*';
2873 bit = ETAG_UNSET;
2874 valid = 1;
2875 token = ap_getword_conf(cmd->pool, &args);
2876 if ((*token == '+') || (*token == '-')) {
2877 action = *token;
2878 token++;
2879 }
2880 else {
2881 /*
2882 * The occurrence of an absolute setting wipes
2883 * out any previous relative ones. The first such
2884 * occurrence forgets any inherited ones, too.
2885 */
2886 if (first) {
2887 cfg->etag_bits = ETAG_UNSET;
2888 cfg->etag_add = ETAG_UNSET;
2889 cfg->etag_remove = ETAG_UNSET;
2890 first = 0;
2891 }
2892 }
2893
2894 if (strcasecmp(token, "None") == 0) {
2895 if (action != '*') {
2896 valid = 0;
2897 }
2898 else {
2899 cfg->etag_bits = bit = ETAG_NONE;
2900 explicit = 1;
2901 }
2902 }
2903 else if (strcasecmp(token, "All") == 0) {
2904 if (action != '*') {
2905 valid = 0;
2906 }
2907 else {
2908 explicit = 1;
2909 cfg->etag_bits = bit = ETAG_ALL;
2910 }
2911 }
2912 else if (strcasecmp(token, "Size") == 0) {
2913 bit = ETAG_SIZE;
2914 }
2915 else if ((strcasecmp(token, "LMTime") == 0)
2916 || (strcasecmp(token, "MTime") == 0)
2917 || (strcasecmp(token, "LastModified") == 0)) {
2918 bit = ETAG_MTIME;
2919 }
2920 else if (strcasecmp(token, "INode") == 0) {
2921 bit = ETAG_INODE;
2922 }
2923 else {
2924 return ap_pstrcat(cmd->pool, "Unknown keyword '",
2925 token, "' for ", cmd->cmd->name,
2926 " directive", NULL);
2927 }
2928
2929 if (! valid) {
2930 return ap_pstrcat(cmd->pool, cmd->cmd->name, " keyword '",
2931 token, "' cannot be used with '+' or '-'",
2932 NULL);
2933 }
2934
2935 if (action == '+') {
2936 /*
2937 * Make sure it's in the 'add' list and absent from the
2938 * 'subtract' list.
2939 */
2940 cfg->etag_add |= bit;
2941 cfg->etag_remove &= (~ bit);
2942 }
2943 else if (action == '-') {
2944 cfg->etag_remove |= bit;
2945 cfg->etag_add &= (~ bit);
2946 }
2947 else {
2948 /*
2949 * Non-relative values wipe out any + or - values
2950 * accumulated so far.
2951 */
2952 cfg->etag_bits |= bit;
2953 cfg->etag_add = ETAG_UNSET;
2954 cfg->etag_remove = ETAG_UNSET;
2955 explicit = 1;
2956 }
2957 }
2958
2959 /*
2960 * Any setting at all will clear the 'None' and 'Unset' bits.
2961 */
2962
2963 if (cfg->etag_add != ETAG_UNSET) {
2964 cfg->etag_add &= (~ ETAG_UNSET);
2965 }
2966 if (cfg->etag_remove != ETAG_UNSET) {
2967 cfg->etag_remove &= (~ ETAG_UNSET);
2968 }
2969 if (explicit) {
2970 cfg->etag_bits &= (~ ETAG_UNSET);
2971 if ((cfg->etag_bits & ETAG_NONE) != ETAG_NONE) {
2972 cfg->etag_bits &= (~ ETAG_NONE);
2973 }
2974 }
2975 return NULL;
2976 }
2977
set_recursion_limit(cmd_parms * cmd,void * dummy,const char * arg1,const char * arg2)2978 static const char *set_recursion_limit(cmd_parms *cmd, void *dummy,
2979 const char *arg1, const char *arg2)
2980 {
2981 core_server_config *conf = ap_get_module_config(cmd->server->module_config,
2982 &core_module);
2983 int limit = atoi(arg1);
2984
2985 if (limit < 0) {
2986 return "The redirect recursion limit cannot be less than zero.";
2987 }
2988 if (limit && limit < 4) {
2989 ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, cmd->server,
2990 "Limiting internal redirects to very low numbers may "
2991 "cause normal requests to fail.");
2992 }
2993
2994 conf->redirect_limit = limit;
2995
2996 if (arg2) {
2997 limit = atoi(arg2);
2998
2999 if (limit < 0) {
3000 return "The subrequest recursion limit cannot be less than zero.";
3001 }
3002 if (limit && limit < 4) {
3003 ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, cmd->server,
3004 "Limiting the subrequest depth to a very low level may"
3005 " cause normal requests to fail.");
3006 }
3007 }
3008
3009 conf->subreq_limit = limit;
3010 conf->recursion_limit_set = 1;
3011
3012 return NULL;
3013 }
3014
log_backtrace(const request_rec * r)3015 static void log_backtrace(const request_rec *r)
3016 {
3017 const request_rec *top = r;
3018
3019 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
3020 "r->uri = %s", r->uri ? r->uri : "(unexpectedly NULL)");
3021
3022 while (top && (top->prev || top->main)) {
3023 if (top->prev) {
3024 top = top->prev;
3025 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
3026 "redirected from r->uri = %s",
3027 top->uri ? top->uri : "(unexpectedly NULL)");
3028 }
3029
3030 if (!top->prev && top->main) {
3031 top = top->main;
3032 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
3033 "subrequested from r->uri = %s",
3034 top->uri ? top->uri : "(unexpectedly NULL)");
3035 }
3036 }
3037 }
3038
3039 /*
3040 * check whether redirect limit is reached
3041 */
ap_is_recursion_limit_exceeded(const request_rec * r)3042 API_EXPORT(int) ap_is_recursion_limit_exceeded(const request_rec *r)
3043 {
3044 core_server_config *conf = ap_get_module_config(r->server->module_config,
3045 &core_module);
3046 const request_rec *top = r;
3047 int redirects = 0, subreqs = 0;
3048 int rlimit = conf->recursion_limit_set
3049 ? conf->redirect_limit
3050 : AP_DEFAULT_MAX_INTERNAL_REDIRECTS;
3051 int slimit = conf->recursion_limit_set
3052 ? conf->subreq_limit
3053 : AP_DEFAULT_MAX_SUBREQ_DEPTH;
3054
3055 /* fast exit (unlimited) */
3056 if (!rlimit && !slimit) {
3057 return 0;
3058 }
3059
3060 while (top->prev || top->main) {
3061 if (top->prev) {
3062 if (rlimit && ++redirects >= rlimit) {
3063 /* uuh, too much. */
3064 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
3065 "Request exceeded the limit of %d internal "
3066 "redirects due to probable configuration error. "
3067 "Use 'LimitInternalRecursion' to increase the "
3068 "limit if necessary. Use 'LogLevel debug' to get "
3069 "a backtrace.", rlimit);
3070
3071 /* post backtrace */
3072 log_backtrace(r);
3073
3074 /* return failure */
3075 return 1;
3076 }
3077
3078 top = top->prev;
3079 }
3080
3081 if (!top->prev && top->main) {
3082 if (slimit && ++subreqs >= slimit) {
3083 /* uuh, too much. */
3084 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
3085 "Request exceeded the limit of %d subrequest "
3086 "nesting levels due to probable confguration "
3087 "error. Use 'LimitInternalRecursion' to increase "
3088 "the limit if necessary. Use 'LogLevel debug' to "
3089 "get a backtrace.", slimit);
3090
3091 /* post backtrace */
3092 log_backtrace(r);
3093
3094 /* return failure */
3095 return 1;
3096 }
3097
3098 top = top->main;
3099 }
3100 }
3101
3102 /* recursion state: ok */
3103 return 0;
3104 }
3105
3106 /* Note --- ErrorDocument will now work from .htaccess files.
3107 * The AllowOverride of Fileinfo allows webmasters to turn it off
3108 */
3109
3110 static const command_rec core_cmds[] = {
3111
3112 /* Old access config file commands */
3113
3114 { "<Directory", dirsection, NULL, RSRC_CONF, RAW_ARGS,
3115 "Container for directives affecting resources located in the specified "
3116 "directories" },
3117 { end_directory_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
3118 "Marks end of <Directory>" },
3119 { "<Location", urlsection, NULL, RSRC_CONF, RAW_ARGS,
3120 "Container for directives affecting resources accessed through the "
3121 "specified URL paths" },
3122 { end_location_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
3123 "Marks end of <Location>" },
3124 { "<VirtualHost", virtualhost_section, NULL, RSRC_CONF, RAW_ARGS,
3125 "Container to map directives to a particular virtual host, takes one or "
3126 "more host addresses" },
3127 { end_virtualhost_section, end_nested_section, NULL, RSRC_CONF, NO_ARGS,
3128 "Marks end of <VirtualHost>" },
3129 { "<Files", filesection, NULL, OR_ALL, RAW_ARGS, "Container for directives "
3130 "affecting files matching specified patterns" },
3131 { end_files_section, end_nested_section, NULL, OR_ALL, NO_ARGS,
3132 "Marks end of <Files>" },
3133 { "<Limit", ap_limit_section, NULL, OR_ALL, RAW_ARGS, "Container for "
3134 "authentication directives when accessed using specified HTTP methods" },
3135 { "</Limit>", endlimit_section, NULL, OR_ALL, NO_ARGS,
3136 "Marks end of <Limit>" },
3137 { "<LimitExcept", ap_limit_section, (void*)1, OR_ALL, RAW_ARGS,
3138 "Container for authentication directives to be applied when any HTTP "
3139 "method other than those specified is used to access the resource" },
3140 { "</LimitExcept>", endlimit_section, (void*)1, OR_ALL, NO_ARGS,
3141 "Marks end of <LimitExcept>" },
3142 { "<IfModule", start_ifmod, NULL, OR_ALL, TAKE1,
3143 "Container for directives based on existance of specified modules" },
3144 { end_ifmodule_section, end_ifmod, NULL, OR_ALL, NO_ARGS,
3145 "Marks end of <IfModule>" },
3146 { "<IfDefine", start_ifdefine, NULL, OR_ALL, TAKE1,
3147 "Container for directives based on existance of command line defines" },
3148 { end_ifdefine_section, end_ifdefine, NULL, OR_ALL, NO_ARGS,
3149 "Marks end of <IfDefine>" },
3150 { "<DirectoryMatch", dirsection, (void*)1, RSRC_CONF, RAW_ARGS,
3151 "Container for directives affecting resources located in the "
3152 "specified directories" },
3153 { end_directorymatch_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
3154 "Marks end of <DirectoryMatch>" },
3155 { "<LocationMatch", urlsection, (void*)1, RSRC_CONF, RAW_ARGS,
3156 "Container for directives affecting resources accessed through the "
3157 "specified URL paths" },
3158 { end_locationmatch_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
3159 "Marks end of <LocationMatch>" },
3160 { "<FilesMatch", filesection, (void*)1, OR_ALL, RAW_ARGS,
3161 "Container for directives affecting files matching specified patterns" },
3162 { end_filesmatch_section, end_nested_section, NULL, OR_ALL, NO_ARGS,
3163 "Marks end of <FilesMatch>" },
3164 { "AuthType", ap_set_string_slot,
3165 (void*)XtOffsetOf(core_dir_config, ap_auth_type), OR_AUTHCFG, TAKE1,
3166 "An HTTP authorization type (e.g., \"Basic\")" },
3167 { "AuthName", set_authname, NULL, OR_AUTHCFG, TAKE1,
3168 "The authentication realm (e.g. \"Members Only\")" },
3169 { "AuthDigestRealmSeed", set_authnonce, NULL, OR_AUTHCFG, TAKE1,
3170 "An authentication token which should be different for each logical realm. "\
3171 "A random value or the servers IP may be a good choise.\n" },
3172 { "Require", require, NULL, OR_AUTHCFG, RAW_ARGS,
3173 "Selects which authenticated users or groups may access a protected space" },
3174 { "Satisfy", satisfy, NULL, OR_AUTHCFG, TAKE1,
3175 "access policy if both allow and require used ('all' or 'any')" },
3176 #ifdef GPROF
3177 { "GprofDir", set_gprof_dir, NULL, RSRC_CONF, TAKE1,
3178 "Directory to plop gmon.out files" },
3179 #endif
3180 { "AddDefaultCharset", set_add_default_charset, NULL, OR_FILEINFO,
3181 TAKE1, "The name of the default charset to add to any Content-Type without one or 'Off' to disable" },
3182
3183 /* Old resource config file commands */
3184
3185 { "AccessFileName", set_access_name, NULL, RSRC_CONF, RAW_ARGS,
3186 "Name(s) of per-directory config files (default: .htaccess)" },
3187 { "DocumentRoot", set_document_root, NULL, RSRC_CONF, TAKE1,
3188 "Root directory of the document tree" },
3189 { "ErrorDocument", set_error_document, NULL, OR_FILEINFO, RAW_ARGS,
3190 "Change responses for HTTP errors" },
3191 { "AllowOverride", set_override, NULL, ACCESS_CONF, RAW_ARGS,
3192 "Controls what groups of directives can be configured by per-directory "
3193 "config files" },
3194 { "Options", set_options, NULL, OR_OPTIONS, RAW_ARGS,
3195 "Set a number of attributes for a given directory" },
3196 { "DefaultType", ap_set_string_slot,
3197 (void*)XtOffsetOf (core_dir_config, ap_default_type),
3198 OR_FILEINFO, TAKE1, "the default MIME type for untypable files" },
3199
3200 /* Old server config file commands */
3201
3202 { "ServerType", server_type, NULL, RSRC_CONF, TAKE1,
3203 "'inetd' or 'standalone'"},
3204 { "Port", server_port, NULL, RSRC_CONF, TAKE1, "A TCP port number"},
3205 { "HostnameLookups", set_hostname_lookups, NULL, ACCESS_CONF|RSRC_CONF, TAKE1,
3206 "\"on\" to enable, \"off\" to disable reverse DNS lookups, or \"double\" to "
3207 "enable double-reverse DNS lookups" },
3208 { "User", set_user, NULL, RSRC_CONF, TAKE1,
3209 "Effective user id for this server"},
3210 { "Group", set_group, NULL, RSRC_CONF, TAKE1,
3211 "Effective group id for this server"},
3212 { "ServerAdmin", set_server_string_slot,
3213 (void *)XtOffsetOf (server_rec, server_admin), RSRC_CONF, TAKE1,
3214 "The email address of the server administrator" },
3215 { "ServerName", set_server_string_slot,
3216 (void *)XtOffsetOf (server_rec, server_hostname), RSRC_CONF, TAKE1,
3217 "The hostname of the server" },
3218 { "ServerSignature", set_signature_flag, NULL, OR_ALL, TAKE1,
3219 "En-/disable server signature (on|off|email)" },
3220 { "ServerRoot", set_server_root, NULL, RSRC_CONF, TAKE1,
3221 "Common directory of server-related files (logs, confs, etc.)" },
3222 { "ErrorLog", set_server_string_slot,
3223 (void *)XtOffsetOf (server_rec, error_fname), RSRC_CONF, TAKE1,
3224 "The filename of the error log" },
3225 { "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1,
3226 "A file for logging the server process ID"},
3227 { "ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, TAKE1,
3228 "A file for Apache to maintain runtime process management information"},
3229 { "LockFile", set_lockfile, NULL, RSRC_CONF, TAKE1,
3230 "The lockfile used when Apache needs to lock the accept() call"},
3231 { "AccessConfig", set_server_string_slot,
3232 (void *)XtOffsetOf (server_rec, access_confname), RSRC_CONF, TAKE1,
3233 "The filename of the access config file" },
3234 { "ResourceConfig", set_server_string_slot,
3235 (void *)XtOffsetOf (server_rec, srm_confname), RSRC_CONF, TAKE1,
3236 "The filename of the resource config file" },
3237 { "ServerAlias", set_server_alias, NULL, RSRC_CONF, RAW_ARGS,
3238 "A name or names alternately used to access the server" },
3239 { "ServerPath", set_serverpath, NULL, RSRC_CONF, TAKE1,
3240 "The pathname the server can be reached at" },
3241 { "Timeout", set_timeout, NULL, RSRC_CONF, TAKE1, "Timeout duration (sec)" },
3242 { "KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF, TAKE1,
3243 "Keep-Alive timeout duration (sec)"},
3244 { "MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF, TAKE1,
3245 "Maximum number of Keep-Alive requests per connection, or 0 for infinite" },
3246 { "KeepAlive", set_keep_alive, NULL, RSRC_CONF, TAKE1,
3247 "Whether persistent connections should be On or Off" },
3248 { "IdentityCheck", set_idcheck, NULL, RSRC_CONF|ACCESS_CONF, FLAG,
3249 "Enable identd (RFC 1413) user lookups - SLOW" },
3250 { "ContentDigest", set_content_md5, NULL, OR_OPTIONS,
3251 FLAG, "whether or not to send a Content-MD5 header with each request" },
3252 { "UseCanonicalName", set_use_canonical_name, NULL,
3253 RSRC_CONF|ACCESS_CONF, TAKE1,
3254 "How to work out the ServerName : Port when constructing URLs" },
3255 { "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1,
3256 "Number of child processes launched at server startup" },
3257 { "MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, TAKE1,
3258 "Minimum number of idle children, to handle request spikes" },
3259 { "MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1,
3260 "Maximum number of idle children" },
3261 { "MaxServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1,
3262 "Deprecated equivalent to MaxSpareServers" },
3263 { "ServersSafetyLimit", set_server_limit, NULL, RSRC_CONF, TAKE1,
3264 "Deprecated equivalent to MaxClients" },
3265 { "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1,
3266 "Maximum number of children alive at the same time" },
3267 { "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1,
3268 "Maximum number of requests a particular child serves before dying." },
3269 { "MaxCPUPerChild", set_child_rl_cpu, NULL, RSRC_CONF, TAKE1,
3270 "Maximum amount of CPU time a child can use (rlimit)." },
3271 { "MaxDATAPerChild", set_child_rl_data, NULL, RSRC_CONF, TAKE1,
3272 "Maximum size of the data segment for a child process (rlimit)." },
3273 { "MaxNOFILEPerChild", set_child_rl_nofile, NULL, RSRC_CONF, TAKE1,
3274 "Maximum number of open file descriptors a child can have (rlimit)." },
3275 { "MaxRSSPerChild", set_child_rl_rss, NULL, RSRC_CONF, TAKE1,
3276 "Maximum amount of physical memory a child can use (rlimit)." },
3277 { "MaxSTACKPerChild", set_child_rl_stack, NULL, RSRC_CONF, TAKE1,
3278 "Maximum amount of stack space a child can use (rlimit)." },
3279 #ifdef RLIMIT_TIME
3280 { "MaxTIMEPerChild", set_child_rl_time, NULL, RSRC_CONF, TAKE1,
3281 "Maximum lifetime (in seconds) of a child (rlimit)." },
3282 #endif
3283 { "RLimitCPU",
3284 set_limit_cpu, (void*)XtOffsetOf(core_dir_config, limit_cpu),
3285 OR_ALL, TAKE12, "Soft/hard limits for max CPU usage in seconds" },
3286 { "RLimitMEM",
3287 set_limit_mem, (void*)XtOffsetOf(core_dir_config, limit_mem),
3288 OR_ALL, TAKE12, "Soft/hard limits for max memory usage per process" },
3289 { "RLimitNPROC",
3290 set_limit_nproc, (void*)XtOffsetOf(core_dir_config, limit_nproc),
3291 OR_ALL, TAKE12, "soft/hard limits for max number of processes per uid" },
3292 { "RLimitNOFILE",
3293 set_limit_nofile, (void*)XtOffsetOf(core_dir_config, limit_nofile),
3294 OR_ALL, TAKE12, "soft/hard limits for max number of files per process" },
3295 #ifdef RLIMIT_TIME
3296 { "RLimitTIME",
3297 set_limit_time, (void*)XtOffsetOf(core_dir_config, limit_time),
3298 OR_ALL, TAKE12, "Soft/hard limits for max human time in seconds" },
3299 #endif
3300 { "BindAddress", set_bind_address, NULL, RSRC_CONF, TAKE1,
3301 "'*', a numeric IP address, or the name of a host with a unique IP address"},
3302 { "Listen", set_listener, NULL, RSRC_CONF, TAKE12,
3303 "A port number or a numeric IP address and a port number"},
3304 { "SendBufferSize", set_send_buffer_size, NULL, RSRC_CONF, TAKE1,
3305 "Send buffer size in bytes"},
3306 { "AddModule", add_module_command, NULL, RSRC_CONF, ITERATE,
3307 "The name of a module" },
3308 { "ClearModuleList", clear_module_list_command, NULL, RSRC_CONF, NO_ARGS,
3309 NULL },
3310 { "ThreadsPerChild", set_threads, NULL, RSRC_CONF, TAKE1,
3311 "Number of threads a child creates" },
3312 { "ExcessRequestsPerChild", set_excess_requests, NULL, RSRC_CONF, TAKE1,
3313 "Maximum number of requests a particular child serves after it is ready "
3314 "to die." },
3315 { "ListenBacklog", set_listenbacklog, NULL, RSRC_CONF, TAKE1,
3316 "Maximum length of the queue of pending connections, as used by listen(2)" },
3317 { "AcceptFilter", set_acceptfilter, NULL, RSRC_CONF, FLAG,
3318 "Switch AcceptFiltering on/off (default is "
3319 "on"
3320 ")."
3321 "This feature is currently not compiled in; so this directive "
3322 "is ignored."
3323 },
3324 { "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1,
3325 "The location of the directory Apache changes to before dumping core" },
3326 { "Include", include_config, NULL, (RSRC_CONF | ACCESS_CONF), TAKE1,
3327 "Name of the config file to be included" },
3328 { "LogLevel", set_loglevel, NULL, RSRC_CONF, TAKE1,
3329 "Level of verbosity in error logging" },
3330 { "NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF, TAKE12,
3331 "A numeric IP address:port, or the name of a host" },
3332 { "CGICommandArgs", set_cgi_command_args, NULL, OR_OPTIONS, FLAG,
3333 "Allow or Disallow CGI requests to pass args on the command line" },
3334 { "ServerTokens", set_serv_tokens, NULL, RSRC_CONF, TAKE1,
3335 "Tokens displayed in the Server: header - Min[imal], OS, Prod[uctOnly], Full" },
3336 { "LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF, TAKE1,
3337 "Limit on maximum size of an HTTP request line"},
3338 { "LimitRequestFieldsize", set_limit_req_fieldsize, NULL, RSRC_CONF, TAKE1,
3339 "Limit on maximum size of an HTTP request header field"},
3340 { "LimitRequestFields", set_limit_req_fields, NULL, RSRC_CONF, TAKE1,
3341 "Limit (0 = unlimited) on max number of header fields in a request message"},
3342 { "LimitRequestBody", set_limit_req_body,
3343 (void*)XtOffsetOf(core_dir_config, limit_req_body),
3344 OR_ALL, TAKE1,
3345 "Limit (in bytes) on maximum size of request message body" },
3346 { "ProtocolReqCheck", set_protocol_req_check, NULL, RSRC_CONF, FLAG,
3347 "Enable strict checking of Protocol type in requests" },
3348 { "ShmemUIDisUser", set_change_shmem_uid, NULL, RSRC_CONF, FLAG,
3349 "Enable the setting of SysV shared memory scoreboard uid/gid to User/Group" },
3350 { "AcceptMutex", set_accept_mutex, NULL, RSRC_CONF, TAKE1,
3351 "Serialized Accept Mutex; the methods "
3352 "'sysvsem' "
3353 "'flock' "
3354 "are compiled in"
3355 },
3356
3357 { "FileETag", set_etag_bits, NULL, OR_FILEINFO, RAW_ARGS,
3358 "Specify components used to construct a file's ETag"},
3359
3360 { "LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF, TAKE12,
3361 "maximum recursion depth of internal redirects and subrequests"},
3362
3363 { NULL }
3364 };
3365
3366 /*****************************************************************
3367 *
3368 * Core handlers for various phases of server operation...
3369 */
3370
core_translate(request_rec * r)3371 static int core_translate(request_rec *r)
3372 {
3373 void *sconf = r->server->module_config;
3374 core_server_config *conf = ap_get_module_config(sconf, &core_module);
3375
3376 if (r->proxyreq != NOT_PROXY) {
3377 return HTTP_FORBIDDEN;
3378 }
3379 if ((r->uri[0] != '/') && strcmp(r->uri, "*")) {
3380 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
3381 "Invalid URI in request %s", r->the_request);
3382 return BAD_REQUEST;
3383 }
3384
3385 if (r->server->path
3386 && !strncmp(r->uri, r->server->path, r->server->pathlen)
3387 && (r->server->path[r->server->pathlen - 1] == '/'
3388 || r->uri[r->server->pathlen] == '/'
3389 || r->uri[r->server->pathlen] == '\0')) {
3390 r->filename = ap_pstrcat(r->pool, conf->ap_document_root,
3391 (r->uri + r->server->pathlen), NULL);
3392 }
3393 else {
3394 /*
3395 * Make sure that we do not mess up the translation by adding two
3396 * /'s in a row. This happens under windows when the document
3397 * root ends with a /
3398 */
3399 if ((conf->ap_document_root[strlen(conf->ap_document_root)-1] == '/')
3400 && (*(r->uri) == '/')) {
3401 r->filename = ap_pstrcat(r->pool, conf->ap_document_root, r->uri+1,
3402 NULL);
3403 }
3404 else {
3405 r->filename = ap_pstrcat(r->pool, conf->ap_document_root, r->uri,
3406 NULL);
3407 }
3408 }
3409
3410 return OK;
3411 }
3412
do_nothing(request_rec * r)3413 static int do_nothing(request_rec *r) { return OK; }
3414
3415 struct mmap_rec {
3416 void *mm;
3417 size_t length;
3418 };
3419
mmap_cleanup(void * mmv)3420 static void mmap_cleanup(void *mmv)
3421 {
3422 struct mmap_rec *mmd = mmv;
3423
3424 if (munmap(mmd->mm, mmd->length) == -1) {
3425 ap_log_error(APLOG_MARK, APLOG_ERR, NULL,
3426 "Failed to munmap memory of length %ld at 0x%lx",
3427 (long) mmd->length, (long) mmd->mm);
3428 }
3429 }
3430
3431 /*
3432 * Default handler for MIME types without other handlers. Only GET
3433 * and OPTIONS at this point... anyone who wants to write a generic
3434 * handler for PUT or POST is free to do so, but it seems unwise to provide
3435 * any defaults yet... So, for now, we assume that this will always be
3436 * the last handler called and return 405 or 501.
3437 */
3438
default_handler(request_rec * r)3439 static int default_handler(request_rec *r)
3440 {
3441 core_dir_config *d =
3442 (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
3443 int rangestatus, errstatus;
3444 FILE *f;
3445 caddr_t mm;
3446
3447 /* This handler has no use for a request body (yet), but we still
3448 * need to read and discard it if the client sent one.
3449 */
3450 if ((errstatus = ap_discard_request_body(r)) != OK) {
3451 return errstatus;
3452 }
3453
3454 r->allowed |= (1 << M_GET) | (1 << M_OPTIONS);
3455
3456 if (r->method_number == M_INVALID) {
3457 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
3458 "Invalid method in request %s",
3459 ap_escape_logitem(r->pool, r->the_request));
3460 return NOT_IMPLEMENTED;
3461 }
3462 if (r->method_number == M_OPTIONS) {
3463 return ap_send_http_options(r);
3464 }
3465 if (r->method_number == M_PUT) {
3466 return METHOD_NOT_ALLOWED;
3467 }
3468
3469 if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) {
3470 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
3471 "File does not exist: %s",r->path_info ?
3472 ap_pstrcat(r->pool, r->filename, r->path_info, NULL)
3473 : r->filename);
3474 return HTTP_NOT_FOUND;
3475 }
3476 if (r->method_number != M_GET) {
3477 return METHOD_NOT_ALLOWED;
3478 }
3479
3480 f = ap_pfopen(r->pool, r->filename, "r");
3481
3482 if (f == NULL) {
3483 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
3484 "file permissions deny server access: %s", r->filename);
3485 return FORBIDDEN;
3486 }
3487
3488 ap_update_mtime(r, r->finfo.st_mtime);
3489 ap_set_last_modified(r);
3490 ap_set_etag(r);
3491 ap_table_setn(r->headers_out, "Accept-Ranges", "bytes");
3492 if (((errstatus = ap_meets_conditions(r)) != OK)
3493 || (errstatus = ap_set_content_length(r, r->finfo.st_size))) {
3494 return errstatus;
3495 }
3496
3497 ap_block_alarms();
3498 if ((r->finfo.st_size >= MMAP_THRESHOLD)
3499 && (r->finfo.st_size < MMAP_LIMIT)
3500 && (!r->header_only || (d->content_md5 & 1))) {
3501 /* we need to protect ourselves in case we die while we've got the
3502 * file mmapped */
3503 mm = mmap(NULL, r->finfo.st_size, PROT_READ, MAP_PRIVATE,
3504 fileno(f), 0);
3505 if (mm == (caddr_t)-1) {
3506 ap_log_rerror(APLOG_MARK, APLOG_CRIT, r,
3507 "default_handler: mmap failed: %s", r->filename);
3508 }
3509 }
3510 else {
3511 mm = (caddr_t)-1;
3512 }
3513
3514 if (mm == (caddr_t)-1) {
3515 ap_unblock_alarms();
3516
3517 if (d->content_md5 & 1) {
3518 ap_table_setn(r->headers_out, "Content-MD5",
3519 ap_md5digest(r->pool, f));
3520 }
3521
3522 rangestatus = ap_set_byterange(r);
3523
3524 ap_send_http_header(r);
3525
3526 if (!r->header_only) {
3527 if (!rangestatus) {
3528 ap_send_fd(f, r);
3529 }
3530 else {
3531 long offset, length;
3532 while (ap_each_byterange(r, &offset, &length)) {
3533 /*
3534 * Non zero returns are more portable than checking
3535 * for a return of -1.
3536 */
3537 if (fseek(f, offset, SEEK_SET)) {
3538 ap_log_error(APLOG_MARK, APLOG_ERR, r->server,
3539 "Failed to fseek for byterange (%ld, %ld): %s",
3540 offset, length, r->filename);
3541 }
3542 else {
3543 ap_send_fd_length(f, r, length);
3544 }
3545 }
3546 }
3547 }
3548
3549 }
3550 else {
3551 struct mmap_rec *mmd;
3552
3553 mmd = ap_palloc(r->pool, sizeof(*mmd));
3554 mmd->mm = mm;
3555 mmd->length = r->finfo.st_size;
3556 ap_register_cleanup(r->pool, (void *)mmd, mmap_cleanup, mmap_cleanup);
3557 ap_unblock_alarms();
3558
3559 if (d->content_md5 & 1) {
3560 AP_MD5_CTX context;
3561
3562 ap_MD5Init(&context);
3563 ap_MD5Update(&context, (void *)mm, (unsigned int)r->finfo.st_size);
3564 ap_table_setn(r->headers_out, "Content-MD5",
3565 ap_md5contextTo64(r->pool, &context));
3566 }
3567
3568 rangestatus = ap_set_byterange(r);
3569 ap_send_http_header(r);
3570
3571 if (!r->header_only) {
3572 if (!rangestatus) {
3573 ap_send_mmap(mm, r, 0, r->finfo.st_size);
3574 }
3575 else {
3576 long offset, length;
3577 while (ap_each_byterange(r, &offset, &length)) {
3578 ap_send_mmap(mm, r, offset, length);
3579 }
3580 }
3581 }
3582 }
3583
3584 ap_pfclose(r->pool, f);
3585 return OK;
3586 }
3587
3588 static const handler_rec core_handlers[] = {
3589 { "*/*", default_handler },
3590 { "default-handler", default_handler },
3591 { NULL, NULL }
3592 };
3593
3594 API_VAR_EXPORT module core_module = {
3595 STANDARD_MODULE_STUFF,
3596 NULL, /* initializer */
3597 create_core_dir_config, /* create per-directory config structure */
3598 merge_core_dir_configs, /* merge per-directory config structures */
3599 create_core_server_config, /* create per-server config structure */
3600 merge_core_server_configs, /* merge per-server config structures */
3601 core_cmds, /* command table */
3602 core_handlers, /* handlers */
3603 core_translate, /* translate_handler */
3604 NULL, /* check_user_id */
3605 NULL, /* check auth */
3606 do_nothing, /* check access */
3607 do_nothing, /* type_checker */
3608 NULL, /* pre-run fixups */
3609 NULL, /* logger */
3610 NULL, /* header parser */
3611 NULL, /* child_init */
3612 NULL, /* child_exit */
3613 NULL /* post_read_request */
3614 };
3615