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