X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=server%2Fconfig.c;h=61daeaf4a91902e4fa543a09052a1c645543e9be;hb=c810409b4c033e620dbdd5ee9a02618880f9c0b4;hp=07f8f256c89718cecd8c851babe5446b73ea6bc3;hpb=ed451e94d1edccf3ddb4d19c4c29fd7423eb03be;p=apache diff --git a/server/config.c b/server/config.c index 07f8f256c8..61daeaf4a9 100644 --- a/server/config.c +++ b/server/config.c @@ -15,7 +15,7 @@ */ /* - * http_config.c: once was auxillary functions for reading httpd's config + * http_config.c: once was auxiliary functions for reading httpd's config * file and converting filenames into a namespace * * Rob McCool @@ -49,12 +49,17 @@ #include "http_main.h" #include "http_vhost.h" #include "util_cfgtree.h" +#include "util_varbuf.h" +#include "mpm_common.h" #define APLOG_UNSET (APLOG_NO_MODULE - 1) -APLOG_USE_MODULE(core); +/* we know core's module_index is 0 */ +#undef APLOG_MODULE_INDEX +#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX AP_DECLARE_DATA const char *ap_server_argv0 = NULL; AP_DECLARE_DATA const char *ap_server_root = NULL; +AP_DECLARE_DATA const char *ap_runtime_dir = NULL; AP_DECLARE_DATA server_rec *ap_server_conf = NULL; AP_DECLARE_DATA apr_pool_t *ap_pglobal = NULL; @@ -75,6 +80,7 @@ APR_HOOK_STRUCT( APR_HOOK_LINK(quick_handler) APR_HOOK_LINK(optional_fn_retrieve) APR_HOOK_LINK(test_config) + APR_HOOK_LINK(open_htaccess) ) AP_IMPLEMENT_HOOK_RUN_ALL(int, header_parser, @@ -130,7 +136,8 @@ AP_DECLARE(int) ap_hook_post_config(ap_HOOK_post_config_t *pf, apr_hook_debug_show("post_config", aszPre, aszSucc); } -AP_DECLARE(apr_array_header_t *) ap_hook_get_post_config(void) { +AP_DECLARE(apr_array_header_t *) ap_hook_get_post_config(void) +{ return _hooks.link_post_config; } @@ -142,7 +149,7 @@ AP_DECLARE(int) ap_run_post_config(apr_pool_t *pconf, ap_LINK_post_config_t *pHook; int n; - if(!_hooks.link_post_config) + if (!_hooks.link_post_config) return; pHook = (ap_LINK_post_config_t *)_hooks.link_post_config->elts; @@ -166,6 +173,26 @@ AP_IMPLEMENT_HOOK_RUN_FIRST(int, handler, (request_rec *r), AP_IMPLEMENT_HOOK_RUN_FIRST(int, quick_handler, (request_rec *r, int lookup), (r, lookup), DECLINED) +AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, open_htaccess, + (request_rec *r, const char *dir_name, const char *access_name, + ap_configfile_t **conffile, const char **full_name), + (r, dir_name, access_name, conffile, full_name), + AP_DECLINED) + +/* hooks with no args are implemented last, after disabling APR hook probes */ +#if defined(APR_HOOK_PROBES_ENABLED) +#undef APR_HOOK_PROBES_ENABLED +#undef APR_HOOK_PROBE_ENTRY +#define APR_HOOK_PROBE_ENTRY(ud,ns,name,args) +#undef APR_HOOK_PROBE_RETURN +#define APR_HOOK_PROBE_RETURN(ud,ns,name,rv,args) +#undef APR_HOOK_PROBE_INVOKE +#define APR_HOOK_PROBE_INVOKE(ud,ns,name,src,args) +#undef APR_HOOK_PROBE_COMPLETE +#define APR_HOOK_PROBE_COMPLETE(ud,ns,name,src,rv,args) +#undef APR_HOOK_INT_DCL_UD +#define APR_HOOK_INT_DCL_UD +#endif AP_IMPLEMENT_HOOK_VOID(optional_fn_retrieve, (void), ()) /**************************************************************** @@ -197,15 +224,28 @@ static int max_modules = 0; */ static int conf_vector_length = 0; +static int reserved_module_slots = 0; + AP_DECLARE_DATA module *ap_top_module = NULL; AP_DECLARE_DATA module **ap_loaded_modules=NULL; static apr_hash_t *ap_config_hash = NULL; +/* a list of the module symbol names with the trailing "_module"removed */ +static char **ap_module_short_names = NULL; + typedef int (*handler_func)(request_rec *); typedef void *(*dir_maker_func)(apr_pool_t *, char *); typedef void *(*merger_func)(apr_pool_t *, void *, void *); +/* A list of the merge_dir_config functions of all loaded modules, sorted + * by module_index. + * Using this list in ap_merge_per_dir_configs() is faster than following + * the module->next linked list because of better memory locality (resulting + * in better cache usage). + */ +static merger_func *merger_func_cache; + /* maximum nesting level for config directories */ #ifndef AP_MAX_INCLUDE_DIR_DEPTH #define AP_MAX_INCLUDE_DIR_DEPTH (128) @@ -250,16 +290,14 @@ AP_CORE_DECLARE(ap_conf_vector_t *) ap_merge_per_dir_configs(apr_pool_t *p, void **conf_vector = apr_palloc(p, sizeof(void *) * conf_vector_length); void **base_vector = (void **)base; void **new_vector = (void **)new_conf; - module *modp; - - for (modp = ap_top_module; modp; modp = modp->next) { - int i = modp->module_index; + int i; + for (i = 0; i < total_modules; i++) { if (!new_vector[i]) { conf_vector[i] = base_vector[i]; } else { - merger_func df = modp->merge_dir_config; + const merger_func df = merger_func_cache[i]; if (df && base_vector[i]) { conf_vector[i] = (*df)(p, base_vector[i], new_vector[i]); } @@ -339,12 +377,6 @@ static int invoke_filter_init(request_rec *r, ap_filter_t *filters) return OK; } -/* - * TODO: Move this to an appropriate include file and possibly prefix it - * with AP_. - */ -#define DEFAULT_HANDLER_NAME "" - AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r) { const char *handler; @@ -393,7 +425,7 @@ AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r) } } else { - handler = DEFAULT_HANDLER_NAME; + handler = AP_DEFAULT_HANDLER_NAME; } r->handler = handler; @@ -404,7 +436,7 @@ AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r) r->handler = old_handler; if (result == DECLINED && r->handler && r->filename) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(00523) "handler \"%s\" not found for: %s", r->handler, r->filename); } if ((result != OK) && (result != DONE) && (result != DECLINED) && (result != SUSPENDED) @@ -418,7 +450,7 @@ AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r) */ ignore = apr_table_get(r->notes, "HTTP_IGNORE_RANGE"); if (!ignore) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00524) "Handler for %s returned invalid result code %d", r->handler, result); result = HTTP_INTERNAL_SERVER_ERROR; @@ -467,19 +499,13 @@ struct ap_mod_list_struct { const command_rec *cmd; }; -static apr_status_t reload_conf_hash(void *baton) -{ - ap_config_hash = NULL; - return APR_SUCCESS; -} - static void rebuild_conf_hash(apr_pool_t *p, int add_prelinked) { module **m; ap_config_hash = apr_hash_make(p); - apr_pool_cleanup_register(p, NULL, reload_conf_hash, + apr_pool_cleanup_register(p, &ap_config_hash, ap_pool_cleanup_set_null, apr_pool_cleanup_null); if (add_prelinked) { for (m = ap_prelinked_modules; *m != NULL; m++) { @@ -520,8 +546,11 @@ static void ap_add_module_commands(module *m, apr_pool_t *p) /* One-time setup for precompiled modules --- NOT to be done on restart */ -AP_DECLARE(const char *) ap_add_module(module *m, apr_pool_t *p) +AP_DECLARE(const char *) ap_add_module(module *m, apr_pool_t *p, + const char *sym_name) { + ap_module_symbol_t *sym = ap_prelinked_module_symbols; + /* This could be called from a LoadModule httpd.conf command, * after the file has been linked and the module structure within it * teased out... @@ -534,23 +563,51 @@ AP_DECLARE(const char *) ap_add_module(module *m, apr_pool_t *p) m->name, m->version, MODULE_MAGIC_NUMBER_MAJOR); } - if (m->next == NULL) { - m->next = ap_top_module; - ap_top_module = m; - } - if (m->module_index == -1) { - m->module_index = total_modules++; - dynamic_modules++; - - if (dynamic_modules > DYNAMIC_MODULE_LIMIT) { + if (dynamic_modules >= DYNAMIC_MODULE_LIMIT) { return apr_psprintf(p, "Module \"%s\" could not be loaded, " "because the dynamic module limit was " "reached. Please increase " "DYNAMIC_MODULE_LIMIT and recompile.", m->name); } + /* + * If this fails some module forgot to call ap_reserve_module_slots*. + */ + ap_assert(total_modules < conf_vector_length); + + m->module_index = total_modules++; + dynamic_modules++; + + } + else if (!sym_name) { + while (sym->modp != NULL) { + if (sym->modp == m) { + sym_name = sym->name; + break; + } + sym++; + } } + if (m->next == NULL) { + m->next = ap_top_module; + ap_top_module = m; + } + + if (sym_name) { + int len = strlen(sym_name); + int slen = strlen("_module"); + if (len > slen && !strcmp(sym_name + len - slen, "_module")) { + len -= slen; + } + + ap_module_short_names[m->module_index] = ap_malloc(len + 1); + memcpy(ap_module_short_names[m->module_index], sym_name, len); + ap_module_short_names[m->module_index][len] = '\0'; + merger_func_cache[m->module_index] = m->merge_dir_config; + } + + /* Some C compilers put a complete path into __FILE__, but we want * only the filename (e.g. mod_includes.c). So check for path * components (Unix and DOS), and remove them. @@ -569,8 +626,9 @@ AP_DECLARE(const char *) ap_add_module(module *m, apr_pool_t *p) /* We cannot fix the string in-place, because it's const */ if (m->name[strlen(m->name)-1] == ')') { - char *tmp = strdup(m->name); /* FIXME: memory leak, albeit a small one */ - tmp[strlen(tmp)-1] = '\0'; + char *tmp = ap_malloc(strlen(m->name)); /* FIXME: memory leak, albeit a small one */ + memcpy(tmp, m->name, strlen(m->name)-1); + tmp[strlen(m->name)-1] = '\0'; m->name = tmp; } #endif /*_OSD_POSIX*/ @@ -613,7 +671,7 @@ AP_DECLARE(void) ap_remove_module(module *m) if (!modp) { /* Uh-oh, this module doesn't exist */ - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00525) "Cannot remove module %s: not found in module list", m->name); return; @@ -623,13 +681,18 @@ AP_DECLARE(void) ap_remove_module(module *m) modp->next = modp->next->next; } + free(ap_module_short_names[m->module_index]); + ap_module_short_names[m->module_index] = NULL; + merger_func_cache[m->module_index] = NULL; + m->module_index = -1; /* simulate being unloaded, should * be unnecessary */ dynamic_modules--; total_modules--; } -AP_DECLARE(const char *) ap_add_loaded_module(module *mod, apr_pool_t *p) +AP_DECLARE(const char *) ap_add_loaded_module(module *mod, apr_pool_t *p, + const char *short_name) { module **m; const char *error; @@ -637,7 +700,7 @@ AP_DECLARE(const char *) ap_add_loaded_module(module *mod, apr_pool_t *p) /* * Add module pointer to top of chained module list */ - error = ap_add_module(mod, p); + error = ap_add_module(mod, p, short_name); if (error) { return error; } @@ -674,7 +737,7 @@ AP_DECLARE(void) ap_remove_loaded_module(module *mod) * * Note: 1. We cannot determine if the module was successfully * removed by ap_remove_module(). - * 2. We have not to complain explicity when the module + * 2. We have not to complain explicitly when the module * is not found because ap_remove_module() did it * for us already. */ @@ -709,14 +772,19 @@ AP_DECLARE(const char *) ap_setup_prelinked_modules(process_rec *process) conf_vector_length = max_modules; /* - * Initialise list of loaded modules + * Initialise list of loaded modules and short names */ ap_loaded_modules = (module **)apr_palloc(process->pool, sizeof(module *) * conf_vector_length); + if (!ap_module_short_names) + ap_module_short_names = ap_calloc(sizeof(char *), conf_vector_length); + + if (!merger_func_cache) + merger_func_cache = ap_calloc(sizeof(merger_func), conf_vector_length); - if (ap_loaded_modules == NULL) { + if (ap_loaded_modules == NULL || ap_module_short_names == NULL + || merger_func_cache == NULL) return "Ouch! Out of memory in ap_setup_prelinked_modules()!"; - } for (m = ap_preloaded_modules, m2 = ap_loaded_modules; *m != NULL; ) *m2++ = *m++; @@ -727,7 +795,7 @@ AP_DECLARE(const char *) ap_setup_prelinked_modules(process_rec *process) * Initialize chain of linked (=activate) modules */ for (m = ap_prelinked_modules; *m != NULL; m++) { - error = ap_add_module(*m, process->pconf); + error = ap_add_module(*m, process->pconf, NULL); if (error) { return error; } @@ -743,6 +811,13 @@ AP_DECLARE(const char *) ap_find_module_name(module *m) return m->name; } +AP_DECLARE(const char *) ap_find_module_short_name(int module_index) +{ + if (module_index < 0 || module_index >= conf_vector_length) + return NULL; + return ap_module_short_names[module_index]; +} + AP_DECLARE(module *) ap_find_linked_module(const char *name) { module *modp; @@ -769,11 +844,30 @@ AP_DECLARE(module *) ap_find_linked_module(const char *name) static const char *invoke_cmd(const command_rec *cmd, cmd_parms *parms, void *mconfig, const char *args) { + int override_list_ok = 0; char *w, *w2, *w3; const char *errmsg = NULL; - if ((parms->override & cmd->req_override) == 0) - return apr_pstrcat(parms->pool, cmd->name, " not allowed here", NULL); + /* Have we been provided a list of acceptable directives? */ + if (parms->override_list != NULL) { + if (apr_table_get(parms->override_list, cmd->name) != NULL) { + override_list_ok = 1; + } + } + + if ((parms->override & cmd->req_override) == 0 && !override_list_ok) { + if (parms->override & NONFATAL_OVERRIDE) { + ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, parms->temp_pool, + APLOGNO(02295) + "%s in .htaccess forbidden by AllowOverride", + cmd->name); + return NULL; + } + else { + return apr_pstrcat(parms->pool, cmd->name, + " not allowed here", NULL); + } + } parms->info = cmd->cmd_data; parms->cmd = cmd; @@ -886,12 +980,20 @@ static const char *invoke_cmd(const command_rec *cmd, cmd_parms *parms, return cmd->AP_TAKE3(parms, mconfig, w, w2, w3); case ITERATE: - while (*(w = ap_getword_conf(parms->pool, &args)) != '\0') { + w = ap_getword_conf(parms->pool, &args); + + if (*w == '\0') + return apr_pstrcat(parms->pool, cmd->name, + " requires at least one argument", + cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); + while (*w != '\0') { errmsg = cmd->AP_TAKE1(parms, mconfig, w); if (errmsg && strcmp(errmsg, DECLINE_CMD) != 0) return errmsg; + + w = ap_getword_conf(parms->pool, &args); } return errmsg; @@ -915,7 +1017,11 @@ static const char *invoke_cmd(const command_rec *cmd, cmd_parms *parms, return errmsg; case FLAG: - w = ap_getword_conf(parms->pool, &args); + /* + * This is safe to use temp_pool here, because the 'flag' itself is not + * forwarded as-is + */ + w = ap_getword_conf(parms->temp_pool, &args); if (*w == '\0' || (strcasecmp(w, "on") && strcasecmp(w, "off"))) return apr_pstrcat(parms->pool, cmd->name, " must be On or Off", @@ -1009,7 +1115,11 @@ static const char *ap_build_config_sub(apr_pool_t *p, apr_pool_t *temp_pool, args = ap_resolve_env(temp_pool, l); #endif - cmd_name = ap_getword_conf(p, &args); + /* The first word is the name of a directive. We can safely use the + * 'temp_pool' for it. If it matches the name of a known directive, we + * can reference the string within the module if needed. Otherwise, we + * can still make a copy in the 'p' pool. */ + cmd_name = ap_getword_conf(temp_pool, &args); if (*cmd_name == '\0') { /* Note: this branch should not occur. An empty line should have * triggered the exit further above. @@ -1030,10 +1140,11 @@ static const char *ap_build_config_sub(apr_pool_t *p, apr_pool_t *temp_pool, newdir = apr_pcalloc(p, sizeof(ap_directive_t)); newdir->filename = parms->config_file->name; newdir->line_num = parms->config_file->line_number; - newdir->directive = cmd_name; newdir->args = apr_pstrdup(p, args); if ((cmd = ap_find_command_in_modules(cmd_name, &mod)) != NULL) { + newdir->directive = cmd->name; + if (cmd->req_override & EXEC_ON_READ) { ap_directive_t *sub_tree = NULL; @@ -1067,6 +1178,11 @@ static const char *ap_build_config_sub(apr_pool_t *p, apr_pool_t *temp_pool, return retval; } } + else { + /* No known directive found? Make a copy of what we have parsed. */ + newdir->directive = apr_pstrdup(p, cmd_name); + } + if (cmd_name[0] == '<') { if (cmd_name[1] != '/') { @@ -1111,6 +1227,9 @@ static const char *ap_build_config_sub(apr_pool_t *p, apr_pool_t *temp_pool, return retval; } +#define VARBUF_INIT_LEN 200 +#define VARBUF_MAX_LEN (16*1024*1024) + AP_DECLARE(const char *) ap_build_cont_config(apr_pool_t *p, apr_pool_t *temp_pool, cmd_parms *parms, @@ -1118,37 +1237,41 @@ AP_DECLARE(const char *) ap_build_cont_config(apr_pool_t *p, ap_directive_t **curr_parent, char *orig_directive) { - char *l; char *bracket; const char *retval; ap_directive_t *sub_tree = NULL; - - /* Since this function can be called recursively, allocate - * the temporary 8k string buffer from the temp_pool rather - * than the stack to avoid over-running a fixed length stack. - */ - l = apr_palloc(temp_pool, MAX_STRING_LEN); - - bracket = apr_pstrcat(p, orig_directive + 1, ">", NULL); - while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) { - if (!memcmp(l, "", NULL); + ap_varbuf_init(temp_pool, &vb, VARBUF_INIT_LEN); + + while ((rc = ap_varbuf_cfg_getline(&vb, parms->config_file, max_len)) + == APR_SUCCESS) { + if (!memcmp(vb.buf, "config_file, rc); *current = sub_tree; return NULL; @@ -1160,7 +1283,7 @@ static const char *ap_walk_config_sub(const ap_directive_t *current, { const command_rec *cmd; ap_mod_list *ml; - char *dir = apr_pstrdup(parms->pool, current->directive); + char *dir = apr_pstrdup(parms->temp_pool, current->directive); ap_str_tolower(dir); @@ -1168,11 +1291,20 @@ static const char *ap_walk_config_sub(const ap_directive_t *current, if (ml == NULL) { parms->err_directive = current; - return apr_pstrcat(parms->pool, "Invalid command '", - current->directive, - "', perhaps misspelled or defined by a module " - "not included in the server configuration", - NULL); + if (parms->override & NONFATAL_UNKNOWN) { + ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, parms->temp_pool, + APLOGNO(02296) "Unknown directive %s " + "perhaps misspelled or defined by a module " + "not included in the server configuration", dir); + return NULL; + } + else { + return apr_pstrcat(parms->pool, "Invalid command '", + current->directive, + "', perhaps misspelled or defined by a module " + "not included in the server configuration", + NULL); + } } for ( ; ml != NULL; ml = ml->next) { @@ -1194,7 +1326,7 @@ static const char *ap_walk_config_sub(const ap_directive_t *current, if (retval != NULL && strcmp(retval, DECLINE_CMD) != 0) { /* If the directive in error has already been set, don't * replace it. Otherwise, an error inside a container - * will be reported as occuring on the first line of the + * will be reported as occurring on the first line of the * container. */ if (!parms->err_directive) { @@ -1240,17 +1372,41 @@ AP_DECLARE(const char *) ap_build_config(cmd_parms *parms, { ap_directive_t *current = *conftree; ap_directive_t *curr_parent = NULL; - char *l = apr_palloc (temp_pool, MAX_STRING_LEN); const char *errmsg; + ap_directive_t **last_ptr = NULL; + apr_status_t rc; + struct ap_varbuf vb; + apr_size_t max_len = VARBUF_MAX_LEN; + if (p == temp_pool) + max_len = HUGE_STRING_LEN; /* lower limit for .htaccess */ + + ap_varbuf_init(temp_pool, &vb, VARBUF_INIT_LEN); if (current != NULL) { + /* If we have to traverse the whole tree again for every included + * config file, the required time grows as O(n^2) with the number of + * files. This can be a significant delay for large configurations. + * Therefore we cache a pointer to the last node. + */ + last_ptr = &(current->last); + + if (last_ptr && *last_ptr) { + current = *last_ptr; + } + while (current->next) { current = current->next; } + + if (last_ptr) { + /* update cached pointer to last node */ + *last_ptr = current; + } } - while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) { - errmsg = ap_build_config_sub(p, temp_pool, l, parms, + while ((rc = ap_varbuf_cfg_getline(&vb, parms->config_file, max_len)) + == APR_SUCCESS) { + errmsg = ap_build_config_sub(p, temp_pool, vb.buf, parms, ¤t, &curr_parent, conftree); if (errmsg != NULL) return errmsg; @@ -1263,6 +1419,9 @@ AP_DECLARE(const char *) ap_build_config(cmd_parms *parms, *conftree = current; } } + ap_varbuf_free(&vb); + if (rc != APR_EOF && rc != APR_SUCCESS) + return ap_pcfg_strerror(temp_pool, parms->config_file, rc); if (curr_parent != NULL) { errmsg = ""; @@ -1343,6 +1502,18 @@ AP_DECLARE_NONSTD(const char *) ap_set_flag_slot(cmd_parms *cmd, return NULL; } +AP_DECLARE_NONSTD(const char *) ap_set_flag_slot_char(cmd_parms *cmd, + void *struct_ptr_v, int arg) +{ + int offset = (int)(long)cmd->info; + char *struct_ptr = (char *)struct_ptr_v; + + *(struct_ptr + offset) = arg ? 1 : 0; + + return NULL; +} + + AP_DECLARE_NONSTD(const char *) ap_set_file_slot(cmd_parms *cmd, void *struct_ptr, const char *arg) { @@ -1400,7 +1571,7 @@ AP_DECLARE(void) ap_set_module_loglevel(apr_pool_t *pool, struct ap_logconf *l, */ static cmd_parms default_parms = -{NULL, 0, 0, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; +{NULL, 0, 0, NULL, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; AP_DECLARE(char *) ap_server_root_relative(apr_pool_t *p, const char *file) { @@ -1418,20 +1589,42 @@ AP_DECLARE(char *) ap_server_root_relative(apr_pool_t *p, const char *file) } } +AP_DECLARE(char *) ap_runtime_dir_relative(apr_pool_t *p, const char *file) +{ + char *newpath = NULL; + apr_status_t rv; + const char *runtime_dir = ap_runtime_dir ? ap_runtime_dir : ap_server_root_relative(p, DEFAULT_REL_RUNTIMEDIR); + + rv = apr_filepath_merge(&newpath, runtime_dir, file, + APR_FILEPATH_TRUENAME, p); + if (newpath && (rv == APR_SUCCESS || APR_STATUS_IS_EPATHWILD(rv) + || APR_STATUS_IS_ENOENT(rv) + || APR_STATUS_IS_ENOTDIR(rv))) { + return newpath; + } + else { + return NULL; + } +} + + AP_DECLARE(const char *) ap_soak_end_container(cmd_parms *cmd, char *directive) { - char l[MAX_STRING_LEN]; + struct ap_varbuf vb; const char *args; char *cmd_name; + apr_status_t rc; + apr_size_t max_len = VARBUF_MAX_LEN; + if (cmd->pool == cmd->temp_pool) + max_len = HUGE_STRING_LEN; /* lower limit for .htaccess */ - while(!(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) { -#if RESOLVE_ENV_PER_TOKEN - args = l; -#else - args = ap_resolve_env(cmd->temp_pool, l); -#endif + ap_varbuf_init(cmd->temp_pool, &vb, VARBUF_INIT_LEN); + + while ((rc = ap_varbuf_cfg_getline(&vb, cmd->config_file, max_len)) + == APR_SUCCESS) { + args = vb.buf; - cmd_name = ap_getword_conf(cmd->pool, &args); + cmd_name = ap_getword_conf(cmd->temp_pool, &args); if (cmd_name[0] == '<') { if (cmd_name[1] == '/') { cmd_name[strlen(cmd_name) - 1] = '\0'; @@ -1442,6 +1635,7 @@ AP_DECLARE(const char *) ap_soak_end_container(cmd_parms *cmd, char *directive) cmd_name, ">", NULL); } + ap_varbuf_free(&vb); return NULL; /* found end of container */ } else { @@ -1457,6 +1651,8 @@ AP_DECLARE(const char *) ap_soak_end_container(cmd_parms *cmd, char *directive) } } } + if (rc != APR_EOF && rc != APR_SUCCESS) + return ap_pcfg_strerror(cmd->temp_pool, cmd->config_file, rc); return apr_pstrcat(cmd->pool, "Expected before end of configuration", @@ -1471,7 +1667,7 @@ static const char *execute_now(char *cmd_line, const char *args, { const command_rec *cmd; ap_mod_list *ml; - char *dir = apr_pstrdup(parms->pool, cmd_line); + char *dir = apr_pstrdup(parms->temp_pool, cmd_line); ap_str_tolower(dir); @@ -1516,31 +1712,31 @@ typedef struct { /* arr_elts_getstr() returns the next line from the string array. */ -static void *arr_elts_getstr(void *buf, size_t bufsiz, void *param) +static apr_status_t arr_elts_getstr(void *buf, apr_size_t bufsiz, void *param) { arr_elts_param_t *arr_param = (arr_elts_param_t *)param; + char *elt; /* End of array reached? */ if (++arr_param->curr_idx > arr_param->array->nelts) - return NULL; + return APR_EOF; /* return the line */ - apr_cpystrn(buf, - ((char **)arr_param->array->elts)[arr_param->curr_idx - 1], - bufsiz); - - return buf; + elt = ((char **)arr_param->array->elts)[arr_param->curr_idx - 1]; + if (apr_cpystrn(buf, elt, bufsiz) - (char *)buf >= bufsiz - 1) + return APR_ENOSPC; + return APR_SUCCESS; } /* arr_elts_close(): dummy close routine (makes sure no more lines can be read) */ -static int arr_elts_close(void *param) +static apr_status_t arr_elts_close(void *param) { arr_elts_param_t *arr_param = (arr_elts_param_t *)param; arr_param->curr_idx = arr_param->array->nelts; - return 0; + return APR_SUCCESS; } static const char *process_command_config(server_rec *s, @@ -1594,6 +1790,54 @@ static int fname_alphasort(const void *fn1, const void *fn2) return strcmp(f1->fname,f2->fname); } +/** + * Used by -D DUMP_INCLUDES to output the config file "tree". + */ +static void dump_config_name(const char *fname, apr_pool_t *p) +{ + unsigned i, recursion, line_number; + void *data; + apr_file_t *out = NULL; + + apr_file_open_stdout(&out, p); + + /* ap_include_sentinel is defined by the core Include directive; use it to + * figure out how deep in the stack we are. + */ + apr_pool_userdata_get(&data, "ap_include_sentinel", p); + + if (data) { + recursion = *(unsigned *)data; + } else { + recursion = 0; + } + + /* Indent once for each level. */ + for (i = 0; i < (recursion + 1); ++i) { + apr_file_printf(out, " "); + } + + /* ap_include_lineno is similarly defined to tell us where in the last + * config file we were. + */ + apr_pool_userdata_get(&data, "ap_include_lineno", p); + + if (data) { + line_number = *(unsigned *)data; + } else { + line_number = 0; + } + + /* Print the line number and the name of the parsed file. */ + if (line_number > 0) { + apr_file_printf(out, "(%u)", line_number); + } else { + apr_file_printf(out, "(*)"); + } + + apr_file_printf(out, " %s\n", fname); +} + AP_DECLARE(const char *) ap_process_resource_config(server_rec *s, const char *fname, ap_directive_t **conftree, @@ -1614,9 +1858,12 @@ AP_DECLARE(const char *) ap_process_resource_config(server_rec *s, rv = ap_pcfg_openfile(&cfp, p, fname); if (rv != APR_SUCCESS) { - char errmsg[120]; - return apr_psprintf(p, "Could not open configuration file %s: %s", - fname, apr_strerror(rv, errmsg, sizeof errmsg)); + return apr_psprintf(p, "Could not open configuration file %s: %pm", + fname, &rv); + } + + if (ap_exists_config_define("DUMP_INCLUDES")) { + dump_config_name(fname, p); } parms.config_file = cfp; @@ -1624,9 +1871,12 @@ AP_DECLARE(const char *) ap_process_resource_config(server_rec *s, ap_cfg_closefile(cfp); if (error) { - return apr_psprintf(p, "Syntax error on line %d of %s: %s", - parms.err_directive->line_num, - parms.err_directive->filename, error); + if (parms.err_directive) + return apr_psprintf(p, "Syntax error on line %d of %s: %s", + parms.err_directive->line_num, + parms.err_directive->filename, error); + else + return error; } return NULL; @@ -1643,13 +1893,13 @@ static const char *process_resource_config_nofnmatch(server_rec *s, const char *error; apr_status_t rv; - if (ap_is_directory(p, fname)) { + if (ap_is_directory(ptemp, fname)) { apr_dir_t *dirp; apr_finfo_t dirent; int current; apr_array_header_t *candidates = NULL; fnames *fnew; - char *path = apr_pstrdup(p, fname); + char *path = apr_pstrdup(ptemp, fname); if (++depth > AP_MAX_INCLUDE_DIR_DEPTH) { return apr_psprintf(p, "Directory %s exceeds the maximum include " @@ -1663,20 +1913,19 @@ static const char *process_resource_config_nofnmatch(server_rec *s, * entries here and store 'em away. Recall we need full pathnames * for this. */ - rv = apr_dir_open(&dirp, path, p); + rv = apr_dir_open(&dirp, path, ptemp); if (rv != APR_SUCCESS) { - char errmsg[120]; - return apr_psprintf(p, "Could not open config directory %s: %s", - path, apr_strerror(rv, errmsg, sizeof errmsg)); + return apr_psprintf(p, "Could not open config directory %s: %pm", + path, &rv); } - candidates = apr_array_make(p, 1, sizeof(fnames)); + candidates = apr_array_make(ptemp, 1, sizeof(fnames)); while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) { /* strip out '.' and '..' */ if (strcmp(dirent.name, ".") && strcmp(dirent.name, "..")) { fnew = (fnames *) apr_array_push(candidates); - fnew->fname = ap_make_full_path(p, path, dirent.name); + fnew->fname = ap_make_full_path(ptemp, path, dirent.name); } } @@ -1726,7 +1975,7 @@ static const char *process_resource_config_fnmatch(server_rec *s, /* find the first part of the filename */ rest = ap_strchr_c(fname, '/'); if (rest) { - fname = apr_pstrndup(ptemp, fname, rest - fname); + fname = apr_pstrmemdup(ptemp, fname, rest - fname); rest++; } @@ -1752,9 +2001,8 @@ static const char *process_resource_config_fnmatch(server_rec *s, */ rv = apr_dir_open(&dirp, path, ptemp); if (rv != APR_SUCCESS) { - char errmsg[120]; - return apr_psprintf(p, "Could not open config directory %s: %s", - path, apr_strerror(rv, errmsg, sizeof errmsg)); + return apr_psprintf(p, "Could not open config directory %s: %pm", + path, &rv); } candidates = apr_array_make(ptemp, 1, sizeof(fnames)); @@ -1828,15 +2076,15 @@ AP_DECLARE(const char *) ap_process_fnmatch_configs(server_rec *s, /* don't require conf/httpd.conf if we have a -C or -c switch */ if ((ap_server_pre_read_config->nelts || ap_server_post_read_config->nelts) - && !(strcmp(fname, ap_server_root_relative(p, SERVER_CONFIG_FILE)))) { + && !(strcmp(fname, ap_server_root_relative(ptemp, SERVER_CONFIG_FILE)))) { apr_finfo_t finfo; - if (apr_stat(&finfo, fname, APR_FINFO_LINK | APR_FINFO_TYPE, p) != APR_SUCCESS) + if (apr_stat(&finfo, fname, APR_FINFO_LINK | APR_FINFO_TYPE, ptemp) != APR_SUCCESS) return NULL; } if (!apr_fnmatch_test(fname)) { - return ap_process_resource_config(s, fname, conftree, p, ptemp); + return process_resource_config_nofnmatch(s, fname, conftree, p, ptemp, 0, optional); } else { apr_status_t status; @@ -1856,10 +2104,7 @@ AP_DECLARE(const char *) ap_process_fnmatch_configs(server_rec *s, /* walk the filepath */ return process_resource_config_fnmatch(s, rootpath, filepath, conftree, p, ptemp, 0, optional); - } - - return NULL; } AP_DECLARE(int) ap_process_config_tree(server_rec *s, @@ -1880,26 +2125,35 @@ AP_DECLARE(int) ap_process_config_tree(server_rec *s, errmsg = ap_walk_config(conftree, &parms, s->lookup_defaults); if (errmsg) { - ap_log_perror(APLOG_MARK, APLOG_STARTUP, 0, p, - "Syntax error on line %d of %s:", - parms.err_directive->line_num, - parms.err_directive->filename); - ap_log_perror(APLOG_MARK, APLOG_STARTUP, 0, p, - "%s", errmsg); + if (parms.err_directive) + ap_log_perror(APLOG_MARK, APLOG_STARTUP, 0, p, APLOGNO(00526) + "Syntax error on line %d of %s:", + parms.err_directive->line_num, + parms.err_directive->filename); + ap_log_perror(APLOG_MARK, APLOG_STARTUP, 0, p, "%s", errmsg); return HTTP_INTERNAL_SERVER_ERROR; } return OK; } +apr_status_t ap_open_htaccess(request_rec *r, const char *dir_name, + const char *access_name, + ap_configfile_t **conffile, + const char **full_name) +{ + *full_name = ap_make_full_path(r->pool, dir_name, access_name); + return ap_pcfg_openfile(conffile, r->pool, *full_name); +} + AP_CORE_DECLARE(int) ap_parse_htaccess(ap_conf_vector_t **result, request_rec *r, int override, - int override_opts, - const char *d, const char *access_name) + int override_opts, apr_table_t *override_list, + const char *d, const char *access_names) { ap_configfile_t *f = NULL; cmd_parms parms; - char *filename = NULL; + const char *filename; const struct htaccess_result *cache; struct htaccess_result *new; ap_conf_vector_t *dc = NULL; @@ -1916,21 +2170,18 @@ AP_CORE_DECLARE(int) ap_parse_htaccess(ap_conf_vector_t **result, parms = default_parms; parms.override = override; parms.override_opts = override_opts; + parms.override_list = override_list; parms.pool = r->pool; parms.temp_pool = r->pool; parms.server = r->server; parms.path = apr_pstrdup(r->pool, d); /* loop through the access names and find the first one */ - while (access_name[0]) { - /* AFAICT; there is no use of the actual 'filename' against - * any canonicalization, so we will simply take the given - * name, ignoring case sensitivity and aliases - */ - filename = ap_make_full_path(r->pool, d, - ap_getword_conf(r->pool, &access_name)); - status = ap_pcfg_openfile(&f, r->pool, filename); + while (access_names[0]) { + const char *access_name = ap_getword_conf(r->pool, &access_names); + filename = NULL; + status = ap_run_open_htaccess(r, d, access_name, &f, &filename); if (status == APR_SUCCESS) { const char *errmsg; ap_directive_t *temptree = NULL; @@ -1956,10 +2207,11 @@ AP_CORE_DECLARE(int) ap_parse_htaccess(ap_conf_vector_t **result, else { if (!APR_STATUS_IS_ENOENT(status) && !APR_STATUS_IS_ENOTDIR(status)) { - ap_log_rerror(APLOG_MARK, APLOG_CRIT, status, r, + ap_log_rerror(APLOG_MARK, APLOG_CRIT, status, r, APLOGNO(00529) "%s pcfg_openfile: unable to check htaccess file, " - "ensure it is readable", - filename); + "ensure it is readable and that '%s' " + "is executable", + filename, d); apr_table_setn(r->notes, "error-notes", "Server unable to read htaccess file, denying " "access to be safe"); @@ -2000,7 +2252,7 @@ AP_CORE_DECLARE(const char *) ap_init_virtual_host(apr_pool_t *p, s->keep_alive = -1; s->keep_alive_max = -1; s->error_log = main_server->error_log; - s->log.level = main_server->log.level; + s->log.level = APLOG_UNSET; s->log.module_levels = NULL; /* useful default, otherwise we get a port of 0 on redirects */ s->port = main_server->port; @@ -2039,25 +2291,25 @@ AP_DECLARE(struct ap_logconf *) ap_new_log_config(apr_pool_t *p, return l; } -AP_DECLARE(void) ap_merge_log_config(const struct ap_logconf *old, - struct ap_logconf *new) +AP_DECLARE(void) ap_merge_log_config(const struct ap_logconf *old_conf, + struct ap_logconf *new_conf) { - if (new->level != APLOG_UNSET) { + if (new_conf->level != APLOG_UNSET) { /* Setting the main loglevel resets all per-module log levels. * I.e. if new->level has been set, we must ignore old->module_levels. */ return; } - new->level = old->level; - if (new->module_levels == NULL) { - new->module_levels = old->module_levels; + new_conf->level = old_conf->level; + if (new_conf->module_levels == NULL) { + new_conf->module_levels = old_conf->module_levels; } - else if (old->module_levels != NULL) { + else if (old_conf->module_levels != NULL) { int i; for (i = 0; i < conf_vector_length; i++) { - if (new->module_levels[i] == APLOG_UNSET) - new->module_levels[i] = old->module_levels[i]; + if (new_conf->module_levels[i] == APLOG_UNSET) + new_conf->module_levels[i] = old_conf->module_levels[i]; } } } @@ -2065,8 +2317,8 @@ AP_DECLARE(void) ap_merge_log_config(const struct ap_logconf *old, AP_DECLARE(void) ap_fixup_virtual_hosts(apr_pool_t *p, server_rec *main_server) { server_rec *virt; - core_dir_config *dconf = ap_get_module_config(main_server->lookup_defaults, - &core_module); + core_dir_config *dconf = + ap_get_core_module_config(main_server->lookup_defaults); dconf->log = &main_server->log; for (virt = main_server->next; virt; virt = virt->next) { @@ -2094,7 +2346,7 @@ AP_DECLARE(void) ap_fixup_virtual_hosts(apr_pool_t *p, server_rec *main_server) ap_merge_log_config(&main_server->log, &virt->log); - dconf = ap_get_module_config(virt->lookup_defaults, &core_module); + dconf = ap_get_core_module_config(virt->lookup_defaults); dconf->log = &virt->log; /* XXX: this is really something that should be dealt with by a @@ -2143,8 +2395,13 @@ static server_rec *init_server_config(process_rec *process, apr_pool_t *p) /* NOT virtual host; don't match any real network interface */ rv = apr_sockaddr_info_get(&s->addrs->host_addr, - NULL, APR_INET, 0, 0, p); - ap_assert(rv == APR_SUCCESS); /* otherwise: bug or no storage */ + NULL, APR_UNSPEC, 0, 0, p); + if (rv != APR_SUCCESS) { + /* should we test here for rv being an EAIERR? */ + ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, rv, NULL, APLOGNO(00530) + "initialisation: bug or getaddrinfo fail"); + return NULL; + } s->addrs->host_port = 0; /* matches any port */ s->addrs->virthost = ""; /* must be non-NULL */ @@ -2159,10 +2416,36 @@ static server_rec *init_server_config(process_rec *process, apr_pool_t *p) static apr_status_t reset_conf_vector_length(void *dummy) { + reserved_module_slots = 0; conf_vector_length = max_modules; return APR_SUCCESS; } +static int conf_vector_length_pre_config(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp) +{ + /* + * We have loaded all modules that are loaded by EXEC_ON_READ directives. + * From now on we reduce the size of the config vectors to what we need, + * plus what has been reserved (e.g. by mod_perl) for additional modules + * loaded later on. + * If max_modules is too small, ap_add_module() will abort. + */ + if (total_modules + reserved_module_slots < max_modules) { + conf_vector_length = total_modules + reserved_module_slots; + } + apr_pool_cleanup_register(pconf, NULL, reset_conf_vector_length, + apr_pool_cleanup_null); + return OK; +} + + +AP_CORE_DECLARE(void) ap_register_config_hooks(apr_pool_t *p) +{ + ap_hook_pre_config(conf_vector_length_pre_config, NULL, NULL, + APR_HOOK_REALLY_LAST); +} + AP_DECLARE(server_rec*) ap_read_config(process_rec *process, apr_pool_t *ptemp, const char *filename, ap_directive_t **conftree) @@ -2170,9 +2453,22 @@ AP_DECLARE(server_rec*) ap_read_config(process_rec *process, apr_pool_t *ptemp, const char *confname, *error; apr_pool_t *p = process->pconf; server_rec *s = init_server_config(process, p); + if (s == NULL) { + return s; + } init_config_globals(p); + if (ap_exists_config_define("DUMP_INCLUDES")) { + apr_file_t *out = NULL; + apr_file_open_stdout(&out, p); + + /* Included files will be dumped as the config is walked; print a + * header. + */ + apr_file_printf(out, "Included configuration files:\n"); + } + /* All server-wide config files now have the SAME syntax... */ error = process_command_config(s, ap_server_pre_read_config, conftree, p, ptemp); @@ -2189,7 +2485,7 @@ AP_DECLARE(server_rec*) ap_read_config(process_rec *process, apr_pool_t *ptemp, if (!confname) { ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, - APR_EBADPATH, NULL, "Invalid config file path %s", + APR_EBADPATH, NULL, APLOGNO(00532) "Invalid config file path %s", filename); return NULL; } @@ -2201,13 +2497,12 @@ AP_DECLARE(server_rec*) ap_read_config(process_rec *process, apr_pool_t *ptemp, return NULL; } - /* - * We have loaded the dynamic modules. From now on we know exactly how - * long the config vectors need to be. - */ - conf_vector_length = total_modules; - apr_pool_cleanup_register(p, NULL, reset_conf_vector_length, - apr_pool_cleanup_null); + error = ap_check_mpm(); + if (error) { + ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, 0, NULL, APLOGNO(00534) + "%s: Configuration error: %s", ap_server_argv0, error); + return NULL; + } error = process_command_config(s, ap_server_post_read_config, conftree, p, ptemp); @@ -2271,10 +2566,10 @@ static void show_overrides(const command_rec *pc, module *pm) printf("anywhere"); } else if (pc->req_override & RSRC_CONF) { - printf("only outside , or "); + printf("only outside , , , or "); } else { - printf("only inside , or "); + printf("only inside , , , or "); } /* Warn if the directive is allowed inside or .htaccess @@ -2379,3 +2674,26 @@ AP_DECLARE(void *) ap_retained_data_create(const char *key, apr_size_t size) apr_pool_userdata_set((const void *)retained, key, apr_pool_cleanup_null, ap_pglobal); return retained; } + +static int count_directives_sub(const char *directive, ap_directive_t *current) +{ + int count = 0; + while (current != NULL) { + if (current->first_child != NULL) + count += count_directives_sub(directive, current->first_child); + if (strcasecmp(current->directive, directive) == 0) + count++; + current = current->next; + } + return count; +} + +AP_DECLARE(void) ap_reserve_module_slots(int count) +{ + reserved_module_slots += count; +} + +AP_DECLARE(void) ap_reserve_module_slots_directive(const char *directive) +{ + ap_reserve_module_slots(count_directives_sub(directive, ap_conftree)); +}