/src/httpd/server/config.c
Line | Count | Source (jump to first uncovered line) |
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 | | /* |
18 | | * http_config.c: once was auxiliary functions for reading httpd's config |
19 | | * file and converting filenames into a namespace |
20 | | * |
21 | | * Rob McCool |
22 | | * |
23 | | * Wall-to-wall rewrite for Apache... commands which are part of the |
24 | | * server core can now be found next door in "http_core.c". Now contains |
25 | | * general command loop, and functions which do bookkeeping for the new |
26 | | * Apache config stuff (modules and configuration vectors). |
27 | | * |
28 | | * rst |
29 | | * |
30 | | */ |
31 | | |
32 | | #include "apr.h" |
33 | | #include "apr_strings.h" |
34 | | #include "apr_portable.h" |
35 | | #include "apr_file_io.h" |
36 | | #include "apr_fnmatch.h" |
37 | | |
38 | | #define APR_WANT_STDIO |
39 | | #define APR_WANT_STRFUNC |
40 | | #include "apr_want.h" |
41 | | |
42 | | #include "ap_config.h" |
43 | | #include "httpd.h" |
44 | | #include "http_config.h" |
45 | | #include "http_protocol.h" |
46 | | #include "http_core.h" |
47 | | #include "http_log.h" /* for errors in parse_htaccess */ |
48 | | #include "http_request.h" /* for default_handler (see invoke_handler) */ |
49 | | #include "http_main.h" |
50 | | #include "http_vhost.h" |
51 | | #include "util_cfgtree.h" |
52 | | #include "util_varbuf.h" |
53 | | #include "mpm_common.h" |
54 | | |
55 | 0 | #define APLOG_UNSET (APLOG_NO_MODULE - 1) |
56 | | /* we know core's module_index is 0 */ |
57 | | #undef APLOG_MODULE_INDEX |
58 | 0 | #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX |
59 | | |
60 | | AP_DECLARE_DATA const char *ap_server_argv0 = NULL; |
61 | | AP_DECLARE_DATA const char *ap_server_root = NULL; |
62 | | AP_DECLARE_DATA server_rec *ap_server_conf = NULL; |
63 | | AP_DECLARE_DATA apr_pool_t *ap_pglobal = NULL; |
64 | | |
65 | | AP_DECLARE_DATA apr_array_header_t *ap_server_pre_read_config = NULL; |
66 | | AP_DECLARE_DATA apr_array_header_t *ap_server_post_read_config = NULL; |
67 | | AP_DECLARE_DATA apr_array_header_t *ap_server_config_defines = NULL; |
68 | | |
69 | | AP_DECLARE_DATA ap_directive_t *ap_conftree = NULL; |
70 | | |
71 | | APR_HOOK_STRUCT( |
72 | | APR_HOOK_LINK(header_parser) |
73 | | APR_HOOK_LINK(pre_config) |
74 | | APR_HOOK_LINK(check_config) |
75 | | APR_HOOK_LINK(post_config) |
76 | | APR_HOOK_LINK(open_logs) |
77 | | APR_HOOK_LINK(child_init) |
78 | | APR_HOOK_LINK(handler) |
79 | | APR_HOOK_LINK(quick_handler) |
80 | | APR_HOOK_LINK(optional_fn_retrieve) |
81 | | APR_HOOK_LINK(test_config) |
82 | | APR_HOOK_LINK(open_htaccess) |
83 | | ) |
84 | | |
85 | | AP_IMPLEMENT_HOOK_RUN_ALL(int, header_parser, |
86 | | (request_rec *r), (r), OK, DECLINED) |
87 | | |
88 | | AP_IMPLEMENT_HOOK_RUN_ALL(int, pre_config, |
89 | | (apr_pool_t *pconf, apr_pool_t *plog, |
90 | | apr_pool_t *ptemp), |
91 | | (pconf, plog, ptemp), OK, DECLINED) |
92 | | |
93 | | AP_IMPLEMENT_HOOK_RUN_ALL(int, check_config, |
94 | | (apr_pool_t *pconf, apr_pool_t *plog, |
95 | | apr_pool_t *ptemp, server_rec *s), |
96 | | (pconf, plog, ptemp, s), OK, DECLINED) |
97 | | |
98 | | AP_IMPLEMENT_HOOK_VOID(test_config, |
99 | | (apr_pool_t *pconf, server_rec *s), |
100 | | (pconf, s)) |
101 | | |
102 | | AP_IMPLEMENT_HOOK_RUN_ALL(int, post_config, |
103 | | (apr_pool_t *pconf, apr_pool_t *plog, |
104 | | apr_pool_t *ptemp, server_rec *s), |
105 | | (pconf, plog, ptemp, s), OK, DECLINED) |
106 | | |
107 | | /* During the course of debugging I expanded this macro out, so |
108 | | * rather than remove all the useful information there is in the |
109 | | * following lines, I'm going to leave it here in case anyone |
110 | | * else finds it useful. |
111 | | * |
112 | | * Ben has looked at it and thinks it correct :) |
113 | | * |
114 | | AP_DECLARE(int) ap_hook_post_config(ap_HOOK_post_config_t *pf, |
115 | | const char * const *aszPre, |
116 | | const char * const *aszSucc, |
117 | | int nOrder) |
118 | | { |
119 | | ap_LINK_post_config_t *pHook; |
120 | | |
121 | | if (!_hooks.link_post_config) { |
122 | | _hooks.link_post_config = apr_array_make(apr_hook_global_pool, 1, |
123 | | sizeof(ap_LINK_post_config_t)); |
124 | | apr_hook_sort_register("post_config", &_hooks.link_post_config); |
125 | | } |
126 | | |
127 | | pHook = apr_array_push(_hooks.link_post_config); |
128 | | pHook->pFunc = pf; |
129 | | pHook->aszPredecessors = aszPre; |
130 | | pHook->aszSuccessors = aszSucc; |
131 | | pHook->nOrder = nOrder; |
132 | | pHook->szName = apr_hook_debug_current; |
133 | | |
134 | | if (apr_hook_debug_enabled) |
135 | | apr_hook_debug_show("post_config", aszPre, aszSucc); |
136 | | } |
137 | | |
138 | | AP_DECLARE(apr_array_header_t *) ap_hook_get_post_config(void) |
139 | | { |
140 | | return _hooks.link_post_config; |
141 | | } |
142 | | |
143 | | AP_DECLARE(int) ap_run_post_config(apr_pool_t *pconf, |
144 | | apr_pool_t *plog, |
145 | | apr_pool_t *ptemp, |
146 | | server_rec *s) |
147 | | { |
148 | | ap_LINK_post_config_t *pHook; |
149 | | int n; |
150 | | |
151 | | if (!_hooks.link_post_config) |
152 | | return; |
153 | | |
154 | | pHook = (ap_LINK_post_config_t *)_hooks.link_post_config->elts; |
155 | | for (n = 0; n < _hooks.link_post_config->nelts; ++n) |
156 | | pHook[n].pFunc (pconf, plog, ptemp, s); |
157 | | } |
158 | | */ |
159 | | |
160 | | AP_IMPLEMENT_HOOK_RUN_ALL(int, open_logs, |
161 | | (apr_pool_t *pconf, apr_pool_t *plog, |
162 | | apr_pool_t *ptemp, server_rec *s), |
163 | | (pconf, plog, ptemp, s), OK, DECLINED) |
164 | | |
165 | | AP_IMPLEMENT_HOOK_VOID(child_init, |
166 | | (apr_pool_t *pchild, server_rec *s), |
167 | | (pchild, s)) |
168 | | |
169 | | AP_IMPLEMENT_HOOK_RUN_FIRST(int, handler, (request_rec *r), |
170 | | (r), DECLINED) |
171 | | |
172 | | AP_IMPLEMENT_HOOK_RUN_FIRST(int, quick_handler, (request_rec *r, int lookup), |
173 | | (r, lookup), DECLINED) |
174 | | |
175 | | AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, open_htaccess, |
176 | | (request_rec *r, const char *dir_name, const char *access_name, |
177 | | ap_configfile_t **conffile, const char **full_name), |
178 | | (r, dir_name, access_name, conffile, full_name), |
179 | | AP_DECLINED) |
180 | | |
181 | | /* hooks with no args are implemented last, after disabling APR hook probes */ |
182 | | #if defined(APR_HOOK_PROBES_ENABLED) |
183 | | #undef APR_HOOK_PROBES_ENABLED |
184 | | #undef APR_HOOK_PROBE_ENTRY |
185 | | #define APR_HOOK_PROBE_ENTRY(ud,ns,name,args) |
186 | | #undef APR_HOOK_PROBE_RETURN |
187 | | #define APR_HOOK_PROBE_RETURN(ud,ns,name,rv,args) |
188 | | #undef APR_HOOK_PROBE_INVOKE |
189 | | #define APR_HOOK_PROBE_INVOKE(ud,ns,name,src,args) |
190 | | #undef APR_HOOK_PROBE_COMPLETE |
191 | | #define APR_HOOK_PROBE_COMPLETE(ud,ns,name,src,rv,args) |
192 | | #undef APR_HOOK_INT_DCL_UD |
193 | | #define APR_HOOK_INT_DCL_UD |
194 | | #endif |
195 | | AP_IMPLEMENT_HOOK_VOID(optional_fn_retrieve, (void), ()) |
196 | | |
197 | | /**************************************************************** |
198 | | * |
199 | | * We begin with the functions which deal with the linked list |
200 | | * of modules which control just about all of the server operation. |
201 | | */ |
202 | | |
203 | | /* total_modules is the number of modules that have been linked |
204 | | * into the server. |
205 | | */ |
206 | | static int total_modules = 0; |
207 | | |
208 | | /* dynamic_modules is the number of modules that have been added |
209 | | * after the pre-loaded ones have been set up. It shouldn't be larger |
210 | | * than DYNAMIC_MODULE_LIMIT. |
211 | | */ |
212 | | static int dynamic_modules = 0; |
213 | | |
214 | | /* The maximum possible value for total_modules, i.e. number of static |
215 | | * modules plus DYNAMIC_MODULE_LIMIT. |
216 | | */ |
217 | | static int max_modules = 0; |
218 | | |
219 | | /* The number of elements we need to alloc for config vectors. Before loading |
220 | | * of dynamic modules, we must be liberal and set this to max_modules. After |
221 | | * loading of dynamic modules, we can trim it down to total_modules. On |
222 | | * restart, reset to max_modules. |
223 | | */ |
224 | | static int conf_vector_length = 0; |
225 | | |
226 | | static int reserved_module_slots = 0; |
227 | | |
228 | | AP_DECLARE_DATA module *ap_top_module = NULL; |
229 | | AP_DECLARE_DATA module **ap_loaded_modules=NULL; |
230 | | |
231 | | static apr_hash_t *ap_config_hash = NULL; |
232 | | |
233 | | /* a list of the module symbol names with the trailing "_module"removed */ |
234 | | static char **ap_module_short_names = NULL; |
235 | | |
236 | | typedef int (*handler_func)(request_rec *); |
237 | | typedef void *(*dir_maker_func)(apr_pool_t *, char *); |
238 | | typedef void *(*merger_func)(apr_pool_t *, void *, void *); |
239 | | |
240 | | /* A list of the merge_dir_config functions of all loaded modules, sorted |
241 | | * by module_index. |
242 | | * Using this list in ap_merge_per_dir_configs() is faster than following |
243 | | * the module->next linked list because of better memory locality (resulting |
244 | | * in better cache usage). |
245 | | */ |
246 | | static merger_func *merger_func_cache; |
247 | | |
248 | | /* maximum nesting level for config directories */ |
249 | | #ifndef AP_MAX_INCLUDE_DIR_DEPTH |
250 | | #define AP_MAX_INCLUDE_DIR_DEPTH (128) |
251 | | #endif |
252 | | |
253 | | /* Dealing with config vectors. These are associated with per-directory, |
254 | | * per-server, and per-request configuration, and have a void* pointer for |
255 | | * each modules. The nature of the structure pointed to is private to the |
256 | | * module in question... the core doesn't (and can't) know. However, there |
257 | | * are defined interfaces which allow it to create instances of its private |
258 | | * per-directory and per-server structures, and to merge the per-directory |
259 | | * structures of a directory and its subdirectory (producing a new one in |
260 | | * which the defaults applying to the base directory have been properly |
261 | | * overridden). |
262 | | */ |
263 | | |
264 | | static ap_conf_vector_t *create_empty_config(apr_pool_t *p) |
265 | 527 | { |
266 | 527 | void *conf_vector = apr_pcalloc(p, sizeof(void *) * conf_vector_length); |
267 | 527 | return conf_vector; |
268 | 527 | } |
269 | | |
270 | | static ap_conf_vector_t *create_default_per_dir_config(apr_pool_t *p) |
271 | 0 | { |
272 | 0 | void **conf_vector = apr_pcalloc(p, sizeof(void *) * conf_vector_length); |
273 | 0 | module *modp; |
274 | |
|
275 | 0 | for (modp = ap_top_module; modp; modp = modp->next) { |
276 | 0 | dir_maker_func df = modp->create_dir_config; |
277 | |
|
278 | 0 | if (df) |
279 | 0 | conf_vector[modp->module_index] = (*df)(p, NULL); |
280 | 0 | } |
281 | |
|
282 | 0 | return (ap_conf_vector_t *)conf_vector; |
283 | 0 | } |
284 | | |
285 | | AP_CORE_DECLARE(ap_conf_vector_t *) ap_merge_per_dir_configs(apr_pool_t *p, |
286 | | ap_conf_vector_t *base, |
287 | | ap_conf_vector_t *new_conf) |
288 | 0 | { |
289 | 0 | void **conf_vector = apr_palloc(p, sizeof(void *) * conf_vector_length); |
290 | 0 | void **base_vector = (void **)base; |
291 | 0 | void **new_vector = (void **)new_conf; |
292 | 0 | int i; |
293 | |
|
294 | 0 | for (i = 0; i < total_modules; i++) { |
295 | 0 | if (!new_vector[i]) { |
296 | 0 | conf_vector[i] = base_vector[i]; |
297 | 0 | } |
298 | 0 | else { |
299 | 0 | const merger_func df = merger_func_cache[i]; |
300 | 0 | if (df && base_vector[i]) { |
301 | 0 | conf_vector[i] = (*df)(p, base_vector[i], new_vector[i]); |
302 | 0 | } |
303 | 0 | else |
304 | 0 | conf_vector[i] = new_vector[i]; |
305 | 0 | } |
306 | 0 | } |
307 | |
|
308 | 0 | return (ap_conf_vector_t *)conf_vector; |
309 | 0 | } |
310 | | |
311 | | static ap_conf_vector_t *create_server_config(apr_pool_t *p, server_rec *s) |
312 | 0 | { |
313 | 0 | void **conf_vector = apr_pcalloc(p, sizeof(void *) * conf_vector_length); |
314 | 0 | module *modp; |
315 | |
|
316 | 0 | for (modp = ap_top_module; modp; modp = modp->next) { |
317 | 0 | if (modp->create_server_config) |
318 | 0 | conf_vector[modp->module_index] = (*modp->create_server_config)(p, s); |
319 | 0 | } |
320 | |
|
321 | 0 | return (ap_conf_vector_t *)conf_vector; |
322 | 0 | } |
323 | | |
324 | | static void merge_server_configs(apr_pool_t *p, ap_conf_vector_t *base, |
325 | | server_rec *virt) |
326 | 0 | { |
327 | | /* Can reuse the 'virt' vector for the spine of it, since we don't |
328 | | * have to deal with the moral equivalent of .htaccess files here... |
329 | | */ |
330 | |
|
331 | 0 | void **base_vector = (void **)base; |
332 | 0 | void **virt_vector = (void **)virt->module_config; |
333 | 0 | module *modp; |
334 | |
|
335 | 0 | for (modp = ap_top_module; modp; modp = modp->next) { |
336 | 0 | merger_func df = modp->merge_server_config; |
337 | 0 | int i = modp->module_index; |
338 | |
|
339 | 0 | if (!virt_vector[i]) { |
340 | 0 | if (df && modp->create_server_config |
341 | 0 | && (ap_get_module_flags(modp) & |
342 | 0 | AP_MODULE_FLAG_ALWAYS_MERGE)) { |
343 | 0 | virt_vector[i] = (*modp->create_server_config)(p, virt); |
344 | 0 | } |
345 | 0 | else { |
346 | 0 | virt_vector[i] = base_vector[i]; |
347 | 0 | df = NULL; |
348 | 0 | } |
349 | 0 | } |
350 | 0 | if (df) { |
351 | 0 | virt_vector[i] = (*df)(p, base_vector[i], virt_vector[i]); |
352 | 0 | } |
353 | 0 | } |
354 | 0 | } |
355 | | |
356 | | AP_CORE_DECLARE(ap_conf_vector_t *) ap_create_request_config(apr_pool_t *p) |
357 | 527 | { |
358 | 527 | return create_empty_config(p); |
359 | 527 | } |
360 | | |
361 | | AP_CORE_DECLARE(ap_conf_vector_t *) ap_create_conn_config(apr_pool_t *p) |
362 | 0 | { |
363 | 0 | return create_empty_config(p); |
364 | 0 | } |
365 | | |
366 | | AP_CORE_DECLARE(ap_conf_vector_t *) ap_create_per_dir_config(apr_pool_t *p) |
367 | 0 | { |
368 | 0 | return create_empty_config(p); |
369 | 0 | } |
370 | | |
371 | | /* Invoke the filter_init_func for all filters with FILTERS where f->r |
372 | | * matches R. Restricting to a matching R avoids re-running init |
373 | | * functions for filters configured for r->main where r is a |
374 | | * subrequest. */ |
375 | | static int invoke_filter_init(request_rec *r, ap_filter_t *filters) |
376 | 0 | { |
377 | 0 | while (filters) { |
378 | 0 | if (filters->frec->filter_init_func && filters->r == r) { |
379 | 0 | int result = filters->frec->filter_init_func(filters); |
380 | 0 | if (result != OK) { |
381 | 0 | return result; |
382 | 0 | } |
383 | 0 | } |
384 | 0 | filters = filters->next; |
385 | 0 | } |
386 | 0 | return OK; |
387 | 0 | } |
388 | | |
389 | | AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r) |
390 | 0 | { |
391 | 0 | const char *handler; |
392 | 0 | const char *p; |
393 | 0 | int result; |
394 | 0 | const char *old_handler = r->handler; |
395 | 0 | const char *ignore; |
396 | | |
397 | | /* |
398 | | * The new insert_filter stage makes the most sense here. We only use |
399 | | * it when we are going to run the request, so we must insert filters |
400 | | * if any are available. Since the goal of this phase is to allow all |
401 | | * modules to insert a filter if they want to, this filter returns |
402 | | * void. I just can't see any way that this filter can reasonably |
403 | | * fail, either your modules inserts something or it doesn't. rbb |
404 | | */ |
405 | 0 | ap_run_insert_filter(r); |
406 | | |
407 | | /* Before continuing, allow each filter that is in the two chains to |
408 | | * run their init function to let them do any magic before we could |
409 | | * start generating data. |
410 | | */ |
411 | 0 | result = invoke_filter_init(r, r->input_filters); |
412 | 0 | if (result != OK) { |
413 | 0 | return result; |
414 | 0 | } |
415 | 0 | result = invoke_filter_init(r, r->output_filters); |
416 | 0 | if (result != OK) { |
417 | 0 | return result; |
418 | 0 | } |
419 | | |
420 | 0 | if (!r->handler) { |
421 | 0 | if (r->content_type) { |
422 | 0 | handler = r->content_type; |
423 | 0 | if ((p=ap_strchr_c(handler, ';')) != NULL) { |
424 | 0 | char *new_handler = (char *)apr_pmemdup(r->pool, handler, |
425 | 0 | p - handler + 1); |
426 | 0 | char *p2 = new_handler + (p - handler); |
427 | 0 | handler = new_handler; |
428 | | |
429 | | /* exclude media type arguments */ |
430 | 0 | while (p2 > handler && p2[-1] == ' ') |
431 | 0 | --p2; /* strip trailing spaces */ |
432 | |
|
433 | 0 | *p2='\0'; |
434 | 0 | } |
435 | 0 | } |
436 | 0 | else { |
437 | 0 | handler = AP_DEFAULT_HANDLER_NAME; |
438 | 0 | } |
439 | |
|
440 | 0 | r->handler = handler; |
441 | 0 | } |
442 | |
|
443 | 0 | result = ap_run_handler(r); |
444 | |
|
445 | 0 | r->handler = old_handler; |
446 | |
|
447 | 0 | if (result == DECLINED && r->handler && r->filename) { |
448 | 0 | ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(00523) |
449 | 0 | "handler \"%s\" not found for: %s", r->handler, r->filename); |
450 | 0 | } |
451 | 0 | if ((result != OK) && (result != DONE) && (result != DECLINED) && (result != SUSPENDED) |
452 | 0 | && (result != AP_FILTER_ERROR) /* ap_die() knows about this specifically */ |
453 | 0 | && !ap_is_HTTP_VALID_RESPONSE(result)) { |
454 | | /* If a module is deliberately returning something else |
455 | | * (request_rec in non-HTTP or proprietary extension?) |
456 | | * let it set a note to allow it explicitly. |
457 | | * Otherwise, a return code that is neither reserved nor HTTP |
458 | | * is a bug, as in PR#31759. |
459 | | */ |
460 | 0 | ignore = apr_table_get(r->notes, "HTTP_IGNORE_RANGE"); |
461 | 0 | if (!ignore) { |
462 | 0 | ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00524) |
463 | 0 | "Handler for %s returned invalid result code %d", |
464 | 0 | r->handler, result); |
465 | 0 | result = HTTP_INTERNAL_SERVER_ERROR; |
466 | 0 | } |
467 | 0 | } |
468 | |
|
469 | 0 | return result == DECLINED ? HTTP_INTERNAL_SERVER_ERROR : result; |
470 | 0 | } |
471 | | |
472 | | AP_DECLARE(int) ap_method_is_limited(cmd_parms *cmd, const char *method) |
473 | 0 | { |
474 | 0 | int methnum; |
475 | |
|
476 | 0 | methnum = ap_method_number_of(method); |
477 | | |
478 | | /* |
479 | | * A method number either hardcoded into apache or |
480 | | * added by a module and registered. |
481 | | */ |
482 | 0 | if (methnum != M_INVALID) { |
483 | 0 | return (cmd->limited & (AP_METHOD_BIT << methnum)) ? 1 : 0; |
484 | 0 | } |
485 | | |
486 | 0 | return 0; /* not found */ |
487 | 0 | } |
488 | | |
489 | | AP_DECLARE(void) ap_register_hooks(module *m, apr_pool_t *p) |
490 | 0 | { |
491 | 0 | if (m->register_hooks) { |
492 | 0 | if (getenv("SHOW_HOOKS")) { |
493 | 0 | printf("Registering hooks for %s\n", m->name); |
494 | 0 | apr_hook_debug_enabled = 1; |
495 | 0 | } |
496 | |
|
497 | 0 | apr_hook_debug_current = m->name; |
498 | 0 | m->register_hooks(p); |
499 | 0 | } |
500 | 0 | } |
501 | | |
502 | | static void ap_add_module_commands(module *m, apr_pool_t *p); |
503 | | |
504 | | typedef struct ap_mod_list_struct ap_mod_list; |
505 | | struct ap_mod_list_struct { |
506 | | struct ap_mod_list_struct *next; |
507 | | module *m; |
508 | | const command_rec *cmd; |
509 | | }; |
510 | | |
511 | | static void rebuild_conf_hash(apr_pool_t *p, int add_prelinked) |
512 | 0 | { |
513 | 0 | module **m; |
514 | |
|
515 | 0 | ap_config_hash = apr_hash_make(p); |
516 | |
|
517 | 0 | apr_pool_cleanup_register(p, &ap_config_hash, ap_pool_cleanup_set_null, |
518 | 0 | apr_pool_cleanup_null); |
519 | 0 | if (add_prelinked) { |
520 | 0 | for (m = ap_prelinked_modules; *m != NULL; m++) { |
521 | 0 | ap_add_module_commands(*m, p); |
522 | 0 | } |
523 | 0 | } |
524 | 0 | } |
525 | | |
526 | | static void ap_add_module_commands(module *m, apr_pool_t *p) |
527 | 0 | { |
528 | 0 | apr_pool_t *tpool; |
529 | 0 | ap_mod_list *mln; |
530 | 0 | const command_rec *cmd; |
531 | 0 | char *dir; |
532 | |
|
533 | 0 | cmd = m->cmds; |
534 | |
|
535 | 0 | if (ap_config_hash == NULL) { |
536 | 0 | rebuild_conf_hash(p, 0); |
537 | 0 | } |
538 | |
|
539 | 0 | tpool = apr_hash_pool_get(ap_config_hash); |
540 | |
|
541 | 0 | while (cmd && cmd->name) { |
542 | 0 | mln = apr_palloc(tpool, sizeof(ap_mod_list)); |
543 | 0 | mln->cmd = cmd; |
544 | 0 | mln->m = m; |
545 | 0 | dir = apr_pstrdup(tpool, cmd->name); |
546 | |
|
547 | 0 | ap_str_tolower(dir); |
548 | |
|
549 | 0 | mln->next = apr_hash_get(ap_config_hash, dir, APR_HASH_KEY_STRING); |
550 | 0 | apr_hash_set(ap_config_hash, dir, APR_HASH_KEY_STRING, mln); |
551 | 0 | ++cmd; |
552 | 0 | } |
553 | 0 | } |
554 | | |
555 | | |
556 | | /* One-time setup for precompiled modules --- NOT to be done on restart */ |
557 | | |
558 | | AP_DECLARE(const char *) ap_add_module(module *m, apr_pool_t *p, |
559 | | const char *sym_name) |
560 | 0 | { |
561 | 0 | ap_module_symbol_t *sym = ap_prelinked_module_symbols; |
562 | | |
563 | | /* This could be called from a LoadModule httpd.conf command, |
564 | | * after the file has been linked and the module structure within it |
565 | | * teased out... |
566 | | */ |
567 | |
|
568 | 0 | if (m->version != MODULE_MAGIC_NUMBER_MAJOR) { |
569 | 0 | return apr_psprintf(p, "Module \"%s\" is not compatible with this " |
570 | 0 | "version of Apache (found %d, need %d). Please " |
571 | 0 | "contact the vendor for the correct version.", |
572 | 0 | m->name, m->version, MODULE_MAGIC_NUMBER_MAJOR); |
573 | 0 | } |
574 | | |
575 | 0 | if (m->module_index == -1) { |
576 | 0 | if (dynamic_modules >= DYNAMIC_MODULE_LIMIT) { |
577 | 0 | return apr_psprintf(p, "Module \"%s\" could not be loaded, " |
578 | 0 | "because the dynamic module limit was " |
579 | 0 | "reached. Please increase " |
580 | 0 | "DYNAMIC_MODULE_LIMIT and recompile.", m->name); |
581 | 0 | } |
582 | | /* |
583 | | * If this fails some module forgot to call ap_reserve_module_slots*. |
584 | | */ |
585 | 0 | ap_assert(total_modules < conf_vector_length); |
586 | | |
587 | 0 | m->module_index = total_modules++; |
588 | 0 | dynamic_modules++; |
589 | |
|
590 | 0 | } |
591 | 0 | else if (!sym_name) { |
592 | 0 | while (sym->modp != NULL) { |
593 | 0 | if (sym->modp == m) { |
594 | 0 | sym_name = sym->name; |
595 | 0 | break; |
596 | 0 | } |
597 | 0 | sym++; |
598 | 0 | } |
599 | 0 | } |
600 | | |
601 | 0 | if (m->next == NULL) { |
602 | 0 | m->next = ap_top_module; |
603 | 0 | ap_top_module = m; |
604 | 0 | } |
605 | |
|
606 | 0 | if (sym_name) { |
607 | 0 | int len = strlen(sym_name); |
608 | 0 | int slen = strlen("_module"); |
609 | 0 | if (len > slen && !strcmp(sym_name + len - slen, "_module")) { |
610 | 0 | len -= slen; |
611 | 0 | } |
612 | |
|
613 | 0 | ap_module_short_names[m->module_index] = ap_malloc(len + 1); |
614 | 0 | memcpy(ap_module_short_names[m->module_index], sym_name, len); |
615 | 0 | ap_module_short_names[m->module_index][len] = '\0'; |
616 | 0 | merger_func_cache[m->module_index] = m->merge_dir_config; |
617 | 0 | } |
618 | | |
619 | | |
620 | | /* Some C compilers put a complete path into __FILE__, but we want |
621 | | * only the filename (e.g. mod_includes.c). So check for path |
622 | | * components (Unix and DOS), and remove them. |
623 | | */ |
624 | |
|
625 | 0 | if (ap_strrchr_c(m->name, '/')) |
626 | 0 | m->name = 1 + ap_strrchr_c(m->name, '/'); |
627 | |
|
628 | 0 | if (ap_strrchr_c(m->name, '\\')) |
629 | 0 | m->name = 1 + ap_strrchr_c(m->name, '\\'); |
630 | |
|
631 | | #ifdef _OSD_POSIX |
632 | | /* __FILE__ = |
633 | | * "*POSIX(/home/martin/apache/src/modules/standard/mod_info.c)" |
634 | | */ |
635 | | |
636 | | /* We cannot fix the string in-place, because it's const */ |
637 | | if (m->name[strlen(m->name)-1] == ')') { |
638 | | char *tmp = ap_malloc(strlen(m->name)); /* FIXME: memory leak, albeit a small one */ |
639 | | memcpy(tmp, m->name, strlen(m->name)-1); |
640 | | tmp[strlen(m->name)-1] = '\0'; |
641 | | m->name = tmp; |
642 | | } |
643 | | #endif /*_OSD_POSIX*/ |
644 | |
|
645 | 0 | ap_add_module_commands(m, p); |
646 | | /* FIXME: is this the right place to call this? |
647 | | * It doesn't appear to be |
648 | | */ |
649 | 0 | ap_register_hooks(m, p); |
650 | |
|
651 | 0 | return NULL; |
652 | 0 | } |
653 | | |
654 | | /* |
655 | | * remove_module undoes what add_module did. There are some caveats: |
656 | | * when the module is removed, its slot is lost so all the current |
657 | | * per-dir and per-server configurations are invalid. So we should |
658 | | * only ever call this function when you are invalidating almost |
659 | | * all our current data. I.e. when doing a restart. |
660 | | */ |
661 | | |
662 | | AP_DECLARE(void) ap_remove_module(module *m) |
663 | 0 | { |
664 | 0 | module *modp; |
665 | |
|
666 | 0 | modp = ap_top_module; |
667 | 0 | if (modp == m) { |
668 | | /* We are the top module, special case */ |
669 | 0 | ap_top_module = modp->next; |
670 | 0 | m->next = NULL; |
671 | 0 | } |
672 | 0 | else { |
673 | | /* Not the top module, find use. When found modp will |
674 | | * point to the module _before_ us in the list |
675 | | */ |
676 | |
|
677 | 0 | while (modp && modp->next != m) { |
678 | 0 | modp = modp->next; |
679 | 0 | } |
680 | |
|
681 | 0 | if (!modp) { |
682 | | /* Uh-oh, this module doesn't exist */ |
683 | 0 | ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00525) |
684 | 0 | "Cannot remove module %s: not found in module list", |
685 | 0 | m->name); |
686 | 0 | return; |
687 | 0 | } |
688 | | |
689 | | /* Eliminate us from the module list */ |
690 | 0 | modp->next = modp->next->next; |
691 | 0 | } |
692 | | |
693 | 0 | free(ap_module_short_names[m->module_index]); |
694 | 0 | ap_module_short_names[m->module_index] = NULL; |
695 | 0 | merger_func_cache[m->module_index] = NULL; |
696 | |
|
697 | 0 | m->module_index = -1; /* simulate being unloaded, should |
698 | | * be unnecessary */ |
699 | 0 | dynamic_modules--; |
700 | 0 | total_modules--; |
701 | 0 | } |
702 | | |
703 | | AP_DECLARE(const char *) ap_add_loaded_module(module *mod, apr_pool_t *p, |
704 | | const char *short_name) |
705 | 0 | { |
706 | 0 | module **m; |
707 | 0 | const char *error; |
708 | | |
709 | | /* |
710 | | * Add module pointer to top of chained module list |
711 | | */ |
712 | 0 | error = ap_add_module(mod, p, short_name); |
713 | 0 | if (error) { |
714 | 0 | return error; |
715 | 0 | } |
716 | | |
717 | | /* |
718 | | * And module pointer to list of loaded modules |
719 | | * |
720 | | * Notes: 1. ap_add_module() would already complain if no more space |
721 | | * exists for adding a dynamically loaded module |
722 | | * 2. ap_add_module() accepts double inclusion, so we have |
723 | | * to accept this, too. |
724 | | */ |
725 | 0 | for (m = ap_loaded_modules; *m != NULL; m++) |
726 | 0 | ; |
727 | 0 | *m++ = mod; |
728 | 0 | *m = NULL; |
729 | |
|
730 | 0 | return NULL; |
731 | 0 | } |
732 | | |
733 | | AP_DECLARE(void) ap_remove_loaded_module(module *mod) |
734 | 0 | { |
735 | 0 | module **m; |
736 | 0 | module **m2; |
737 | 0 | int done; |
738 | | |
739 | | /* |
740 | | * Remove module pointer from chained module list |
741 | | */ |
742 | 0 | ap_remove_module(mod); |
743 | | |
744 | | /* |
745 | | * Remove module pointer from list of loaded modules |
746 | | * |
747 | | * Note: 1. We cannot determine if the module was successfully |
748 | | * removed by ap_remove_module(). |
749 | | * 2. We have not to complain explicitly when the module |
750 | | * is not found because ap_remove_module() did it |
751 | | * for us already. |
752 | | */ |
753 | 0 | for (m = m2 = ap_loaded_modules, done = 0; *m2 != NULL; m2++) { |
754 | 0 | if (*m2 == mod && done == 0) |
755 | 0 | done = 1; |
756 | 0 | else |
757 | 0 | *m++ = *m2; |
758 | 0 | } |
759 | |
|
760 | 0 | *m = NULL; |
761 | 0 | } |
762 | | |
763 | | AP_DECLARE(const char *) ap_setup_prelinked_modules(process_rec *process) |
764 | 0 | { |
765 | 0 | module **m; |
766 | 0 | module **m2; |
767 | 0 | const char *error; |
768 | |
|
769 | 0 | apr_hook_global_pool=process->pconf; |
770 | |
|
771 | 0 | rebuild_conf_hash(process->pconf, 0); |
772 | | |
773 | | /* |
774 | | * Initialise total_modules variable and module indices |
775 | | */ |
776 | 0 | total_modules = 0; |
777 | 0 | for (m = ap_preloaded_modules; *m != NULL; m++) |
778 | 0 | (*m)->module_index = total_modules++; |
779 | |
|
780 | 0 | max_modules = total_modules + DYNAMIC_MODULE_LIMIT + 1; |
781 | 0 | conf_vector_length = max_modules; |
782 | | |
783 | | /* |
784 | | * Initialise list of loaded modules and short names |
785 | | */ |
786 | 0 | ap_loaded_modules = (module **)apr_palloc(process->pool, |
787 | 0 | sizeof(module *) * conf_vector_length); |
788 | 0 | if (!ap_module_short_names) |
789 | 0 | ap_module_short_names = ap_calloc(sizeof(char *), conf_vector_length); |
790 | |
|
791 | 0 | if (!merger_func_cache) |
792 | 0 | merger_func_cache = ap_calloc(sizeof(merger_func), conf_vector_length); |
793 | |
|
794 | 0 | if (ap_loaded_modules == NULL || ap_module_short_names == NULL |
795 | 0 | || merger_func_cache == NULL) |
796 | 0 | return "Ouch! Out of memory in ap_setup_prelinked_modules()!"; |
797 | | |
798 | 0 | for (m = ap_preloaded_modules, m2 = ap_loaded_modules; *m != NULL; ) |
799 | 0 | *m2++ = *m++; |
800 | |
|
801 | 0 | *m2 = NULL; |
802 | | |
803 | | /* |
804 | | * Initialize chain of linked (=activate) modules |
805 | | */ |
806 | 0 | for (m = ap_prelinked_modules; *m != NULL; m++) { |
807 | 0 | error = ap_add_module(*m, process->pconf, NULL); |
808 | 0 | if (error) { |
809 | 0 | return error; |
810 | 0 | } |
811 | 0 | } |
812 | | |
813 | 0 | apr_hook_sort_all(); |
814 | |
|
815 | 0 | return NULL; |
816 | 0 | } |
817 | | |
818 | | AP_DECLARE(const char *) ap_find_module_name(module *m) |
819 | 0 | { |
820 | 0 | return m->name; |
821 | 0 | } |
822 | | |
823 | | AP_DECLARE(const char *) ap_find_module_short_name(int module_index) |
824 | 0 | { |
825 | 0 | if (module_index < 0 || module_index >= conf_vector_length) |
826 | 0 | return NULL; |
827 | 0 | return ap_module_short_names[module_index]; |
828 | 0 | } |
829 | | |
830 | | AP_DECLARE(module *) ap_find_linked_module(const char *name) |
831 | 0 | { |
832 | 0 | module *modp; |
833 | |
|
834 | 0 | for (modp = ap_top_module; modp; modp = modp->next) { |
835 | 0 | if (strcmp(modp->name, name) == 0) |
836 | 0 | return modp; |
837 | 0 | } |
838 | | |
839 | 0 | return NULL; |
840 | 0 | } |
841 | | |
842 | | /***************************************************************** |
843 | | * |
844 | | * Resource, access, and .htaccess config files now parsed by a common |
845 | | * command loop. |
846 | | * |
847 | | * Let's begin with the basics; parsing the line and |
848 | | * invoking the function... |
849 | | */ |
850 | | |
851 | 0 | #define AP_MAX_ARGC 64 |
852 | | |
853 | | static const char *invoke_cmd(const command_rec *cmd, cmd_parms *parms, |
854 | | void *mconfig, const char *args, |
855 | | ap_directive_t *parent) |
856 | 0 | { |
857 | 0 | int override_list_ok = 0; |
858 | 0 | char *w, *w2, *w3; |
859 | 0 | const char *errmsg = NULL; |
860 | | |
861 | | /* Have we been provided a list of acceptable directives? */ |
862 | 0 | if (parms->override_list != NULL) { |
863 | 0 | if (apr_table_get(parms->override_list, cmd->name) != NULL) { |
864 | 0 | override_list_ok = 1; |
865 | 0 | } |
866 | 0 | } |
867 | |
|
868 | 0 | if ((parms->override & cmd->req_override) == 0 && !override_list_ok) { |
869 | 0 | if (parms->override & NONFATAL_OVERRIDE) { |
870 | 0 | ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, parms->temp_pool, |
871 | 0 | APLOGNO(02295) |
872 | 0 | "%s in .htaccess forbidden by AllowOverride", |
873 | 0 | cmd->name); |
874 | 0 | return NULL; |
875 | 0 | } |
876 | 0 | else if (parms->directive && parms->directive->parent) { |
877 | 0 | return apr_pstrcat(parms->pool, cmd->name, " not allowed in ", |
878 | 0 | parms->directive->parent->directive, ">", |
879 | 0 | " context", NULL); |
880 | 0 | } |
881 | 0 | else { |
882 | 0 | return apr_pstrcat(parms->pool, cmd->name, |
883 | 0 | " not allowed here", NULL); |
884 | 0 | } |
885 | 0 | } |
886 | | |
887 | 0 | parms->info = cmd->cmd_data; |
888 | 0 | parms->cmd = cmd; |
889 | 0 | parms->parent = parent; |
890 | |
|
891 | 0 | switch (cmd->args_how) { |
892 | 0 | case RAW_ARGS: |
893 | | #ifdef RESOLVE_ENV_PER_TOKEN |
894 | | args = ap_resolve_env(parms->pool,args); |
895 | | #endif |
896 | 0 | return cmd->AP_RAW_ARGS(parms, mconfig, args); |
897 | | |
898 | 0 | case TAKE_ARGV: |
899 | 0 | { |
900 | 0 | char *argv[AP_MAX_ARGC]; |
901 | 0 | int argc = 0; |
902 | |
|
903 | 0 | do { |
904 | 0 | w = ap_getword_conf(parms->pool, &args); |
905 | 0 | if (*w == '\0' && *args == '\0') { |
906 | 0 | break; |
907 | 0 | } |
908 | 0 | argv[argc] = w; |
909 | 0 | argc++; |
910 | 0 | } while (argc < AP_MAX_ARGC && *args != '\0'); |
911 | | |
912 | 0 | return cmd->AP_TAKE_ARGV(parms, mconfig, argc, argv); |
913 | 0 | } |
914 | | |
915 | 0 | case NO_ARGS: |
916 | 0 | if (*args != 0) |
917 | 0 | return apr_pstrcat(parms->pool, cmd->name, " takes no arguments", |
918 | 0 | NULL); |
919 | | |
920 | 0 | return cmd->AP_NO_ARGS(parms, mconfig); |
921 | | |
922 | 0 | case TAKE1: |
923 | 0 | w = ap_getword_conf(parms->pool, &args); |
924 | |
|
925 | 0 | if (*w == '\0' || *args != 0) |
926 | 0 | return apr_pstrcat(parms->pool, cmd->name, " takes one argument", |
927 | 0 | cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); |
928 | | |
929 | 0 | return cmd->AP_TAKE1(parms, mconfig, w); |
930 | | |
931 | 0 | case TAKE2: |
932 | 0 | w = ap_getword_conf(parms->pool, &args); |
933 | 0 | w2 = ap_getword_conf(parms->pool, &args); |
934 | |
|
935 | 0 | if (*w == '\0' || *w2 == '\0' || *args != 0) |
936 | 0 | return apr_pstrcat(parms->pool, cmd->name, " takes two arguments", |
937 | 0 | cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); |
938 | | |
939 | 0 | return cmd->AP_TAKE2(parms, mconfig, w, w2); |
940 | | |
941 | 0 | case TAKE12: |
942 | 0 | w = ap_getword_conf(parms->pool, &args); |
943 | 0 | w2 = ap_getword_conf(parms->pool, &args); |
944 | |
|
945 | 0 | if (*w == '\0' || *args != 0) |
946 | 0 | return apr_pstrcat(parms->pool, cmd->name, " takes 1-2 arguments", |
947 | 0 | cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); |
948 | | |
949 | 0 | return cmd->AP_TAKE2(parms, mconfig, w, *w2 ? w2 : NULL); |
950 | | |
951 | 0 | case TAKE3: |
952 | 0 | w = ap_getword_conf(parms->pool, &args); |
953 | 0 | w2 = ap_getword_conf(parms->pool, &args); |
954 | 0 | w3 = ap_getword_conf(parms->pool, &args); |
955 | |
|
956 | 0 | if (*w == '\0' || *w2 == '\0' || *w3 == '\0' || *args != 0) |
957 | 0 | return apr_pstrcat(parms->pool, cmd->name, " takes three arguments", |
958 | 0 | cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); |
959 | | |
960 | 0 | return cmd->AP_TAKE3(parms, mconfig, w, w2, w3); |
961 | | |
962 | 0 | case TAKE23: |
963 | 0 | w = ap_getword_conf(parms->pool, &args); |
964 | 0 | w2 = ap_getword_conf(parms->pool, &args); |
965 | 0 | w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL; |
966 | |
|
967 | 0 | if (*w == '\0' || *w2 == '\0' || *args != 0) |
968 | 0 | return apr_pstrcat(parms->pool, cmd->name, |
969 | 0 | " takes two or three arguments", |
970 | 0 | cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); |
971 | | |
972 | 0 | return cmd->AP_TAKE3(parms, mconfig, w, w2, w3); |
973 | | |
974 | 0 | case TAKE123: |
975 | 0 | w = ap_getword_conf(parms->pool, &args); |
976 | 0 | w2 = *args ? ap_getword_conf(parms->pool, &args) : NULL; |
977 | 0 | w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL; |
978 | |
|
979 | 0 | if (*w == '\0' || *args != 0) |
980 | 0 | return apr_pstrcat(parms->pool, cmd->name, |
981 | 0 | " takes one, two or three arguments", |
982 | 0 | cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); |
983 | | |
984 | 0 | return cmd->AP_TAKE3(parms, mconfig, w, w2, w3); |
985 | | |
986 | 0 | case TAKE13: |
987 | 0 | w = ap_getword_conf(parms->pool, &args); |
988 | 0 | w2 = *args ? ap_getword_conf(parms->pool, &args) : NULL; |
989 | 0 | w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL; |
990 | |
|
991 | 0 | if (*w == '\0' || (w2 && *w2 && !w3) || *args != 0) |
992 | 0 | return apr_pstrcat(parms->pool, cmd->name, |
993 | 0 | " takes one or three arguments", |
994 | 0 | cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); |
995 | | |
996 | 0 | return cmd->AP_TAKE3(parms, mconfig, w, w2, w3); |
997 | | |
998 | 0 | case ITERATE: |
999 | 0 | w = ap_getword_conf(parms->pool, &args); |
1000 | | |
1001 | 0 | if (*w == '\0') |
1002 | 0 | return apr_pstrcat(parms->pool, cmd->name, |
1003 | 0 | " requires at least one argument", |
1004 | 0 | cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); |
1005 | | |
1006 | 0 | while (*w != '\0') { |
1007 | 0 | errmsg = cmd->AP_TAKE1(parms, mconfig, w); |
1008 | |
|
1009 | 0 | if (errmsg && strcmp(errmsg, DECLINE_CMD) != 0) |
1010 | 0 | return errmsg; |
1011 | | |
1012 | 0 | w = ap_getword_conf(parms->pool, &args); |
1013 | 0 | } |
1014 | | |
1015 | 0 | return errmsg; |
1016 | | |
1017 | 0 | case ITERATE2: |
1018 | 0 | w = ap_getword_conf(parms->pool, &args); |
1019 | |
|
1020 | 0 | if (*w == '\0' || *args == 0) |
1021 | 0 | return apr_pstrcat(parms->pool, cmd->name, |
1022 | 0 | " requires at least two arguments", |
1023 | 0 | cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); |
1024 | | |
1025 | 0 | while (*(w2 = ap_getword_conf(parms->pool, &args)) != '\0') { |
1026 | |
|
1027 | 0 | errmsg = cmd->AP_TAKE2(parms, mconfig, w, w2); |
1028 | |
|
1029 | 0 | if (errmsg && strcmp(errmsg, DECLINE_CMD) != 0) |
1030 | 0 | return errmsg; |
1031 | 0 | } |
1032 | | |
1033 | 0 | return errmsg; |
1034 | | |
1035 | 0 | case FLAG: |
1036 | | /* |
1037 | | * This is safe to use temp_pool here, because the 'flag' itself is not |
1038 | | * forwarded as-is |
1039 | | */ |
1040 | 0 | w = ap_getword_conf(parms->temp_pool, &args); |
1041 | |
|
1042 | 0 | if (*w == '\0' || (ap_cstr_casecmp(w, "on") && ap_cstr_casecmp(w, "off"))) |
1043 | 0 | return apr_pstrcat(parms->pool, cmd->name, " must be On or Off", |
1044 | 0 | NULL); |
1045 | | |
1046 | 0 | return cmd->AP_FLAG(parms, mconfig, ap_cstr_casecmp(w, "off") != 0); |
1047 | | |
1048 | 0 | default: |
1049 | 0 | return apr_pstrcat(parms->pool, cmd->name, |
1050 | 0 | " is improperly configured internally (server bug)", |
1051 | 0 | NULL); |
1052 | 0 | } |
1053 | 0 | } |
1054 | | |
1055 | | AP_CORE_DECLARE(const command_rec *) ap_find_command(const char *name, |
1056 | | const command_rec *cmds) |
1057 | 0 | { |
1058 | 0 | while (cmds->name) { |
1059 | 0 | if (!ap_cstr_casecmp(name, cmds->name)) |
1060 | 0 | return cmds; |
1061 | | |
1062 | 0 | ++cmds; |
1063 | 0 | } |
1064 | | |
1065 | 0 | return NULL; |
1066 | 0 | } |
1067 | | |
1068 | | AP_CORE_DECLARE(const command_rec *) ap_find_command_in_modules( |
1069 | | const char *cmd_name, module **mod) |
1070 | 0 | { |
1071 | 0 | const command_rec *cmdp; |
1072 | 0 | module *modp; |
1073 | |
|
1074 | 0 | for (modp = *mod; modp; modp = modp->next) { |
1075 | 0 | if (modp->cmds && (cmdp = ap_find_command(cmd_name, modp->cmds))) { |
1076 | 0 | *mod = modp; |
1077 | 0 | return cmdp; |
1078 | 0 | } |
1079 | 0 | } |
1080 | | |
1081 | 0 | return NULL; |
1082 | 0 | } |
1083 | | |
1084 | | AP_CORE_DECLARE(void *) ap_set_config_vectors(server_rec *server, |
1085 | | ap_conf_vector_t *section_vector, |
1086 | | const char *section, |
1087 | | module *mod, apr_pool_t *pconf) |
1088 | 0 | { |
1089 | 0 | void *section_config = ap_get_module_config(section_vector, mod); |
1090 | 0 | void *server_config = ap_get_module_config(server->module_config, mod); |
1091 | |
|
1092 | 0 | if (!section_config && mod->create_dir_config) { |
1093 | | /* ### need to fix the create_dir_config functions' prototype... */ |
1094 | 0 | section_config = (*mod->create_dir_config)(pconf, (char *)section); |
1095 | 0 | ap_set_module_config(section_vector, mod, section_config); |
1096 | 0 | } |
1097 | |
|
1098 | 0 | if (!server_config && mod->create_server_config) { |
1099 | 0 | server_config = (*mod->create_server_config)(pconf, server); |
1100 | 0 | ap_set_module_config(server->module_config, mod, server_config); |
1101 | 0 | } |
1102 | |
|
1103 | 0 | return section_config; |
1104 | 0 | } |
1105 | | |
1106 | | static const char *execute_now(char *cmd_line, const char *args, |
1107 | | cmd_parms *parms, |
1108 | | apr_pool_t *p, apr_pool_t *ptemp, |
1109 | | ap_directive_t **sub_tree, |
1110 | | ap_directive_t *parent); |
1111 | | |
1112 | | static const char *ap_build_config_sub(apr_pool_t *p, apr_pool_t *temp_pool, |
1113 | | const char *l, cmd_parms *parms, |
1114 | | ap_directive_t **current, |
1115 | | ap_directive_t **curr_parent, |
1116 | | ap_directive_t **conftree) |
1117 | 0 | { |
1118 | 0 | const char *retval = NULL; |
1119 | 0 | const char *args; |
1120 | 0 | char *cmd_name; |
1121 | 0 | ap_directive_t *newdir; |
1122 | 0 | const command_rec *cmd; |
1123 | 0 | ap_mod_list *ml; |
1124 | 0 | char *lname; |
1125 | |
|
1126 | 0 | if (*l == '#' || *l == '\0') |
1127 | 0 | return NULL; |
1128 | | |
1129 | | #if RESOLVE_ENV_PER_TOKEN |
1130 | | args = l; |
1131 | | #else |
1132 | 0 | args = ap_resolve_env(temp_pool, l); |
1133 | 0 | #endif |
1134 | | |
1135 | | /* The first word is the name of a directive. We can safely use the |
1136 | | * 'temp_pool' for it. If it matches the name of a known directive, we |
1137 | | * can reference the string within the module if needed. Otherwise, we |
1138 | | * can still make a copy in the 'p' pool. */ |
1139 | 0 | cmd_name = ap_getword_conf(temp_pool, &args); |
1140 | 0 | if (*cmd_name == '\0') { |
1141 | | /* Note: this branch should not occur. An empty line should have |
1142 | | * triggered the exit further above. |
1143 | | */ |
1144 | 0 | return NULL; |
1145 | 0 | } |
1146 | | |
1147 | 0 | if (cmd_name[1] != '/') { |
1148 | 0 | char *lastc = cmd_name + strlen(cmd_name) - 1; |
1149 | 0 | if (*lastc == '>') { |
1150 | 0 | *lastc = '\0' ; |
1151 | 0 | } |
1152 | 0 | if (cmd_name[0] == '<' && *args == '\0') { |
1153 | 0 | args = ">"; |
1154 | 0 | } |
1155 | 0 | } |
1156 | |
|
1157 | 0 | newdir = apr_pcalloc(p, sizeof(ap_directive_t)); |
1158 | 0 | newdir->filename = parms->config_file->name; |
1159 | 0 | newdir->line_num = parms->config_file->line_number; |
1160 | 0 | newdir->args = apr_pstrdup(p, args); |
1161 | |
|
1162 | 0 | lname = apr_pstrdup(temp_pool, cmd_name); |
1163 | 0 | ap_str_tolower(lname); |
1164 | 0 | ml = apr_hash_get(ap_config_hash, lname, APR_HASH_KEY_STRING); |
1165 | |
|
1166 | 0 | if (ml && (cmd = ml->cmd) != NULL) { |
1167 | 0 | newdir->directive = cmd->name; |
1168 | 0 | if (cmd->req_override & EXEC_ON_READ) { |
1169 | 0 | ap_directive_t *sub_tree = NULL; |
1170 | |
|
1171 | 0 | parms->err_directive = newdir; |
1172 | 0 | retval = execute_now(cmd_name, args, parms, p, temp_pool, |
1173 | 0 | &sub_tree, *curr_parent); |
1174 | 0 | if (*current) { |
1175 | 0 | (*current)->next = sub_tree; |
1176 | 0 | } |
1177 | 0 | else { |
1178 | 0 | *current = sub_tree; |
1179 | 0 | if (*curr_parent) { |
1180 | 0 | (*curr_parent)->first_child = (*current); |
1181 | 0 | } |
1182 | 0 | if (*current) { |
1183 | 0 | (*current)->parent = (*curr_parent); |
1184 | 0 | } |
1185 | 0 | } |
1186 | 0 | if (*current) { |
1187 | 0 | if (!*conftree) { |
1188 | | /* Before walking *current to the end of the list, |
1189 | | * set the head to *current. |
1190 | | */ |
1191 | 0 | *conftree = *current; |
1192 | 0 | } |
1193 | 0 | while ((*current)->next != NULL) { |
1194 | 0 | (*current) = (*current)->next; |
1195 | 0 | (*current)->parent = (*curr_parent); |
1196 | 0 | } |
1197 | 0 | } |
1198 | 0 | return retval; |
1199 | 0 | } |
1200 | 0 | } |
1201 | 0 | else { |
1202 | | /* No known directive found? Make a copy of what we have parsed. */ |
1203 | 0 | newdir->directive = apr_pstrdup(p, cmd_name); |
1204 | 0 | } |
1205 | | |
1206 | | |
1207 | 0 | if (cmd_name[0] == '<') { |
1208 | 0 | if (cmd_name[1] != '/') { |
1209 | 0 | (*current) = ap_add_node(curr_parent, *current, newdir, 1); |
1210 | 0 | } |
1211 | 0 | else if (*curr_parent == NULL) { |
1212 | 0 | parms->err_directive = newdir; |
1213 | 0 | return apr_pstrcat(p, cmd_name, |
1214 | 0 | " without matching <", cmd_name + 2, |
1215 | 0 | " section", NULL); |
1216 | 0 | } |
1217 | 0 | else { |
1218 | 0 | char *bracket = cmd_name + strlen(cmd_name) - 1; |
1219 | |
|
1220 | 0 | if (*bracket != '>') { |
1221 | 0 | parms->err_directive = newdir; |
1222 | 0 | return apr_pstrcat(p, cmd_name, |
1223 | 0 | "> directive missing closing '>'", NULL); |
1224 | 0 | } |
1225 | | |
1226 | 0 | *bracket = '\0'; |
1227 | |
|
1228 | 0 | if (ap_cstr_casecmp(cmd_name + 2, |
1229 | 0 | (*curr_parent)->directive + 1) != 0) { |
1230 | 0 | parms->err_directive = newdir; |
1231 | 0 | return apr_pstrcat(p, "Expected </", |
1232 | 0 | (*curr_parent)->directive + 1, "> but saw ", |
1233 | 0 | cmd_name, ">", NULL); |
1234 | 0 | } |
1235 | | |
1236 | 0 | *bracket = '>'; |
1237 | | |
1238 | | /* done with this section; move up a level */ |
1239 | 0 | *current = *curr_parent; |
1240 | 0 | *curr_parent = (*current)->parent; |
1241 | 0 | } |
1242 | 0 | } |
1243 | 0 | else { |
1244 | 0 | *current = ap_add_node(curr_parent, *current, newdir, 0); |
1245 | 0 | } |
1246 | | |
1247 | 0 | return retval; |
1248 | 0 | } |
1249 | | |
1250 | 0 | #define VARBUF_INIT_LEN 200 |
1251 | 0 | #define VARBUF_MAX_LEN (16*1024*1024) |
1252 | | |
1253 | | AP_DECLARE(const char *) ap_build_cont_config(apr_pool_t *p, |
1254 | | apr_pool_t *temp_pool, |
1255 | | cmd_parms *parms, |
1256 | | ap_directive_t **current, |
1257 | | ap_directive_t **curr_parent, |
1258 | | const char *orig_directive) |
1259 | 0 | { |
1260 | 0 | char *bracket; |
1261 | 0 | const char *retval; |
1262 | 0 | ap_directive_t *sub_tree = NULL; |
1263 | 0 | apr_status_t rc; |
1264 | 0 | struct ap_varbuf vb; |
1265 | 0 | apr_size_t max_len = VARBUF_MAX_LEN; |
1266 | 0 | if (p == temp_pool) |
1267 | 0 | max_len = HUGE_STRING_LEN; /* lower limit for .htaccess */ |
1268 | |
|
1269 | 0 | bracket = apr_pstrcat(temp_pool, orig_directive + 1, ">", NULL); |
1270 | 0 | ap_varbuf_init(temp_pool, &vb, VARBUF_INIT_LEN); |
1271 | |
|
1272 | 0 | while ((rc = ap_varbuf_cfg_getline(&vb, parms->config_file, max_len)) |
1273 | 0 | == APR_SUCCESS) { |
1274 | 0 | if (!memcmp(vb.buf, "</", 2) |
1275 | 0 | && (ap_cstr_casecmp(vb.buf + 2, bracket) == 0) |
1276 | 0 | && (*curr_parent == NULL)) { |
1277 | 0 | break; |
1278 | 0 | } |
1279 | 0 | retval = ap_build_config_sub(p, temp_pool, vb.buf, parms, current, |
1280 | 0 | curr_parent, &sub_tree); |
1281 | 0 | if (retval != NULL) |
1282 | 0 | return retval; |
1283 | | |
1284 | 0 | if (sub_tree == NULL) { |
1285 | 0 | sub_tree = *curr_parent; |
1286 | 0 | } |
1287 | |
|
1288 | 0 | if (sub_tree == NULL) { |
1289 | 0 | sub_tree = *current; |
1290 | 0 | } |
1291 | 0 | } |
1292 | 0 | ap_varbuf_free(&vb); |
1293 | 0 | if (rc != APR_EOF && rc != APR_SUCCESS) |
1294 | 0 | return ap_pcfg_strerror(temp_pool, parms->config_file, rc); |
1295 | | |
1296 | 0 | *current = sub_tree; |
1297 | 0 | return NULL; |
1298 | 0 | } |
1299 | | |
1300 | | static const char *ap_walk_config_sub(const ap_directive_t *current, |
1301 | | cmd_parms *parms, |
1302 | | ap_conf_vector_t *section_vector) |
1303 | 0 | { |
1304 | 0 | const command_rec *cmd; |
1305 | 0 | ap_mod_list *ml; |
1306 | 0 | char *dir = apr_pstrdup(parms->temp_pool, current->directive); |
1307 | |
|
1308 | 0 | ap_str_tolower(dir); |
1309 | |
|
1310 | 0 | ml = apr_hash_get(ap_config_hash, dir, APR_HASH_KEY_STRING); |
1311 | |
|
1312 | 0 | if (ml == NULL) { |
1313 | 0 | parms->err_directive = current; |
1314 | 0 | if (parms->override & NONFATAL_UNKNOWN) { |
1315 | 0 | ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, parms->temp_pool, |
1316 | 0 | APLOGNO(02296) "Unknown directive %s " |
1317 | 0 | "perhaps misspelled or defined by a module " |
1318 | 0 | "not included in the server configuration", dir); |
1319 | 0 | return NULL; |
1320 | 0 | } |
1321 | 0 | else { |
1322 | 0 | return apr_pstrcat(parms->pool, "Invalid command '", |
1323 | 0 | current->directive, |
1324 | 0 | "', perhaps misspelled or defined by a module " |
1325 | 0 | "not included in the server configuration", |
1326 | 0 | NULL); |
1327 | 0 | } |
1328 | 0 | } |
1329 | | |
1330 | 0 | for ( ; ml != NULL; ml = ml->next) { |
1331 | 0 | void *dir_config = ap_set_config_vectors(parms->server, |
1332 | 0 | section_vector, |
1333 | 0 | parms->path, |
1334 | 0 | ml->m, |
1335 | 0 | parms->pool); |
1336 | 0 | const char *retval; |
1337 | 0 | cmd = ml->cmd; |
1338 | | |
1339 | | /* Once was enough? */ |
1340 | 0 | if (cmd->req_override & EXEC_ON_READ) { |
1341 | 0 | continue; |
1342 | 0 | } |
1343 | | |
1344 | 0 | retval = invoke_cmd(cmd, parms, dir_config, current->args, NULL); |
1345 | |
|
1346 | 0 | if (retval != NULL && strcmp(retval, DECLINE_CMD) != 0) { |
1347 | | /* If the directive in error has already been set, don't |
1348 | | * replace it. Otherwise, an error inside a container |
1349 | | * will be reported as occurring on the first line of the |
1350 | | * container. |
1351 | | */ |
1352 | 0 | if (!parms->err_directive) { |
1353 | 0 | parms->err_directive = current; |
1354 | 0 | } |
1355 | 0 | return retval; |
1356 | 0 | } |
1357 | 0 | } |
1358 | | |
1359 | 0 | return NULL; |
1360 | 0 | } |
1361 | | |
1362 | | AP_DECLARE(const char *) ap_walk_config(ap_directive_t *current, |
1363 | | cmd_parms *parms, |
1364 | | ap_conf_vector_t *section_vector) |
1365 | 0 | { |
1366 | 0 | ap_conf_vector_t *oldconfig = parms->context; |
1367 | |
|
1368 | 0 | parms->context = section_vector; |
1369 | | |
1370 | | /* scan through all directives, executing each one */ |
1371 | 0 | for (; current != NULL; current = current->next) { |
1372 | 0 | const char *errmsg; |
1373 | |
|
1374 | 0 | parms->directive = current; |
1375 | | |
1376 | | /* actually parse the command and execute the correct function */ |
1377 | 0 | errmsg = ap_walk_config_sub(current, parms, section_vector); |
1378 | 0 | if (errmsg != NULL) { |
1379 | | /* restore the context (just in case) */ |
1380 | 0 | parms->context = oldconfig; |
1381 | 0 | return errmsg; |
1382 | 0 | } |
1383 | 0 | } |
1384 | | |
1385 | 0 | parms->context = oldconfig; |
1386 | 0 | return NULL; |
1387 | 0 | } |
1388 | | |
1389 | | AP_DECLARE(const char *) ap_build_config(cmd_parms *parms, |
1390 | | apr_pool_t *p, apr_pool_t *temp_pool, |
1391 | | ap_directive_t **conftree) |
1392 | 0 | { |
1393 | 0 | ap_directive_t *current = *conftree; |
1394 | 0 | ap_directive_t *curr_parent = NULL; |
1395 | 0 | const char *errmsg; |
1396 | 0 | ap_directive_t **last_ptr = NULL; |
1397 | 0 | apr_status_t rc; |
1398 | 0 | struct ap_varbuf vb; |
1399 | 0 | apr_size_t max_len = VARBUF_MAX_LEN; |
1400 | 0 | if (p == temp_pool) |
1401 | 0 | max_len = HUGE_STRING_LEN; /* lower limit for .htaccess */ |
1402 | |
|
1403 | 0 | ap_varbuf_init(temp_pool, &vb, VARBUF_INIT_LEN); |
1404 | |
|
1405 | 0 | if (current != NULL) { |
1406 | | /* If we have to traverse the whole tree again for every included |
1407 | | * config file, the required time grows as O(n^2) with the number of |
1408 | | * files. This can be a significant delay for large configurations. |
1409 | | * Therefore we cache a pointer to the last node. |
1410 | | */ |
1411 | 0 | last_ptr = &(current->last); |
1412 | |
|
1413 | 0 | if (last_ptr && *last_ptr) { |
1414 | 0 | current = *last_ptr; |
1415 | 0 | } |
1416 | |
|
1417 | 0 | while (current->next) { |
1418 | 0 | current = current->next; |
1419 | 0 | } |
1420 | |
|
1421 | 0 | if (last_ptr) { |
1422 | | /* update cached pointer to last node */ |
1423 | 0 | *last_ptr = current; |
1424 | 0 | } |
1425 | 0 | } |
1426 | |
|
1427 | 0 | while ((rc = ap_varbuf_cfg_getline(&vb, parms->config_file, max_len)) |
1428 | 0 | == APR_SUCCESS) { |
1429 | 0 | errmsg = ap_build_config_sub(p, temp_pool, vb.buf, parms, |
1430 | 0 | ¤t, &curr_parent, conftree); |
1431 | 0 | if (errmsg != NULL) |
1432 | 0 | return errmsg; |
1433 | | |
1434 | 0 | if (*conftree == NULL && curr_parent != NULL) { |
1435 | 0 | *conftree = curr_parent; |
1436 | 0 | } |
1437 | |
|
1438 | 0 | if (*conftree == NULL && current != NULL) { |
1439 | 0 | *conftree = current; |
1440 | 0 | } |
1441 | 0 | } |
1442 | 0 | ap_varbuf_free(&vb); |
1443 | 0 | if (rc != APR_EOF && rc != APR_SUCCESS) |
1444 | 0 | return ap_pcfg_strerror(temp_pool, parms->config_file, rc); |
1445 | | |
1446 | 0 | if (curr_parent != NULL) { |
1447 | 0 | errmsg = ""; |
1448 | |
|
1449 | 0 | while (curr_parent != NULL) { |
1450 | 0 | errmsg = apr_psprintf(p, "%s%s%s:%u: %s> was not closed.", |
1451 | 0 | errmsg, |
1452 | 0 | *errmsg == '\0' ? "" : APR_EOL_STR, |
1453 | 0 | curr_parent->filename, |
1454 | 0 | curr_parent->line_num, |
1455 | 0 | curr_parent->directive); |
1456 | |
|
1457 | 0 | parms->err_directive = curr_parent; |
1458 | 0 | curr_parent = curr_parent->parent; |
1459 | 0 | } |
1460 | |
|
1461 | 0 | return errmsg; |
1462 | 0 | } |
1463 | | |
1464 | 0 | return NULL; |
1465 | 0 | } |
1466 | | |
1467 | | /* |
1468 | | * Generic command functions... |
1469 | | */ |
1470 | | |
1471 | | AP_DECLARE_NONSTD(const char *) ap_set_string_slot(cmd_parms *cmd, |
1472 | | void *struct_ptr, |
1473 | | const char *arg) |
1474 | 0 | { |
1475 | 0 | int offset = (int)(long)cmd->info; |
1476 | |
|
1477 | 0 | *(const char **)((char *)struct_ptr + offset) = arg; |
1478 | |
|
1479 | 0 | return NULL; |
1480 | 0 | } |
1481 | | |
1482 | | AP_DECLARE_NONSTD(const char *) ap_set_int_slot(cmd_parms *cmd, |
1483 | | void *struct_ptr, |
1484 | | const char *arg) |
1485 | 0 | { |
1486 | 0 | char *endptr; |
1487 | 0 | char *error_str = NULL; |
1488 | 0 | int offset = (int)(long)cmd->info; |
1489 | |
|
1490 | 0 | *(int *)((char*)struct_ptr + offset) = strtol(arg, &endptr, 10); |
1491 | |
|
1492 | 0 | if ((*arg == '\0') || (*endptr != '\0')) { |
1493 | 0 | error_str = apr_psprintf(cmd->pool, |
1494 | 0 | "Invalid value for directive %s, expected integer", |
1495 | 0 | cmd->directive->directive); |
1496 | 0 | } |
1497 | |
|
1498 | 0 | return error_str; |
1499 | 0 | } |
1500 | | |
1501 | | AP_DECLARE_NONSTD(const char *) ap_set_string_slot_lower(cmd_parms *cmd, |
1502 | | void *struct_ptr, |
1503 | | const char *arg_) |
1504 | 0 | { |
1505 | 0 | char *arg = apr_pstrdup(cmd->pool,arg_); |
1506 | 0 | int offset = (int)(long)cmd->info; |
1507 | |
|
1508 | 0 | ap_str_tolower(arg); |
1509 | 0 | *(char **)((char *)struct_ptr + offset) = arg; |
1510 | |
|
1511 | 0 | return NULL; |
1512 | 0 | } |
1513 | | |
1514 | | AP_DECLARE_NONSTD(const char *) ap_set_flag_slot(cmd_parms *cmd, |
1515 | | void *struct_ptr_v, int arg) |
1516 | 0 | { |
1517 | 0 | int offset = (int)(long)cmd->info; |
1518 | 0 | char *struct_ptr = (char *)struct_ptr_v; |
1519 | |
|
1520 | 0 | *(int *)(struct_ptr + offset) = arg ? 1 : 0; |
1521 | |
|
1522 | 0 | return NULL; |
1523 | 0 | } |
1524 | | |
1525 | | AP_DECLARE_NONSTD(const char *) ap_set_flag_slot_char(cmd_parms *cmd, |
1526 | | void *struct_ptr_v, int arg) |
1527 | 0 | { |
1528 | 0 | int offset = (int)(long)cmd->info; |
1529 | 0 | char *struct_ptr = (char *)struct_ptr_v; |
1530 | |
|
1531 | 0 | *(struct_ptr + offset) = arg ? 1 : 0; |
1532 | |
|
1533 | 0 | return NULL; |
1534 | 0 | } |
1535 | | |
1536 | | |
1537 | | AP_DECLARE_NONSTD(const char *) ap_set_file_slot(cmd_parms *cmd, void *struct_ptr, |
1538 | | const char *arg) |
1539 | 0 | { |
1540 | | /* Prepend server_root to relative arg. |
1541 | | * This allows most args to be independent of server_root, |
1542 | | * so the server can be moved or mirrored with less pain. |
1543 | | */ |
1544 | 0 | const char *path; |
1545 | 0 | int offset = (int)(long)cmd->info; |
1546 | |
|
1547 | 0 | path = ap_server_root_relative(cmd->pool, arg); |
1548 | |
|
1549 | 0 | if (!path) { |
1550 | 0 | return apr_pstrcat(cmd->pool, cmd->cmd->name, ": Invalid file path '", |
1551 | 0 | arg, "'", NULL); |
1552 | 0 | } |
1553 | | |
1554 | 0 | *(const char **) ((char*)struct_ptr + offset) = path; |
1555 | |
|
1556 | 0 | return NULL; |
1557 | 0 | } |
1558 | | |
1559 | | AP_DECLARE_NONSTD(const char *) ap_set_deprecated(cmd_parms *cmd, |
1560 | | void *struct_ptr, |
1561 | | const char *arg) |
1562 | 0 | { |
1563 | 0 | return cmd->cmd->errmsg; |
1564 | 0 | } |
1565 | | |
1566 | | AP_DECLARE(void) ap_reset_module_loglevels(struct ap_logconf *l, int val) |
1567 | 0 | { |
1568 | 0 | if (l->module_levels) |
1569 | 0 | memset(l->module_levels, val, conf_vector_length); |
1570 | 0 | } |
1571 | | |
1572 | | AP_DECLARE(void) ap_set_module_loglevel(apr_pool_t *pool, struct ap_logconf *l, |
1573 | | int index, int level) |
1574 | 0 | { |
1575 | 0 | if (!l->module_levels) { |
1576 | 0 | l->module_levels = apr_palloc(pool, conf_vector_length); |
1577 | 0 | if (l->level == APLOG_UNSET) { |
1578 | 0 | ap_reset_module_loglevels(l, APLOG_UNSET); |
1579 | 0 | } |
1580 | 0 | else { |
1581 | 0 | ap_reset_module_loglevels(l, APLOG_NO_MODULE); |
1582 | 0 | } |
1583 | 0 | } |
1584 | |
|
1585 | 0 | l->module_levels[index] = level; |
1586 | 0 | } |
1587 | | |
1588 | | /***************************************************************** |
1589 | | * |
1590 | | * Reading whole config files... |
1591 | | */ |
1592 | | |
1593 | | static cmd_parms default_parms = |
1594 | | {NULL, 0, 0, NULL, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; |
1595 | | |
1596 | | AP_DECLARE(char *) ap_server_root_relative(apr_pool_t *p, const char *file) |
1597 | 0 | { |
1598 | 0 | char *newpath = NULL; |
1599 | 0 | apr_status_t rv; |
1600 | 0 | rv = apr_filepath_merge(&newpath, ap_server_root, file, |
1601 | 0 | APR_FILEPATH_TRUENAME, p); |
1602 | 0 | if (newpath && (rv == APR_SUCCESS || APR_STATUS_IS_EPATHWILD(rv) |
1603 | 0 | || APR_STATUS_IS_ENOENT(rv) |
1604 | 0 | || APR_STATUS_IS_ENOTDIR(rv))) { |
1605 | 0 | return newpath; |
1606 | 0 | } |
1607 | 0 | else { |
1608 | 0 | return NULL; |
1609 | 0 | } |
1610 | 0 | } |
1611 | | |
1612 | | AP_DECLARE(char *) ap_runtime_dir_relative(apr_pool_t *p, const char *file) |
1613 | 0 | { |
1614 | 0 | char *newpath = NULL; |
1615 | 0 | apr_status_t rv; |
1616 | 0 | const char *runtime_dir = ap_runtime_dir ? ap_runtime_dir : ap_server_root_relative(p, DEFAULT_REL_RUNTIMEDIR); |
1617 | |
|
1618 | 0 | rv = apr_filepath_merge(&newpath, runtime_dir, file, |
1619 | 0 | APR_FILEPATH_TRUENAME, p); |
1620 | 0 | if (newpath && (rv == APR_SUCCESS || APR_STATUS_IS_EPATHWILD(rv) |
1621 | 0 | || APR_STATUS_IS_ENOENT(rv) |
1622 | 0 | || APR_STATUS_IS_ENOTDIR(rv))) { |
1623 | 0 | return newpath; |
1624 | 0 | } |
1625 | 0 | else { |
1626 | 0 | return NULL; |
1627 | 0 | } |
1628 | 0 | } |
1629 | | |
1630 | | |
1631 | | AP_DECLARE(const char *) ap_soak_end_container(cmd_parms *cmd, const char *directive) |
1632 | 0 | { |
1633 | 0 | struct ap_varbuf vb; |
1634 | 0 | const char *args; |
1635 | 0 | char *cmd_name; |
1636 | 0 | apr_status_t rc; |
1637 | 0 | apr_size_t max_len = VARBUF_MAX_LEN; |
1638 | 0 | if (cmd->pool == cmd->temp_pool) |
1639 | 0 | max_len = HUGE_STRING_LEN; /* lower limit for .htaccess */ |
1640 | |
|
1641 | 0 | ap_varbuf_init(cmd->temp_pool, &vb, VARBUF_INIT_LEN); |
1642 | |
|
1643 | 0 | while ((rc = ap_varbuf_cfg_getline(&vb, cmd->config_file, max_len)) |
1644 | 0 | == APR_SUCCESS) { |
1645 | 0 | args = vb.buf; |
1646 | |
|
1647 | 0 | cmd_name = ap_getword_conf(cmd->temp_pool, &args); |
1648 | 0 | if (cmd_name[0] == '<') { |
1649 | 0 | if (cmd_name[1] == '/') { |
1650 | 0 | cmd_name[strlen(cmd_name) - 1] = '\0'; |
1651 | |
|
1652 | 0 | if (ap_cstr_casecmp(cmd_name + 2, directive + 1) != 0) { |
1653 | 0 | return apr_pstrcat(cmd->pool, "Expected </", |
1654 | 0 | directive + 1, "> but saw ", |
1655 | 0 | cmd_name, ">", NULL); |
1656 | 0 | } |
1657 | | |
1658 | 0 | ap_varbuf_free(&vb); |
1659 | 0 | return NULL; /* found end of container */ |
1660 | 0 | } |
1661 | 0 | else { |
1662 | 0 | const char *msg; |
1663 | |
|
1664 | 0 | if (*args == '\0' && cmd_name[strlen(cmd_name) - 1] == '>') { |
1665 | 0 | cmd_name[strlen(cmd_name) - 1] = '\0'; |
1666 | 0 | } |
1667 | |
|
1668 | 0 | if ((msg = ap_soak_end_container(cmd, cmd_name)) != NULL) { |
1669 | 0 | return msg; |
1670 | 0 | } |
1671 | 0 | } |
1672 | 0 | } |
1673 | 0 | } |
1674 | 0 | if (rc != APR_EOF && rc != APR_SUCCESS) |
1675 | 0 | return ap_pcfg_strerror(cmd->temp_pool, cmd->config_file, rc); |
1676 | | |
1677 | 0 | return apr_pstrcat(cmd->pool, "Expected </", |
1678 | 0 | directive + 1, "> before end of configuration", |
1679 | 0 | NULL); |
1680 | 0 | } |
1681 | | |
1682 | | static const char *execute_now(char *cmd_line, const char *args, |
1683 | | cmd_parms *parms, |
1684 | | apr_pool_t *p, apr_pool_t *ptemp, |
1685 | | ap_directive_t **sub_tree, |
1686 | | ap_directive_t *parent) |
1687 | 0 | { |
1688 | 0 | const command_rec *cmd; |
1689 | 0 | ap_mod_list *ml; |
1690 | 0 | char *dir = apr_pstrdup(parms->temp_pool, cmd_line); |
1691 | |
|
1692 | 0 | ap_str_tolower(dir); |
1693 | |
|
1694 | 0 | ml = apr_hash_get(ap_config_hash, dir, APR_HASH_KEY_STRING); |
1695 | |
|
1696 | 0 | if (ml == NULL) { |
1697 | 0 | return apr_pstrcat(parms->pool, "Invalid command '", |
1698 | 0 | cmd_line, |
1699 | 0 | "', perhaps misspelled or defined by a module " |
1700 | 0 | "not included in the server configuration", |
1701 | 0 | NULL); |
1702 | 0 | } |
1703 | | |
1704 | 0 | for ( ; ml != NULL; ml = ml->next) { |
1705 | 0 | const char *retval; |
1706 | 0 | cmd = ml->cmd; |
1707 | |
|
1708 | 0 | retval = invoke_cmd(cmd, parms, sub_tree, args, parent); |
1709 | |
|
1710 | 0 | if (retval != NULL) { |
1711 | 0 | return retval; |
1712 | 0 | } |
1713 | 0 | } |
1714 | | |
1715 | 0 | return NULL; |
1716 | 0 | } |
1717 | | |
1718 | | /* This structure and the following functions are needed for the |
1719 | | * table-based config file reading. They are passed to the |
1720 | | * cfg_open_custom() routine. |
1721 | | */ |
1722 | | |
1723 | | /* Structure to be passed to cfg_open_custom(): it contains an |
1724 | | * index which is incremented from 0 to nelts on each call to |
1725 | | * cfg_getline() (which in turn calls arr_elts_getstr()) |
1726 | | * and an apr_array_header_t pointer for the string array. |
1727 | | */ |
1728 | | typedef struct { |
1729 | | apr_array_header_t *array; |
1730 | | int curr_idx; |
1731 | | } arr_elts_param_t; |
1732 | | |
1733 | | |
1734 | | /* arr_elts_getstr() returns the next line from the string array. */ |
1735 | | static apr_status_t arr_elts_getstr(void *buf, apr_size_t bufsiz, void *param) |
1736 | 0 | { |
1737 | 0 | arr_elts_param_t *arr_param = (arr_elts_param_t *)param; |
1738 | 0 | const char *elt; |
1739 | | |
1740 | | /* End of array reached? */ |
1741 | 0 | if (++arr_param->curr_idx > arr_param->array->nelts) |
1742 | 0 | return APR_EOF; |
1743 | | |
1744 | | /* return the line */ |
1745 | 0 | elt = ((const char **)arr_param->array->elts)[arr_param->curr_idx - 1]; |
1746 | 0 | if (apr_cpystrn(buf, elt, bufsiz) - (char *)buf >= bufsiz - 1) |
1747 | 0 | return APR_ENOSPC; |
1748 | 0 | return APR_SUCCESS; |
1749 | 0 | } |
1750 | | |
1751 | | |
1752 | | /* arr_elts_close(): dummy close routine (makes sure no more lines can be read) */ |
1753 | | static apr_status_t arr_elts_close(void *param) |
1754 | 0 | { |
1755 | 0 | arr_elts_param_t *arr_param = (arr_elts_param_t *)param; |
1756 | |
|
1757 | 0 | arr_param->curr_idx = arr_param->array->nelts; |
1758 | |
|
1759 | 0 | return APR_SUCCESS; |
1760 | 0 | } |
1761 | | |
1762 | | static const char *process_command_config(server_rec *s, |
1763 | | apr_array_header_t *arr, |
1764 | | ap_directive_t **conftree, |
1765 | | apr_pool_t *p, |
1766 | | apr_pool_t *ptemp) |
1767 | 0 | { |
1768 | 0 | const char *errmsg; |
1769 | 0 | cmd_parms parms; |
1770 | 0 | arr_elts_param_t arr_parms; |
1771 | |
|
1772 | 0 | arr_parms.curr_idx = 0; |
1773 | 0 | arr_parms.array = arr; |
1774 | |
|
1775 | 0 | if (ap_config_hash == NULL) { |
1776 | 0 | rebuild_conf_hash(s->process->pconf, 1); |
1777 | 0 | } |
1778 | |
|
1779 | 0 | parms = default_parms; |
1780 | 0 | parms.pool = p; |
1781 | 0 | parms.temp_pool = ptemp; |
1782 | 0 | parms.server = s; |
1783 | 0 | parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT); |
1784 | 0 | parms.override_opts = OPT_ALL | OPT_SYM_OWNER | OPT_MULTI; |
1785 | |
|
1786 | 0 | parms.config_file = ap_pcfg_open_custom(p, "-c/-C directives", |
1787 | 0 | &arr_parms, NULL, |
1788 | 0 | arr_elts_getstr, arr_elts_close); |
1789 | |
|
1790 | 0 | errmsg = ap_build_config(&parms, p, ptemp, conftree); |
1791 | 0 | ap_cfg_closefile(parms.config_file); |
1792 | |
|
1793 | 0 | if (errmsg) { |
1794 | 0 | return apr_pstrcat(p, "Syntax error in -C/-c directive: ", errmsg, |
1795 | 0 | NULL); |
1796 | 0 | } |
1797 | | |
1798 | 0 | return NULL; |
1799 | 0 | } |
1800 | | |
1801 | | /** |
1802 | | * Used by -D DUMP_INCLUDES to output the config file "tree". |
1803 | | */ |
1804 | | static void dump_config_name(const char *fname, apr_pool_t *p) |
1805 | 0 | { |
1806 | 0 | unsigned i, recursion, line_number; |
1807 | 0 | void *data; |
1808 | 0 | apr_file_t *out = NULL; |
1809 | |
|
1810 | 0 | apr_file_open_stdout(&out, p); |
1811 | | |
1812 | | /* ap_include_sentinel is defined by the core Include directive; use it to |
1813 | | * figure out how deep in the stack we are. |
1814 | | */ |
1815 | 0 | apr_pool_userdata_get(&data, "ap_include_sentinel", p); |
1816 | |
|
1817 | 0 | if (data) { |
1818 | 0 | recursion = *(unsigned *)data; |
1819 | 0 | } else { |
1820 | 0 | recursion = 0; |
1821 | 0 | } |
1822 | | |
1823 | | /* Indent once for each level. */ |
1824 | 0 | for (i = 0; i < (recursion + 1); ++i) { |
1825 | 0 | apr_file_printf(out, " "); |
1826 | 0 | } |
1827 | | |
1828 | | /* ap_include_lineno is similarly defined to tell us where in the last |
1829 | | * config file we were. |
1830 | | */ |
1831 | 0 | apr_pool_userdata_get(&data, "ap_include_lineno", p); |
1832 | |
|
1833 | 0 | if (data) { |
1834 | 0 | line_number = *(unsigned *)data; |
1835 | 0 | } else { |
1836 | 0 | line_number = 0; |
1837 | 0 | } |
1838 | | |
1839 | | /* Print the line number and the name of the parsed file. */ |
1840 | 0 | if (line_number > 0) { |
1841 | 0 | apr_file_printf(out, "(%u)", line_number); |
1842 | 0 | } else { |
1843 | 0 | apr_file_printf(out, "(*)"); |
1844 | 0 | } |
1845 | |
|
1846 | 0 | apr_file_printf(out, " %s\n", fname); |
1847 | 0 | } |
1848 | | |
1849 | | AP_DECLARE(const char *) ap_process_resource_config(server_rec *s, |
1850 | | const char *fname, |
1851 | | ap_directive_t **conftree, |
1852 | | apr_pool_t *p, |
1853 | | apr_pool_t *ptemp) |
1854 | 0 | { |
1855 | 0 | ap_configfile_t *cfp; |
1856 | 0 | cmd_parms parms; |
1857 | 0 | apr_status_t rv; |
1858 | 0 | const char *error; |
1859 | |
|
1860 | 0 | parms = default_parms; |
1861 | 0 | parms.pool = p; |
1862 | 0 | parms.temp_pool = ptemp; |
1863 | 0 | parms.server = s; |
1864 | 0 | parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT); |
1865 | 0 | parms.override_opts = OPT_ALL | OPT_SYM_OWNER | OPT_MULTI; |
1866 | |
|
1867 | 0 | rv = ap_pcfg_openfile(&cfp, p, fname); |
1868 | 0 | if (rv != APR_SUCCESS) { |
1869 | 0 | return apr_psprintf(p, "Could not open configuration file %s: %pm", |
1870 | 0 | fname, &rv); |
1871 | 0 | } |
1872 | | |
1873 | 0 | if (ap_exists_config_define("DUMP_INCLUDES")) { |
1874 | 0 | dump_config_name(fname, p); |
1875 | 0 | } |
1876 | |
|
1877 | 0 | parms.config_file = cfp; |
1878 | 0 | error = ap_build_config(&parms, p, ptemp, conftree); |
1879 | 0 | ap_cfg_closefile(cfp); |
1880 | |
|
1881 | 0 | if (error) { |
1882 | 0 | if (parms.err_directive) |
1883 | | /* note: this may not be a 'syntactic' error per se. |
1884 | | * should it rather be "Configuration error ..."? |
1885 | | */ |
1886 | 0 | return apr_psprintf(p, "Syntax error on line %d of %s: %s", |
1887 | 0 | parms.err_directive->line_num, |
1888 | 0 | parms.err_directive->filename, error); |
1889 | 0 | else |
1890 | 0 | return error; |
1891 | 0 | } |
1892 | | |
1893 | 0 | return NULL; |
1894 | 0 | } |
1895 | | |
1896 | | typedef struct { |
1897 | | server_rec *s; |
1898 | | ap_directive_t **conftree; |
1899 | | } configs; |
1900 | | |
1901 | | static const char *process_resource_config_cb(ap_dir_match_t *w, const char *fname) |
1902 | 0 | { |
1903 | 0 | configs *cfgs = w->ctx; |
1904 | 0 | return ap_process_resource_config(cfgs->s, fname, cfgs->conftree, w->p, w->ptemp); |
1905 | 0 | } |
1906 | | |
1907 | | AP_DECLARE(const char *) ap_process_fnmatch_configs(server_rec *s, |
1908 | | const char *fname, |
1909 | | ap_directive_t **conftree, |
1910 | | apr_pool_t *p, |
1911 | | apr_pool_t *ptemp, |
1912 | | int optional) |
1913 | 0 | { |
1914 | 0 | configs cfgs; |
1915 | 0 | ap_dir_match_t w; |
1916 | |
|
1917 | 0 | cfgs.s = s; |
1918 | 0 | cfgs.conftree = conftree; |
1919 | |
|
1920 | 0 | w.prefix = "Include/IncludeOptional: "; |
1921 | 0 | w.p = p; |
1922 | 0 | w.ptemp = ptemp; |
1923 | 0 | w.flags = (optional ? AP_DIR_FLAG_OPTIONAL : AP_DIR_FLAG_NONE) | AP_DIR_FLAG_RECURSIVE; |
1924 | 0 | w.cb = process_resource_config_cb; |
1925 | 0 | w.ctx = &cfgs; |
1926 | 0 | w.depth = 0; |
1927 | | |
1928 | | /* don't require conf/httpd.conf if we have a -C or -c switch */ |
1929 | 0 | if ((ap_server_pre_read_config->nelts |
1930 | 0 | || ap_server_post_read_config->nelts) |
1931 | 0 | && !(strcmp(fname, ap_server_root_relative(ptemp, SERVER_CONFIG_FILE)))) { |
1932 | 0 | apr_finfo_t finfo; |
1933 | |
|
1934 | 0 | if (apr_stat(&finfo, fname, APR_FINFO_LINK | APR_FINFO_TYPE, ptemp) != APR_SUCCESS) |
1935 | 0 | return NULL; |
1936 | 0 | } |
1937 | | |
1938 | 0 | if (!apr_fnmatch_test(fname)) { |
1939 | 0 | return ap_dir_nofnmatch(&w, fname); |
1940 | 0 | } |
1941 | 0 | else { |
1942 | 0 | apr_status_t status; |
1943 | 0 | const char *rootpath, *filepath = fname; |
1944 | | |
1945 | | /* locate the start of the directories proper */ |
1946 | 0 | status = apr_filepath_root(&rootpath, &filepath, APR_FILEPATH_TRUENAME, ptemp); |
1947 | | |
1948 | | /* we allow APR_SUCCESS and APR_EINCOMPLETE */ |
1949 | 0 | if (APR_ERELATIVE == status) { |
1950 | 0 | return apr_pstrcat(p, "Include must have an absolute path, ", fname, NULL); |
1951 | 0 | } |
1952 | 0 | else if (APR_EBADPATH == status) { |
1953 | 0 | return apr_pstrcat(p, "Include has a bad path, ", fname, NULL); |
1954 | 0 | } |
1955 | | |
1956 | | /* walk the filepath */ |
1957 | 0 | return ap_dir_fnmatch(&w, rootpath, filepath); |
1958 | 0 | } |
1959 | 0 | } |
1960 | | |
1961 | | AP_DECLARE(int) ap_process_config_tree(server_rec *s, |
1962 | | ap_directive_t *conftree, |
1963 | | apr_pool_t *p, |
1964 | | apr_pool_t *ptemp) |
1965 | 0 | { |
1966 | 0 | const char *errmsg; |
1967 | 0 | cmd_parms parms; |
1968 | |
|
1969 | 0 | parms = default_parms; |
1970 | 0 | parms.pool = p; |
1971 | 0 | parms.temp_pool = ptemp; |
1972 | 0 | parms.server = s; |
1973 | 0 | parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT); |
1974 | 0 | parms.override_opts = OPT_ALL | OPT_SYM_OWNER | OPT_MULTI; |
1975 | 0 | parms.limited = -1; |
1976 | |
|
1977 | 0 | errmsg = ap_walk_config(conftree, &parms, s->lookup_defaults); |
1978 | 0 | if (errmsg) { |
1979 | 0 | if (parms.err_directive) |
1980 | 0 | ap_log_perror(APLOG_MARK, APLOG_STARTUP, 0, p, APLOGNO(00526) |
1981 | 0 | "Syntax error on line %d of %s:", |
1982 | 0 | parms.err_directive->line_num, |
1983 | 0 | parms.err_directive->filename); |
1984 | 0 | ap_log_perror(APLOG_MARK, APLOG_STARTUP, 0, p, "%s", errmsg); |
1985 | 0 | return HTTP_INTERNAL_SERVER_ERROR; |
1986 | 0 | } |
1987 | | |
1988 | 0 | return OK; |
1989 | 0 | } |
1990 | | |
1991 | | apr_status_t ap_open_htaccess(request_rec *r, const char *dir_name, |
1992 | | const char *access_name, |
1993 | | ap_configfile_t **conffile, |
1994 | | const char **full_name) |
1995 | 0 | { |
1996 | 0 | *full_name = ap_make_full_path(r->pool, dir_name, access_name); |
1997 | 0 | return ap_pcfg_openfile(conffile, r->pool, *full_name); |
1998 | 0 | } |
1999 | | |
2000 | | AP_CORE_DECLARE(int) ap_parse_htaccess(ap_conf_vector_t **result, |
2001 | | request_rec *r, int override, |
2002 | | int override_opts, apr_table_t *override_list, |
2003 | | const char *d, const char *access_names) |
2004 | 0 | { |
2005 | 0 | ap_configfile_t *f = NULL; |
2006 | 0 | cmd_parms parms; |
2007 | 0 | const char *filename; |
2008 | 0 | const struct htaccess_result *cache; |
2009 | 0 | struct htaccess_result *new; |
2010 | 0 | ap_conf_vector_t *dc = NULL; |
2011 | 0 | apr_status_t status; |
2012 | | |
2013 | | /* firstly, search cache */ |
2014 | 0 | for (cache = r->htaccess; cache != NULL; cache = cache->next) { |
2015 | 0 | if (cache->override == override && strcmp(cache->dir, d) == 0) { |
2016 | 0 | *result = cache->htaccess; |
2017 | 0 | return OK; |
2018 | 0 | } |
2019 | 0 | } |
2020 | | |
2021 | 0 | parms = default_parms; |
2022 | 0 | parms.override = override; |
2023 | 0 | parms.override_opts = override_opts; |
2024 | 0 | parms.override_list = override_list; |
2025 | 0 | parms.pool = r->pool; |
2026 | 0 | parms.temp_pool = r->pool; |
2027 | 0 | parms.server = r->server; |
2028 | 0 | parms.path = apr_pstrdup(r->pool, d); |
2029 | | |
2030 | | /* loop through the access names and find the first one */ |
2031 | 0 | while (access_names[0]) { |
2032 | 0 | const char *access_name = ap_getword_conf(r->pool, &access_names); |
2033 | |
|
2034 | 0 | filename = NULL; |
2035 | 0 | status = ap_run_open_htaccess(r, d, access_name, &f, &filename); |
2036 | 0 | if (status == APR_SUCCESS) { |
2037 | 0 | const char *errmsg; |
2038 | 0 | ap_directive_t *temptree = NULL; |
2039 | | |
2040 | | /* Mark the request as tainted by .htaccess */ |
2041 | 0 | r->taint |= AP_TAINT_HTACCESS; |
2042 | 0 | dc = ap_create_per_dir_config(r->pool); |
2043 | |
|
2044 | 0 | parms.config_file = f; |
2045 | 0 | errmsg = ap_build_config(&parms, r->pool, r->pool, &temptree); |
2046 | 0 | if (errmsg == NULL) |
2047 | 0 | errmsg = ap_walk_config(temptree, &parms, dc); |
2048 | |
|
2049 | 0 | ap_cfg_closefile(f); |
2050 | |
|
2051 | 0 | if (errmsg) { |
2052 | 0 | ap_log_rerror(APLOG_MARK, APLOG_ALERT, 0, r, |
2053 | 0 | "%s: %s", filename, errmsg); |
2054 | 0 | return HTTP_INTERNAL_SERVER_ERROR; |
2055 | 0 | } |
2056 | | |
2057 | 0 | *result = dc; |
2058 | 0 | break; |
2059 | 0 | } |
2060 | 0 | else { |
2061 | 0 | if (!APR_STATUS_IS_ENOENT(status) |
2062 | 0 | && !APR_STATUS_IS_ENOTDIR(status)) { |
2063 | 0 | ap_log_rerror(APLOG_MARK, APLOG_CRIT, status, r, APLOGNO(00529) |
2064 | 0 | "%s pcfg_openfile: unable to check htaccess file, " |
2065 | 0 | "ensure it is readable and that '%s' " |
2066 | 0 | "is executable", |
2067 | 0 | filename, d); |
2068 | 0 | apr_table_setn(r->notes, "error-notes", |
2069 | 0 | "Server unable to read htaccess file, denying " |
2070 | 0 | "access to be safe"); |
2071 | 0 | return HTTP_FORBIDDEN; |
2072 | 0 | } |
2073 | 0 | } |
2074 | 0 | } |
2075 | | |
2076 | | /* cache it */ |
2077 | 0 | new = apr_palloc(r->pool, sizeof(struct htaccess_result)); |
2078 | 0 | new->dir = parms.path; |
2079 | 0 | new->override = override; |
2080 | 0 | new->override_opts = override_opts; |
2081 | 0 | new->htaccess = dc; |
2082 | | |
2083 | | /* add to head of list */ |
2084 | 0 | new->next = r->htaccess; |
2085 | 0 | r->htaccess = new; |
2086 | |
|
2087 | 0 | return OK; |
2088 | 0 | } |
2089 | | |
2090 | | AP_CORE_DECLARE(const char *) ap_init_virtual_host(apr_pool_t *p, |
2091 | | const char *hostname, |
2092 | | server_rec *main_server, |
2093 | | server_rec **ps) |
2094 | 0 | { |
2095 | 0 | server_rec *s = (server_rec *) apr_pcalloc(p, sizeof(server_rec)); |
2096 | | |
2097 | | /* TODO: this crap belongs in http_core */ |
2098 | 0 | s->process = main_server->process; |
2099 | 0 | s->server_admin = NULL; |
2100 | 0 | s->server_hostname = NULL; |
2101 | 0 | s->server_scheme = NULL; |
2102 | 0 | s->error_fname = NULL; |
2103 | 0 | s->timeout = 0; |
2104 | 0 | s->keep_alive_timeout = 0; |
2105 | 0 | s->keep_alive = -1; |
2106 | 0 | s->keep_alive_max = -1; |
2107 | 0 | s->error_log = main_server->error_log; |
2108 | 0 | s->log.level = APLOG_UNSET; |
2109 | 0 | s->log.module_levels = NULL; |
2110 | | /* useful default, otherwise we get a port of 0 on redirects */ |
2111 | 0 | s->port = main_server->port; |
2112 | 0 | s->next = NULL; |
2113 | |
|
2114 | 0 | s->is_virtual = 1; |
2115 | 0 | s->names = apr_array_make(p, 4, sizeof(char **)); |
2116 | 0 | s->wild_names = apr_array_make(p, 4, sizeof(char **)); |
2117 | |
|
2118 | 0 | s->module_config = create_empty_config(p); |
2119 | 0 | s->lookup_defaults = ap_create_per_dir_config(p); |
2120 | |
|
2121 | 0 | s->limit_req_line = main_server->limit_req_line; |
2122 | 0 | s->limit_req_fieldsize = main_server->limit_req_fieldsize; |
2123 | 0 | s->limit_req_fields = main_server->limit_req_fields; |
2124 | |
|
2125 | 0 | *ps = s; |
2126 | |
|
2127 | 0 | return ap_parse_vhost_addrs(p, hostname, s); |
2128 | 0 | } |
2129 | | |
2130 | | AP_DECLARE(struct ap_logconf *) ap_new_log_config(apr_pool_t *p, |
2131 | | const struct ap_logconf *old) |
2132 | 0 | { |
2133 | 0 | struct ap_logconf *l = apr_pcalloc(p, sizeof(struct ap_logconf)); |
2134 | 0 | if (old) { |
2135 | 0 | l->level = old->level; |
2136 | 0 | if (old->module_levels) { |
2137 | 0 | l->module_levels = |
2138 | 0 | apr_pmemdup(p, old->module_levels, conf_vector_length); |
2139 | 0 | } |
2140 | 0 | } |
2141 | 0 | else { |
2142 | 0 | l->level = APLOG_UNSET; |
2143 | 0 | } |
2144 | 0 | return l; |
2145 | 0 | } |
2146 | | |
2147 | | AP_DECLARE(void) ap_merge_log_config(const struct ap_logconf *old_conf, |
2148 | | struct ap_logconf *new_conf) |
2149 | 0 | { |
2150 | 0 | if (new_conf->level != APLOG_UNSET) { |
2151 | | /* Setting the main loglevel resets all per-module log levels. |
2152 | | * I.e. if new->level has been set, we must ignore old->module_levels. |
2153 | | */ |
2154 | 0 | return; |
2155 | 0 | } |
2156 | | |
2157 | 0 | new_conf->level = old_conf->level; |
2158 | 0 | if (new_conf->module_levels == NULL) { |
2159 | 0 | new_conf->module_levels = old_conf->module_levels; |
2160 | 0 | } |
2161 | 0 | else if (old_conf->module_levels != NULL) { |
2162 | 0 | int i; |
2163 | 0 | for (i = 0; i < conf_vector_length; i++) { |
2164 | 0 | if (new_conf->module_levels[i] == APLOG_UNSET) |
2165 | 0 | new_conf->module_levels[i] = old_conf->module_levels[i]; |
2166 | 0 | } |
2167 | 0 | } |
2168 | 0 | } |
2169 | | |
2170 | | AP_DECLARE(void) ap_fixup_virtual_hosts(apr_pool_t *p, server_rec *main_server) |
2171 | 0 | { |
2172 | 0 | server_rec *virt; |
2173 | 0 | core_dir_config *dconf = |
2174 | 0 | ap_get_core_module_config(main_server->lookup_defaults); |
2175 | 0 | dconf->log = &main_server->log; |
2176 | |
|
2177 | 0 | for (virt = main_server->next; virt; virt = virt->next) { |
2178 | 0 | merge_server_configs(p, main_server->module_config, virt); |
2179 | |
|
2180 | 0 | virt->lookup_defaults = |
2181 | 0 | ap_merge_per_dir_configs(p, main_server->lookup_defaults, |
2182 | 0 | virt->lookup_defaults); |
2183 | |
|
2184 | 0 | if (virt->server_admin == NULL) |
2185 | 0 | virt->server_admin = main_server->server_admin; |
2186 | |
|
2187 | 0 | if (virt->timeout == 0) |
2188 | 0 | virt->timeout = main_server->timeout; |
2189 | |
|
2190 | 0 | if (virt->keep_alive_timeout == 0) |
2191 | 0 | virt->keep_alive_timeout = main_server->keep_alive_timeout; |
2192 | |
|
2193 | 0 | if (virt->keep_alive == -1) |
2194 | 0 | virt->keep_alive = main_server->keep_alive; |
2195 | |
|
2196 | 0 | if (virt->keep_alive_max == -1) |
2197 | 0 | virt->keep_alive_max = main_server->keep_alive_max; |
2198 | |
|
2199 | 0 | ap_merge_log_config(&main_server->log, &virt->log); |
2200 | |
|
2201 | 0 | dconf = ap_get_core_module_config(virt->lookup_defaults); |
2202 | 0 | dconf->log = &virt->log; |
2203 | | |
2204 | | /* XXX: this is really something that should be dealt with by a |
2205 | | * post-config api phase |
2206 | | */ |
2207 | 0 | ap_core_reorder_directories(p, virt); |
2208 | 0 | } |
2209 | |
|
2210 | 0 | ap_core_reorder_directories(p, main_server); |
2211 | 0 | } |
2212 | | |
2213 | | /***************************************************************** |
2214 | | * |
2215 | | * Getting *everything* configured... |
2216 | | */ |
2217 | | |
2218 | | static void init_config_globals(apr_pool_t *p) |
2219 | 0 | { |
2220 | | /* Global virtual host hash bucket pointers. Init to null. */ |
2221 | 0 | ap_init_vhost_config(p); |
2222 | 0 | } |
2223 | | |
2224 | | static server_rec *init_server_config(process_rec *process, apr_pool_t *p) |
2225 | 0 | { |
2226 | 0 | apr_status_t rv; |
2227 | 0 | server_rec *s = (server_rec *) apr_pcalloc(p, sizeof(server_rec)); |
2228 | |
|
2229 | 0 | apr_file_open_stderr(&s->error_log, p); |
2230 | 0 | s->process = process; |
2231 | 0 | s->port = 0; |
2232 | 0 | s->server_admin = DEFAULT_ADMIN; |
2233 | 0 | s->server_hostname = NULL; |
2234 | 0 | s->server_scheme = NULL; |
2235 | 0 | s->error_fname = DEFAULT_ERRORLOG; |
2236 | 0 | s->log.level = DEFAULT_LOGLEVEL; |
2237 | 0 | s->log.module_levels = NULL; |
2238 | 0 | s->limit_req_line = DEFAULT_LIMIT_REQUEST_LINE; |
2239 | 0 | s->limit_req_fieldsize = DEFAULT_LIMIT_REQUEST_FIELDSIZE; |
2240 | 0 | s->limit_req_fields = DEFAULT_LIMIT_REQUEST_FIELDS; |
2241 | 0 | s->timeout = apr_time_from_sec(DEFAULT_TIMEOUT); |
2242 | 0 | s->keep_alive_timeout = apr_time_from_sec(DEFAULT_KEEPALIVE_TIMEOUT); |
2243 | 0 | s->keep_alive_max = DEFAULT_KEEPALIVE; |
2244 | 0 | s->keep_alive = 1; |
2245 | 0 | s->next = NULL; |
2246 | 0 | s->addrs = apr_pcalloc(p, sizeof(server_addr_rec)); |
2247 | | |
2248 | | /* NOT virtual host; don't match any real network interface */ |
2249 | 0 | rv = apr_sockaddr_info_get(&s->addrs->host_addr, |
2250 | 0 | NULL, APR_UNSPEC, 0, 0, p); |
2251 | 0 | if (rv != APR_SUCCESS) { |
2252 | | /* should we test here for rv being an EAIERR? */ |
2253 | 0 | ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, rv, NULL, APLOGNO(00530) |
2254 | 0 | "initialisation: bug or getaddrinfo fail"); |
2255 | 0 | return NULL; |
2256 | 0 | } |
2257 | | |
2258 | 0 | s->addrs->host_port = 0; /* matches any port */ |
2259 | 0 | s->addrs->virthost = ""; /* must be non-NULL */ |
2260 | 0 | s->names = s->wild_names = NULL; |
2261 | |
|
2262 | 0 | s->module_config = create_server_config(p, s); |
2263 | 0 | s->lookup_defaults = create_default_per_dir_config(p); |
2264 | |
|
2265 | 0 | return s; |
2266 | 0 | } |
2267 | | |
2268 | | |
2269 | | static apr_status_t reset_conf_vector_length(void *dummy) |
2270 | 0 | { |
2271 | 0 | reserved_module_slots = 0; |
2272 | 0 | conf_vector_length = max_modules; |
2273 | 0 | return APR_SUCCESS; |
2274 | 0 | } |
2275 | | |
2276 | | static int conf_vector_length_pre_config(apr_pool_t *pconf, apr_pool_t *plog, |
2277 | | apr_pool_t *ptemp) |
2278 | 0 | { |
2279 | | /* |
2280 | | * We have loaded all modules that are loaded by EXEC_ON_READ directives. |
2281 | | * From now on we reduce the size of the config vectors to what we need, |
2282 | | * plus what has been reserved (e.g. by mod_perl) for additional modules |
2283 | | * loaded later on. |
2284 | | * If max_modules is too small, ap_add_module() will abort. |
2285 | | */ |
2286 | 0 | if (total_modules + reserved_module_slots < max_modules) { |
2287 | 0 | conf_vector_length = total_modules + reserved_module_slots; |
2288 | 0 | } |
2289 | 0 | apr_pool_cleanup_register(pconf, NULL, reset_conf_vector_length, |
2290 | 0 | apr_pool_cleanup_null); |
2291 | 0 | return OK; |
2292 | 0 | } |
2293 | | |
2294 | | |
2295 | | AP_CORE_DECLARE(void) ap_register_config_hooks(apr_pool_t *p) |
2296 | 0 | { |
2297 | 0 | ap_hook_pre_config(conf_vector_length_pre_config, NULL, NULL, |
2298 | 0 | APR_HOOK_REALLY_LAST); |
2299 | 0 | } |
2300 | | |
2301 | | AP_DECLARE(server_rec*) ap_read_config(process_rec *process, apr_pool_t *ptemp, |
2302 | | const char *filename, |
2303 | | ap_directive_t **conftree) |
2304 | 0 | { |
2305 | 0 | const char *confname, *error; |
2306 | 0 | apr_pool_t *p = process->pconf; |
2307 | 0 | server_rec *s = init_server_config(process, p); |
2308 | 0 | if (s == NULL) { |
2309 | 0 | return s; |
2310 | 0 | } |
2311 | 0 | if (ap_server_conf == NULL) { |
2312 | 0 | ap_server_conf = s; |
2313 | 0 | } |
2314 | |
|
2315 | 0 | init_config_globals(p); |
2316 | |
|
2317 | 0 | if (ap_exists_config_define("DUMP_INCLUDES")) { |
2318 | 0 | apr_file_t *out = NULL; |
2319 | 0 | apr_file_open_stdout(&out, p); |
2320 | | |
2321 | | /* Included files will be dumped as the config is walked; print a |
2322 | | * header. |
2323 | | */ |
2324 | 0 | apr_file_printf(out, "Included configuration files:\n"); |
2325 | 0 | } |
2326 | | |
2327 | | /* All server-wide config files now have the SAME syntax... */ |
2328 | 0 | error = process_command_config(s, ap_server_pre_read_config, conftree, |
2329 | 0 | p, ptemp); |
2330 | 0 | if (error) { |
2331 | 0 | ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, 0, NULL, "%s: %s", |
2332 | 0 | ap_server_argv0, error); |
2333 | 0 | return NULL; |
2334 | 0 | } |
2335 | | |
2336 | | /* process_command_config may change the ServerRoot so |
2337 | | * compute this config file name afterwards. |
2338 | | */ |
2339 | 0 | confname = ap_server_root_relative(p, filename); |
2340 | |
|
2341 | 0 | if (!confname) { |
2342 | 0 | ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, |
2343 | 0 | APR_EBADPATH, NULL, APLOGNO(00532) "Invalid config file path %s", |
2344 | 0 | filename); |
2345 | 0 | return NULL; |
2346 | 0 | } |
2347 | | |
2348 | 0 | error = ap_process_resource_config(s, confname, conftree, p, ptemp); |
2349 | 0 | if (error) { |
2350 | 0 | ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, 0, NULL, |
2351 | 0 | "%s: %s", ap_server_argv0, error); |
2352 | 0 | return NULL; |
2353 | 0 | } |
2354 | | |
2355 | 0 | error = ap_check_mpm(); |
2356 | 0 | if (error) { |
2357 | 0 | ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, 0, NULL, APLOGNO(00534) |
2358 | 0 | "%s: Configuration error: %s", ap_server_argv0, error); |
2359 | 0 | return NULL; |
2360 | 0 | } |
2361 | | |
2362 | 0 | error = process_command_config(s, ap_server_post_read_config, conftree, |
2363 | 0 | p, ptemp); |
2364 | |
|
2365 | 0 | if (error) { |
2366 | 0 | ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, 0, NULL, "%s: %s", |
2367 | 0 | ap_server_argv0, error); |
2368 | 0 | return NULL; |
2369 | 0 | } |
2370 | | |
2371 | 0 | return s; |
2372 | 0 | } |
2373 | | |
2374 | | AP_DECLARE(void) ap_single_module_configure(apr_pool_t *p, server_rec *s, |
2375 | | module *m) |
2376 | 0 | { |
2377 | 0 | if (m->create_server_config) |
2378 | 0 | ap_set_module_config(s->module_config, m, |
2379 | 0 | (*m->create_server_config)(p, s)); |
2380 | |
|
2381 | 0 | if (m->create_dir_config) |
2382 | 0 | ap_set_module_config(s->lookup_defaults, m, |
2383 | 0 | (*m->create_dir_config)(p, NULL)); |
2384 | 0 | } |
2385 | | |
2386 | | AP_DECLARE(void) ap_run_rewrite_args(process_rec *process) |
2387 | 0 | { |
2388 | 0 | module *m; |
2389 | |
|
2390 | 0 | for (m = ap_top_module; m; m = m->next) { |
2391 | 0 | if (m->rewrite_args) { |
2392 | 0 | (*m->rewrite_args)(process); |
2393 | 0 | } |
2394 | 0 | } |
2395 | 0 | } |
2396 | | |
2397 | | /******************************************************************** |
2398 | | * Configuration directives are restricted in terms of where they may |
2399 | | * appear in the main configuration files and/or .htaccess files according |
2400 | | * to the bitmask req_override in the command_rec structure. |
2401 | | * If any of the overrides set in req_override are also allowed in the |
2402 | | * context in which the command is read, then the command is allowed. |
2403 | | * The context is determined as follows: |
2404 | | * |
2405 | | * inside *.conf --> override = (RSRC_CONF|OR_ALL)&~(OR_AUTHCFG|OR_LIMIT); |
2406 | | * within <Directory> or <Location> --> override = OR_ALL|ACCESS_CONF; |
2407 | | * within .htaccess --> override = AllowOverride for current directory; |
2408 | | * |
2409 | | * the result is, well, a rather confusing set of possibilities for when |
2410 | | * a particular directive is allowed to be used. This procedure prints |
2411 | | * in English where the given (pc) directive can be used. |
2412 | | */ |
2413 | | static void show_overrides(const command_rec *pc, module *pm) |
2414 | 0 | { |
2415 | 0 | int n = 0; |
2416 | |
|
2417 | 0 | printf("\tAllowed in *.conf "); |
2418 | 0 | if ((pc->req_override & (OR_OPTIONS | OR_FILEINFO | OR_INDEXES)) |
2419 | 0 | || ((pc->req_override & RSRC_CONF) |
2420 | 0 | && ((pc->req_override & (ACCESS_CONF | OR_AUTHCFG | OR_LIMIT))))) { |
2421 | 0 | printf("anywhere"); |
2422 | 0 | } |
2423 | 0 | else if (pc->req_override & RSRC_CONF) { |
2424 | 0 | printf("only outside <Directory>, <Files>, <Location>, or <If>"); |
2425 | 0 | } |
2426 | 0 | else { |
2427 | 0 | printf("only inside <Directory>, <Files>, <Location>, or <If>"); |
2428 | 0 | } |
2429 | | |
2430 | | /* Warn if the directive is allowed inside <Directory> or .htaccess |
2431 | | * but module doesn't support per-dir configuration |
2432 | | */ |
2433 | 0 | if ((pc->req_override & (OR_ALL | ACCESS_CONF)) && !pm->create_dir_config) |
2434 | 0 | printf(" [no per-dir config]"); |
2435 | |
|
2436 | 0 | if (pc->req_override & OR_ALL) { |
2437 | 0 | printf(" and in .htaccess\n\twhen AllowOverride"); |
2438 | |
|
2439 | 0 | if ((pc->req_override & OR_ALL) == OR_ALL) { |
2440 | 0 | printf(" isn't None"); |
2441 | 0 | } |
2442 | 0 | else { |
2443 | 0 | printf(" includes "); |
2444 | |
|
2445 | 0 | if (pc->req_override & OR_AUTHCFG) { |
2446 | 0 | if (n++) |
2447 | 0 | printf(" or "); |
2448 | |
|
2449 | 0 | printf("AuthConfig"); |
2450 | 0 | } |
2451 | |
|
2452 | 0 | if (pc->req_override & OR_LIMIT) { |
2453 | 0 | if (n++) |
2454 | 0 | printf(" or "); |
2455 | |
|
2456 | 0 | printf("Limit"); |
2457 | 0 | } |
2458 | |
|
2459 | 0 | if (pc->req_override & OR_OPTIONS) { |
2460 | 0 | if (n++) |
2461 | 0 | printf(" or "); |
2462 | |
|
2463 | 0 | printf("Options"); |
2464 | 0 | } |
2465 | |
|
2466 | 0 | if (pc->req_override & OR_FILEINFO) { |
2467 | 0 | if (n++) |
2468 | 0 | printf(" or "); |
2469 | |
|
2470 | 0 | printf("FileInfo"); |
2471 | 0 | } |
2472 | |
|
2473 | 0 | if (pc->req_override & OR_INDEXES) { |
2474 | 0 | if (n++) |
2475 | 0 | printf(" or "); |
2476 | |
|
2477 | 0 | printf("Indexes"); |
2478 | 0 | } |
2479 | 0 | } |
2480 | 0 | } |
2481 | |
|
2482 | 0 | printf("\n"); |
2483 | 0 | } |
2484 | | |
2485 | | /* Show the preloaded configuration directives, the help string explaining |
2486 | | * the directive arguments, in what module they are handled, and in |
2487 | | * what parts of the configuration they are allowed. Used for httpd -L. |
2488 | | */ |
2489 | | AP_DECLARE(void) ap_show_directives(void) |
2490 | 0 | { |
2491 | 0 | const command_rec *pc; |
2492 | 0 | int n; |
2493 | |
|
2494 | 0 | for (n = 0; ap_loaded_modules[n]; ++n) { |
2495 | 0 | for (pc = ap_loaded_modules[n]->cmds; pc && pc->name; ++pc) { |
2496 | 0 | printf("%s (%s)\n", pc->name, ap_loaded_modules[n]->name); |
2497 | |
|
2498 | 0 | if (pc->errmsg) |
2499 | 0 | printf("\t%s\n", pc->errmsg); |
2500 | |
|
2501 | 0 | show_overrides(pc, ap_loaded_modules[n]); |
2502 | 0 | } |
2503 | 0 | } |
2504 | 0 | } |
2505 | | |
2506 | | /* Show the preloaded module names. Used for httpd -l. */ |
2507 | | AP_DECLARE(void) ap_show_modules(void) |
2508 | 0 | { |
2509 | 0 | int n; |
2510 | |
|
2511 | 0 | printf("Compiled in modules:\n"); |
2512 | 0 | for (n = 0; ap_loaded_modules[n]; ++n) |
2513 | 0 | printf(" %s\n", ap_loaded_modules[n]->name); |
2514 | 0 | } |
2515 | | |
2516 | | AP_DECLARE(int) ap_exists_directive(apr_pool_t *p, const char *name) |
2517 | 0 | { |
2518 | 0 | char *lname = apr_pstrdup(p, name); |
2519 | |
|
2520 | 0 | ap_str_tolower(lname); |
2521 | | |
2522 | 0 | return ap_config_hash && |
2523 | 0 | apr_hash_get(ap_config_hash, lname, APR_HASH_KEY_STRING) != NULL; |
2524 | 0 | } |
2525 | | |
2526 | | AP_DECLARE(void *) ap_retained_data_get(const char *key) |
2527 | 0 | { |
2528 | 0 | void *retained; |
2529 | |
|
2530 | 0 | apr_pool_userdata_get((void *)&retained, key, ap_pglobal); |
2531 | 0 | return retained; |
2532 | 0 | } |
2533 | | |
2534 | | AP_DECLARE(void *) ap_retained_data_create(const char *key, apr_size_t size) |
2535 | 0 | { |
2536 | 0 | void *retained; |
2537 | |
|
2538 | 0 | retained = apr_pcalloc(ap_pglobal, size); |
2539 | 0 | apr_pool_userdata_set((const void *)retained, key, apr_pool_cleanup_null, ap_pglobal); |
2540 | 0 | return retained; |
2541 | 0 | } |
2542 | | |
2543 | | static int count_directives_sub(const char *directive, ap_directive_t *current) |
2544 | 0 | { |
2545 | 0 | int count = 0; |
2546 | 0 | while (current != NULL) { |
2547 | 0 | if (current->first_child != NULL) |
2548 | 0 | count += count_directives_sub(directive, current->first_child); |
2549 | 0 | if (ap_cstr_casecmp(current->directive, directive) == 0) |
2550 | 0 | count++; |
2551 | 0 | current = current->next; |
2552 | 0 | } |
2553 | 0 | return count; |
2554 | 0 | } |
2555 | | |
2556 | | AP_DECLARE(void) ap_reserve_module_slots(int count) |
2557 | 0 | { |
2558 | 0 | reserved_module_slots += count; |
2559 | 0 | } |
2560 | | |
2561 | | AP_DECLARE(void) ap_reserve_module_slots_directive(const char *directive) |
2562 | 0 | { |
2563 | 0 | ap_reserve_module_slots(count_directives_sub(directive, ap_conftree)); |
2564 | 0 | } |