From ad14e19ad0400e289b06fb7728aea815e6ed49be Mon Sep 17 00:00:00 2001 From: Stefan Fritsch Date: Tue, 27 Dec 2011 19:42:33 +0100 Subject: Upstream tarball 2.2.12 --- server/config.c | 6 ++--- server/core.c | 35 +++++++++++++++++++------- server/core_filters.c | 11 ++++++--- server/gen_test_char.c | 20 ++++++++++++++- server/listen.c | 6 ++++- server/log.c | 59 ++++++++++++++++++++++++++++++++++++-------- server/mpm/prefork/prefork.c | 40 +++++++++++++++++++----------- server/protocol.c | 7 +++++- server/request.c | 58 +++++++++++++++++++++++++++++++++++++++++-- server/util.c | 14 +++++++++-- server/util_script.c | 11 +++++++-- server/vhost.c | 2 +- 12 files changed, 219 insertions(+), 50 deletions(-) (limited to 'server') diff --git a/server/config.c b/server/config.c index 9747c284..101d0e4e 100644 --- a/server/config.c +++ b/server/config.c @@ -1510,7 +1510,7 @@ static const char *process_command_config(server_rec *s, parms.temp_pool = ptemp; parms.server = s; parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT); - parms.override_opts = OPT_ALL | OPT_INCNOEXEC | OPT_SYM_OWNER | OPT_MULTI; + parms.override_opts = OPT_ALL | OPT_SYM_OWNER | OPT_MULTI; parms.config_file = ap_pcfg_open_custom(p, "-c/-C directives", &arr_parms, NULL, @@ -1617,7 +1617,7 @@ static const char *process_resource_config_nofnmatch(server_rec *s, parms.temp_pool = ptemp; parms.server = s; parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT); - parms.override_opts = OPT_ALL | OPT_INCNOEXEC | OPT_SYM_OWNER | OPT_MULTI; + parms.override_opts = OPT_ALL | OPT_SYM_OWNER | OPT_MULTI; rv = ap_pcfg_openfile(&cfp, p, fname); if (rv != APR_SUCCESS) { @@ -1755,7 +1755,7 @@ AP_DECLARE(int) ap_process_config_tree(server_rec *s, parms.temp_pool = ptemp; parms.server = s; parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT); - parms.override_opts = OPT_ALL | OPT_INCNOEXEC | OPT_SYM_OWNER | OPT_MULTI; + parms.override_opts = OPT_ALL | OPT_SYM_OWNER | OPT_MULTI; parms.limited = -1; errmsg = ap_walk_config(conftree, &parms, s->lookup_defaults); diff --git a/server/core.c b/server/core.c index 3b1b01b7..ab437197 100644 --- a/server/core.c +++ b/server/core.c @@ -108,8 +108,7 @@ static void *create_core_dir_config(apr_pool_t *a, char *dir) conf->opts = dir ? OPT_UNSET : OPT_UNSET|OPT_ALL; conf->opts_add = conf->opts_remove = OPT_NONE; conf->override = dir ? OR_UNSET : OR_UNSET|OR_ALL; - conf->override_opts = OPT_UNSET | OPT_ALL | OPT_INCNOEXEC | OPT_SYM_OWNER - | OPT_MULTI; + conf->override_opts = OPT_UNSET | OPT_ALL | OPT_SYM_OWNER | OPT_MULTI; conf->content_md5 = 2; conf->accept_path_info = 3; @@ -242,8 +241,15 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv) conf->opts_remove = (conf->opts_remove & ~new->opts_add) | new->opts_remove; conf->opts = (conf->opts & ~conf->opts_remove) | conf->opts_add; - if ((base->opts & OPT_INCNOEXEC) && (new->opts & OPT_INCLUDES)) { - conf->opts = (conf->opts & ~OPT_INCNOEXEC) | OPT_INCLUDES; + + /* If Includes was enabled with exec in the base config, but + * was enabled without exec in the new config, then disable + * exec in the merged set. */ + if (((base->opts & (OPT_INCLUDES|OPT_INC_WITH_EXEC)) + == (OPT_INCLUDES|OPT_INC_WITH_EXEC)) + && ((new->opts & (OPT_INCLUDES|OPT_INC_WITH_EXEC)) + == OPT_INCLUDES)) { + conf->opts &= ~OPT_INC_WITH_EXEC; } } else { @@ -655,7 +661,16 @@ AP_DECLARE(int) ap_allow_options(request_rec *r) core_dir_config *conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module); - return conf->opts; + /* Per comment in http_core.h - the OPT_INC_WITH_EXEC bit is + * inverted, such that the exposed semantics match that of + * OPT_INCNOEXEC; i.e., the bit is only enabled if exec= is *not* + * permitted. */ + if (conf->opts & OPT_INCLUDES) { + return conf->opts ^ OPT_INC_WITH_EXEC; + } + else { + return conf->opts; + } } AP_DECLARE(int) ap_allow_overrides(request_rec *r) @@ -1304,10 +1319,12 @@ static const char *set_allow_opts(cmd_parms *cmd, allow_options_t *opts, opt = OPT_INDEXES; } else if (!strcasecmp(w, "Includes")) { - opt = OPT_INCLUDES; + /* If Includes is permitted, both Includes and + * IncludesNOEXEC may be changed. */ + opt = (OPT_INCLUDES | OPT_INC_WITH_EXEC); } else if (!strcasecmp(w, "IncludesNOEXEC")) { - opt = (OPT_INCLUDES | OPT_INCNOEXEC); + opt = OPT_INCLUDES; } else if (!strcasecmp(w, "FollowSymLinks")) { opt = OPT_SYM_LINKS; @@ -1428,10 +1445,10 @@ static const char *set_options(cmd_parms *cmd, void *d_, const char *l) opt = OPT_INDEXES; } else if (!strcasecmp(w, "Includes")) { - opt = OPT_INCLUDES; + opt = (OPT_INCLUDES | OPT_INC_WITH_EXEC); } else if (!strcasecmp(w, "IncludesNOEXEC")) { - opt = (OPT_INCLUDES | OPT_INCNOEXEC); + opt = OPT_INCLUDES; } else if (!strcasecmp(w, "FollowSymLinks")) { opt = OPT_SYM_LINKS; diff --git a/server/core_filters.c b/server/core_filters.c index acbe1901..c2ebe981 100644 --- a/server/core_filters.c +++ b/server/core_filters.c @@ -542,6 +542,12 @@ apr_status_t ap_core_output_filter(ap_filter_t *f, apr_bucket_brigade *b) apr_read_type_e eblock = APR_NONBLOCK_READ; apr_pool_t *input_pool = b->p; + /* Fail quickly if the connection has already been aborted. */ + if (c->aborted) { + apr_brigade_cleanup(b); + return APR_ECONNABORTED; + } + if (ctx == NULL) { ctx = apr_pcalloc(c->pool, sizeof(*ctx)); net->out_ctx = ctx; @@ -909,12 +915,9 @@ apr_status_t ap_core_output_filter(ap_filter_t *f, apr_bucket_brigade *b) /* No need to check for SUCCESS, we did that above. */ if (!APR_STATUS_IS_EAGAIN(rv)) { c->aborted = 1; + return APR_ECONNABORTED; } - /* The client has aborted, but the request was successful. We - * will report success, and leave it to the access and error - * logs to note that the connection was aborted. - */ return APR_SUCCESS; } diff --git a/server/gen_test_char.c b/server/gen_test_char.c index 59947d58..3835102d 100644 --- a/server/gen_test_char.c +++ b/server/gen_test_char.c @@ -14,9 +14,27 @@ * limitations under the License. */ +#ifdef CROSS_COMPILE + +#define apr_isalnum(c) (isalnum(((unsigned char)(c)))) +#define apr_isalpha(c) (isalpha(((unsigned char)(c)))) +#define apr_iscntrl(c) (iscntrl(((unsigned char)(c)))) +#define apr_isprint(c) (isprint(((unsigned char)(c)))) +#include +#define APR_HAVE_STDIO_H 1 +#define APR_HAVE_STRING_H 1 + +#else + #include "apr.h" #include "apr_lib.h" +#if defined(WIN32) || defined(OS2) +#define WANT_WIN32_OS2 +#endif + +#endif + #if APR_HAVE_STDIO_H #include #endif @@ -62,7 +80,7 @@ int main(int argc, char *argv[]) printf("\n "); /* escape_shell_cmd */ -#if defined(WIN32) || defined(OS2) +#if defined(WANT_WIN32_OS2) /* Win32/OS2 have many of the same vulnerable characters * as Unix sh, plus the carriage return and percent char. * The proper escaping of these characters varies from unix diff --git a/server/listen.c b/server/listen.c index d1e6da8e..b284d83b 100644 --- a/server/listen.c +++ b/server/listen.c @@ -633,7 +633,11 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, } if (argc != 2) { - proto = "http"; + if (port == 443) { + proto = "https"; + } else { + proto = "http"; + } } else { proto = apr_pstrdup(cmd->pool, argv[1]); diff --git a/server/log.c b/server/log.c index 3aa20b0b..42a77290 100644 --- a/server/log.c +++ b/server/log.c @@ -265,7 +265,8 @@ static void log_child_errfn(apr_pool_t *pool, apr_status_t err, * stderr for the child will be the same as the stdout of the parent. * Otherwise the child will inherit the stderr from the parent. */ static int log_child(apr_pool_t *p, const char *progname, - apr_file_t **fpin, int dummy_stderr) + apr_file_t **fpin, apr_cmdtype_e cmdtype, + int dummy_stderr) { /* Child process code for 'ErrorLog "|..."'; * may want a common framework for this, since I expect it will @@ -277,8 +278,7 @@ static int log_child(apr_pool_t *p, const char *progname, apr_file_t *outfile, *errfile; if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS) - && ((rc = apr_procattr_cmdtype_set(procattr, - APR_SHELLCMD_ENV)) == APR_SUCCESS) + && ((rc = apr_procattr_cmdtype_set(procattr, cmdtype)) == APR_SUCCESS) && ((rc = apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_NO_PIPE, @@ -325,12 +325,26 @@ static int open_error_log(server_rec *s, int is_main, apr_pool_t *p) if (*s->error_fname == '|') { apr_file_t *dummy = NULL; + apr_cmdtype_e cmdtype = APR_SHELLCMD_ENV; + fname = s->error_fname + 1; + /* In 2.4 favor PROGRAM_ENV, accept "||prog" syntax for compatibility + * and "|$cmd" to override the default. + * Any 2.2 backport would continue to favor SHELLCMD_ENV so there + * accept "||prog" to override, and "|$cmd" to ease conversion. + */ + if (*fname == '|') { + cmdtype = APR_PROGRAM_ENV; + ++fname; + } + if (*fname == '$') + ++fname; + /* Spawn a new child logger. If this is the main server_rec, * the new child must use a dummy stderr since the current * stderr might be a pipe to the old logger. Otherwise, the * child inherits the parents stderr. */ - rc = log_child(p, s->error_fname + 1, &dummy, is_main); + rc = log_child(p, fname, &dummy, cmdtype, is_main); if (rc != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL, "Couldn't start ErrorLog process"); @@ -883,12 +897,12 @@ static apr_status_t piped_log_spawn(piped_log *pl) apr_status_t status; if (((status = apr_procattr_create(&procattr, pl->p)) != APR_SUCCESS) || - ((status = apr_procattr_cmdtype_set(procattr, - APR_SHELLCMD_ENV)) != APR_SUCCESS) || + ((status = apr_procattr_cmdtype_set(procattr, pl->cmdtype)) + != APR_SUCCESS) || ((status = apr_procattr_child_in_set(procattr, ap_piped_log_read_fd(pl), ap_piped_log_write_fd(pl))) - != APR_SUCCESS) || + != APR_SUCCESS) || ((status = apr_procattr_child_errfn_set(procattr, log_child_errfn)) != APR_SUCCESS) || ((status = apr_procattr_error_check_set(procattr, 1)) != APR_SUCCESS)) { @@ -1012,7 +1026,9 @@ static apr_status_t piped_log_cleanup(void *data) } -AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program) +AP_DECLARE(piped_log *) ap_open_piped_log_ex(apr_pool_t *p, + const char *program, + apr_cmdtype_e cmdtype) { piped_log *pl; @@ -1020,6 +1036,7 @@ AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program) pl->p = p; pl->program = apr_pstrdup(p, program); pl->pid = NULL; + pl->cmdtype = cmdtype; if (apr_file_pipe_create(&ap_piped_log_read_fd(pl), &ap_piped_log_write_fd(pl), p) != APR_SUCCESS) { return NULL; @@ -1045,13 +1062,15 @@ static apr_status_t piped_log_cleanup(void *data) return APR_SUCCESS; } -AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program) +AP_DECLARE(piped_log *) ap_open_piped_log_ex(apr_pool_t *p, + const char *program, + apr_cmdtype_e cmdtype) { piped_log *pl; apr_file_t *dummy = NULL; int rc; - rc = log_child(p, program, &dummy, 0); + rc = log_child(p, program, &dummy, cmdtype, 0); if (rc != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL, "Couldn't start piped log process"); @@ -1069,6 +1088,26 @@ AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program) #endif +AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, + const char *program) +{ + apr_cmdtype_e cmdtype = APR_SHELLCMD_ENV; + + /* In 2.4 favor PROGRAM_ENV, accept "||prog" syntax for compatibility + * and "|$cmd" to override the default. + * Any 2.2 backport would continue to favor SHELLCMD_ENV so there + * accept "||prog" to override, and "|$cmd" to ease conversion. + */ + if (*program == '|') { + cmdtype = APR_PROGRAM_ENV; + ++program; + } + if (*program == '$') + ++program; + + return ap_open_piped_log_ex(p, program, cmdtype); +} + AP_DECLARE(void) ap_close_piped_log(piped_log *pl) { apr_pool_cleanup_run(pl->p, pl, piped_log_cleanup); diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c index 3849c222..28b60573 100644 --- a/server/mpm/prefork/prefork.c +++ b/server/mpm/prefork/prefork.c @@ -517,8 +517,12 @@ static void child_main(int child_num_arg) (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); /* Set up the pollfd array */ - /* ### check the status */ - (void) apr_pollset_create(&pollset, num_listensocks, pchild, 0); + status = apr_pollset_create(&pollset, num_listensocks, pchild, 0); + if (status != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf, + "Couldn't create pollset in child; check system or user limits"); + clean_child_exit(APEXIT_CHILDSICK); /* assume temporary resource issue */ + } for (lr = ap_listeners, i = num_listensocks; i--; lr = lr->next) { apr_pollfd_t pfd = { 0 }; @@ -573,19 +577,27 @@ static void child_main(int child_num_arg) apr_int32_t numdesc; const apr_pollfd_t *pdesc; - /* timeout == -1 == wait forever */ - status = apr_pollset_poll(pollset, -1, &numdesc, &pdesc); + /* check for termination first so we don't sleep for a while in + * poll if already signalled + */ + if (one_process && shutdown_pending) { + SAFE_ACCEPT(accept_mutex_off()); + return; + } + else if (die_now) { + /* In graceful stop/restart; drop the mutex + * and terminate the child. */ + SAFE_ACCEPT(accept_mutex_off()); + clean_child_exit(0); + } + /* timeout == 10 seconds to avoid a hang at graceful restart/stop + * caused by the closing of sockets by the signal handler + */ + status = apr_pollset_poll(pollset, apr_time_from_sec(10), + &numdesc, &pdesc); if (status != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(status)) { - if (one_process && shutdown_pending) { - return; - } - else if (die_now) { - /* In graceful stop/restart; drop the mutex - * and terminate the child. */ - SAFE_ACCEPT(accept_mutex_off()); - clean_child_exit(0); - } + if (APR_STATUS_IS_TIMEUP(status) || + APR_STATUS_IS_EINTR(status)) { continue; } /* Single Unix documents select as returning errnos diff --git a/server/protocol.c b/server/protocol.c index e5b2e030..23ef080f 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -1643,6 +1643,7 @@ static int send_header(void *data, const char *key, const char *val) AP_DECLARE(void) ap_send_interim_response(request_rec *r, int send_headers) { hdr_ptr x; + char *status_line = NULL; if (r->proto_num < 1001) { /* don't send interim response to HTTP/1.0 Client */ @@ -1654,9 +1655,13 @@ AP_DECLARE(void) ap_send_interim_response(request_rec *r, int send_headers) return; } + status_line = apr_pstrcat(r->pool, AP_SERVER_PROTOCOL, " ", r->status_line, CRLF, NULL); + ap_xlate_proto_to_ascii(status_line, strlen(status_line)); + x.f = r->connection->output_filters; x.bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); - ap_fputstrs(x.f, x.bb, AP_SERVER_PROTOCOL, " ", r->status_line, CRLF, NULL); + + ap_fputs(x.f, x.bb, status_line); if (send_headers) { apr_table_do(send_header, &x, r->headers_out, NULL); apr_table_clear(r->headers_out); diff --git a/server/request.c b/server/request.c index fe4026a3..6ca30f92 100644 --- a/server/request.c +++ b/server/request.c @@ -558,17 +558,71 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) && (!r->path_info || !*r->path_info))) && (cache->dir_conf_tested == sec_ent) && (strcmp(entry_dir, cache->cached) == 0)) { + + int familiar = 0; + /* Well this looks really familiar! If our end-result (per_dir_result) * didn't change, we have absolutely nothing to do :) * Otherwise (as is the case with most dir_merged/file_merged requests) * we must merge our dir_conf_merged onto this new r->per_dir_config. */ if (r->per_dir_config == cache->per_dir_result) { - return OK; + familiar = 1; } - if (r->per_dir_config == cache->dir_conf_merged) { + else if (r->per_dir_config == cache->dir_conf_merged) { r->per_dir_config = cache->per_dir_result; + familiar = 1; + } + if (familiar) { + apr_finfo_t thisinfo; + int res; + allow_options_t opts; + core_dir_config *this_dir; + + this_dir = ap_get_module_config(r->per_dir_config, &core_module); + opts = this_dir->opts; + /* + * If Symlinks are allowed in general we do not need the following + * check. + */ + if (!(opts & OPT_SYM_LINKS)) { + rv = apr_stat(&thisinfo, r->filename, + APR_FINFO_MIN | APR_FINFO_NAME | APR_FINFO_LINK, + r->pool); + /* + * APR_INCOMPLETE is as fine as result as APR_SUCCESS as we + * have added APR_FINFO_NAME to the wanted parameter of + * apr_stat above. On Unix platforms this means that apr_stat + * is always going to return APR_INCOMPLETE in the case that + * the call to the native stat / lstat did not fail. + */ + if ((rv != APR_INCOMPLETE) && (rv != APR_SUCCESS)) { + /* + * This should never happen, because we did a stat on the + * same file, resolving a possible symlink several lines + * above. Therefore do not make a detailed analysis of rv + * in this case for the reason of the failure, just bail out + * with a HTTP_FORBIDDEN in case we hit a race condition + * here. + */ + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "access to %s failed; stat of '%s' failed.", + r->uri, r->filename); + return r->status = HTTP_FORBIDDEN; + } + if (thisinfo.filetype == APR_LNK) { + /* Is this a possibly acceptable symlink? */ + if ((res = resolve_symlink(r->filename, &thisinfo, + opts, r->pool)) != OK) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "Symbolic link not allowed " + "or link target not accessible: %s", + r->filename); + return r->status = res; + } + } + } return OK; } diff --git a/server/util.c b/server/util.c index 3c927c23..e16b8eb2 100644 --- a/server/util.c +++ b/server/util.c @@ -1737,7 +1737,7 @@ AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partia /* ap_escape_uri is now a macro for os_escape_path */ -AP_DECLARE(char *) ap_escape_html(apr_pool_t *p, const char *s) +AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc) { int i, j; char *x; @@ -1750,6 +1750,8 @@ AP_DECLARE(char *) ap_escape_html(apr_pool_t *p, const char *s) j += 4; else if (s[i] == '"') j += 5; + else if (toasc && !apr_isascii(s[i])) + j += 5; if (j == 0) return apr_pstrmemdup(p, s, i); @@ -1772,13 +1774,21 @@ AP_DECLARE(char *) ap_escape_html(apr_pool_t *p, const char *s) memcpy(&x[j], """, 6); j += 5; } + else if (toasc && !apr_isascii(s[i])) { + char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]); + memcpy(&x[j], esc, 6); + j += 5; + } else x[j] = s[i]; x[j] = '\0'; return x; } - +AP_DECLARE(char *) ap_escape_html(apr_pool_t *p, const char *s) +{ + return ap_escape_html2(p, s, 0); +} AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str) { char *ret; diff --git a/server/util_script.c b/server/util_script.c index 09c8dd41..6d6f3f4a 100644 --- a/server/util_script.c +++ b/server/util_script.c @@ -430,12 +430,19 @@ AP_DECLARE(int) ap_scan_script_header_err_core(request_rec *r, char *buffer, while (1) { - if ((*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data) == 0) { + int rv = (*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data); + if (rv == 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, "Premature end of script headers: %s", apr_filepath_name_get(r->filename)); return HTTP_INTERNAL_SERVER_ERROR; } + else if (rv == -1) { + ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, + "Script timed out before returning headers: %s", + apr_filepath_name_get(r->filename)); + return HTTP_GATEWAY_TIME_OUT; + } /* Delete terminal (CR?)LF */ @@ -629,7 +636,7 @@ static int getsfunc_BRIGADE(char *buf, int len, void *arg) rv = apr_bucket_read(e, &bucket_data, &bucket_data_len, APR_BLOCK_READ); if (rv != APR_SUCCESS || (bucket_data_len == 0)) { - return 0; + return APR_STATUS_IS_TIMEUP(rv) ? -1 : 0; } src = bucket_data; src_end = bucket_data + bucket_data_len; diff --git a/server/vhost.c b/server/vhost.c index d7a0a07e..5b79fea5 100644 --- a/server/vhost.c +++ b/server/vhost.c @@ -677,7 +677,7 @@ AP_DECLARE(void) ap_fini_vhost_config(apr_pool_t *p, server_rec *main_s) #endif if (ap_exists_config_define("DUMP_VHOSTS")) { apr_file_t *thefile = NULL; - apr_file_open_stderr(&thefile, p); + apr_file_open_stdout(&thefile, p); dump_vhost_config(thefile); } } -- cgit v1.2.3