/* ==================================================================== * Copyright (c) 1995-1999 The Apache Group. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * 4. The names "Apache Server" and "Apache Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Group and was originally based * on public domain software written at the National Center for * Supercomputing Applications, University of Illinois, Urbana-Champaign. * For more information on the Apache Group and the Apache HTTP server * project, please see . * */ /* * Info Module. Display configuration information for the server and * all included modules. * * * SetHandler server-info * * * GET /server-info - Returns full configuration page for server and all modules * GET /server-info?server - Returns server configuration only * GET /server-info?module_name - Returns configuration for a single module * GET /server-info?list - Returns quick list of included modules * * Rasmus Lerdorf , May 1996 * * 05.01.96 Initial Version * * Lou Langholtz , July 1997 * * 07.11.97 Addition of the AddModuleInfo directive * */ #include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_log.h" #include "http_main.h" #include "http_protocol.h" #include "util_script.h" #include "http_conf_globals.h" typedef struct { char *name; /* matching module name */ char *info; /* additional info */ } info_entry; typedef struct { ap_array_header_t *more_info; } info_svr_conf; typedef struct info_cfg_lines { char *cmd; char *line; struct info_cfg_lines *next; } info_cfg_lines; module MODULE_VAR_EXPORT info_module; extern module *top_module; static void *create_info_config(ap_context_t *p, server_rec *s) { info_svr_conf *conf = (info_svr_conf *) ap_pcalloc(p, sizeof(info_svr_conf)); conf->more_info = ap_make_array(p, 20, sizeof(info_entry)); return conf; } static void *merge_info_config(ap_context_t *p, void *basev, void *overridesv) { info_svr_conf *new = (info_svr_conf *) ap_pcalloc(p, sizeof(info_svr_conf)); info_svr_conf *base = (info_svr_conf *) basev; info_svr_conf *overrides = (info_svr_conf *) overridesv; new->more_info = ap_append_arrays(p, overrides->more_info, base->more_info); return new; } static char *mod_info_html_cmd_string(const char *string, char *buf, size_t buf_len) { const char *s; char *t; char *end_buf; s = string; t = buf; /* keep space for \0 byte */ end_buf = buf + buf_len - 1; while ((*s) && (t < end_buf)) { if (*s == '<') { strncpy(t, "<", end_buf - t); t += 4; } else if (*s == '>') { strncpy(t, ">", end_buf - t); t += 4; } else if (*s == '&') { strncpy(t, "&", end_buf - t); t += 5; } else { *t++ = *s; } s++; } /* oops, overflowed... don't overwrite */ if (t > end_buf) { *end_buf = '\0'; } else { *t = '\0'; } return (buf); } static info_cfg_lines *mod_info_load_config(ap_context_t *p, const char *filename, request_rec *r) { char s[MAX_STRING_LEN]; configfile_t *fp; info_cfg_lines *new, *ret, *prev; const char *t; fp = ap_pcfg_openfile(p, filename); if (!fp) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, errno, r, "mod_info: couldn't open config file %s", filename); return NULL; } ret = NULL; prev = NULL; while (!ap_cfg_getline(s, MAX_STRING_LEN, fp)) { if (*s == '#') { continue; /* skip comments */ } new = ap_palloc(p, sizeof(struct info_cfg_lines)); new->next = NULL; if (!ret) { ret = new; } if (prev) { prev->next = new; } t = s; new->cmd = ap_getword_conf(p, &t); if (*t) { new->line = ap_pstrdup(p, t); } else { new->line = NULL; } prev = new; } ap_cfg_closefile(fp); return (ret); } static void mod_info_module_cmds(request_rec *r, info_cfg_lines *cfg, const command_rec *cmds, char *label) { const command_rec *cmd = cmds; info_cfg_lines *li = cfg, *li_st = NULL, *li_se = NULL; info_cfg_lines *block_start = NULL; int lab = 0, nest = 0; char buf[MAX_STRING_LEN]; while (li) { if (!strncasecmp(li->cmd, "cmd, "cmd, "cmd, "next; nest++; continue; } else if (nest && (!strncasecmp(li->cmd, "cmd, "cmd, "cmd, "", r); if (nest == 2) { ap_rputs("  ", r); } ap_rputs(mod_info_html_cmd_string(li->cmd, buf, sizeof(buf)), r); ap_rputs(" ", r); if (li->line) { ap_rputs(mod_info_html_cmd_string(li->line, buf, sizeof(buf)), r); } ap_rputs("\n", r); nest--; if (!nest) { block_start = NULL; li_st = NULL; } else { block_start = li_st; } li_se = NULL; } else { nest--; if (!nest) { li_st = NULL; } li_se = NULL; } } else { nest--; if (!nest) { li_st = NULL; } li_se = NULL; } li = li->next; continue; } cmd = cmds; while (cmd) { if (cmd->name) { if (!strcasecmp(cmd->name, li->cmd)) { if (!lab) { ap_rputs("
", r); ap_rputs(label, r); ap_rputs("\n", r); lab = 1; } if (((nest && block_start == NULL) || (nest == 2 && block_start == li_st)) && (strncasecmp(li->cmd, "cmd, "cmd, "cmd, "cmd, "cmd, "cmd, "", r); ap_rputs(mod_info_html_cmd_string(li_st->cmd, buf, sizeof(buf)), r); ap_rputs(" ", r); if (li_st->line) { ap_rputs(mod_info_html_cmd_string(li_st->line, buf, sizeof(buf)), r); } ap_rputs("\n", r); block_start = li_st; if (li_se) { ap_rputs("
  ", r); ap_rputs(mod_info_html_cmd_string(li_se->cmd, buf, sizeof(buf)), r); ap_rputs(" ", r); if (li_se->line) { ap_rputs(mod_info_html_cmd_string(li_se->line, buf, sizeof(buf)), r); } ap_rputs("\n", r); block_start = li_se; } } ap_rputs("
", r); if (nest) { ap_rputs("  ", r); } if (nest == 2) { ap_rputs("  ", r); } ap_rputs(mod_info_html_cmd_string(li->cmd, buf, sizeof(buf)), r); if (li->line) { ap_rputs(" ", r); ap_rputs(mod_info_html_cmd_string(li->line, buf, sizeof(buf)), r); ap_rputs("", r); } ap_rputs("", r); } } else break; cmd++; } li = li->next; } } static char *find_more_info(server_rec *s, const char *module_name) { int i; info_svr_conf *conf = (info_svr_conf *) ap_get_module_config(s->module_config, &info_module); info_entry *entry = (info_entry *) conf->more_info->elts; if (!module_name) { return 0; } for (i = 0; i < conf->more_info->nelts; i++) { if (!strcmp(module_name, entry->name)) { return entry->info; } entry++; } return 0; } static int display_info(request_rec *r) { module *modp = NULL; char buf[MAX_STRING_LEN], *cfname; char *more_info; const command_rec *cmd = NULL; const handler_rec *hand = NULL; server_rec *serv = r->server; int comma = 0; info_cfg_lines *mod_info_cfg_httpd = NULL; info_cfg_lines *mod_info_cfg_srm = NULL; info_cfg_lines *mod_info_cfg_access = NULL; r->allowed |= (1 << M_GET); if (r->method_number != M_GET) return DECLINED; r->content_type = "text/html"; ap_send_http_header(r); if (r->header_only) { return 0; } ap_rputs(DOCTYPE_HTML_3_2 "Server Information\n", r); ap_rputs("

Apache Server Information

\n", r); if (!r->args || strcasecmp(r->args, "list")) { cfname = ap_server_root_relative(r->pool, ap_server_confname); mod_info_cfg_httpd = mod_info_load_config(r->pool, cfname, r); cfname = ap_server_root_relative(r->pool, serv->srm_confname); mod_info_cfg_srm = mod_info_load_config(r->pool, cfname, r); cfname = ap_server_root_relative(r->pool, serv->access_confname); mod_info_cfg_access = mod_info_load_config(r->pool, cfname, r); if (!r->args) { ap_rputs("Server Settings, ", r); for (modp = top_module; modp; modp = modp->next) { ap_rprintf(r, "%s", modp->name, modp->name); if (modp->next) { ap_rputs(", ", r); } } ap_rputs("
", r); } if (!r->args || !strcasecmp(r->args, "server")) { ap_rprintf(r, "Server Version: " "%s
\n", ap_get_server_version()); ap_rprintf(r, "Server Built: " "%s
\n", ap_get_server_built()); ap_rprintf(r, "API Version: " "%d:%d
\n", MODULE_MAGIC_NUMBER_MAJOR, MODULE_MAGIC_NUMBER_MINOR); ap_rprintf(r, "User/Group: " "%s(%d)/%d
\n", ap_user_name, (int) ap_user_id, (int) ap_group_id); ap_rprintf(r, "Hostname/port: " "%s:%u
\n", serv->server_hostname, serv->port); ap_rprintf(r, "Daemons: " "start: %d    " "min idle: %d    " "max idle: %d    " "max: %d
\n", ap_daemons_to_start, ap_daemons_min_free, ap_daemons_max_free, ap_daemons_limit); ap_rprintf(r, "Max Requests: " "per child: %d    " "keep alive: %s    " "max per connection: %d
\n", ap_max_requests_per_child, (serv->keep_alive ? "on" : "off"), serv->keep_alive_max); ap_rprintf(r, "Threads: " "per child: %d   
\n", ap_threads_per_child); ap_rprintf(r, "Timeouts: " "connection: %d    " "keep-alive: %d
", serv->timeout, serv->keep_alive_timeout); ap_rprintf(r, "Server Root: " "%s
\n", ap_server_root); ap_rprintf(r, "Config File: " "%s
\n", ap_server_confname); ap_rprintf(r, "PID File: " "%s
\n", ap_pid_fname); ap_rprintf(r, "Scoreboard File: " "%s
\n", ap_scoreboard_fname); } ap_rputs("
", r); for (modp = top_module; modp; modp = modp->next) { if (!r->args || !strcasecmp(modp->name, r->args)) { ap_rprintf(r, "
Module Name: " "%s\n", modp->name, modp->name); ap_rputs("
Content handlers:", r); hand = modp->handlers; if (hand) { while (hand) { if (hand->content_type) { ap_rprintf(r, " %s\n", hand->content_type); } else { break; } hand++; if (hand && hand->content_type) { ap_rputs(",", r); } } } else { ap_rputs(" none", r); } ap_rputs("
Configuration Phase Participation: \n", r); if (modp->child_init) { ap_rputs("Child Init", r); comma = 1; } if (modp->create_dir_config) { if (comma) { ap_rputs(", ", r); } ap_rputs("Create Directory Config", r); comma = 1; } if (modp->merge_dir_config) { if (comma) { ap_rputs(", ", r); } ap_rputs("Merge Directory Configs", r); comma = 1; } if (modp->create_server_config) { if (comma) { ap_rputs(", ", r); } ap_rputs("Create Server Config", r); comma = 1; } if (modp->merge_server_config) { if (comma) { ap_rputs(", ", r); } ap_rputs("Merge Server Configs", r); comma = 1; } if (modp->child_exit) { if (comma) { ap_rputs(", ", r); } ap_rputs("Child Exit", r); comma = 1; } if (!comma) ap_rputs(" none", r); comma = 0; ap_rputs("
Request Phase Participation: \n", r); if (modp->post_read_request) { ap_rputs("Post-Read Request", r); comma = 1; } if (modp->header_parser) { if (comma) { ap_rputs(", ", r); } ap_rputs("Header Parse", r); comma = 1; } if (modp->translate_handler) { if (comma) { ap_rputs(", ", r); } ap_rputs("Translate Path", r); comma = 1; } if (modp->access_checker) { if (comma) { ap_rputs(", ", r); } ap_rputs("Check Access", r); comma = 1; } if (modp->ap_check_user_id) { if (comma) { ap_rputs(", ", r); } ap_rputs("Verify User ID", r); comma = 1; } if (modp->auth_checker) { if (comma) { ap_rputs(", ", r); } ap_rputs("Verify User Access", r); comma = 1; } if (modp->type_checker) { if (comma) { ap_rputs(", ", r); } ap_rputs("Check Type", r); comma = 1; } if (modp->fixer_upper) { if (comma) { ap_rputs(", ", r); } ap_rputs("Fixups", r); comma = 1; } if (modp->logger) { if (comma) { ap_rputs(", ", r); } ap_rputs("Logging", r); comma = 1; } if (!comma) ap_rputs(" none", r); comma = 0; ap_rputs("
Module Directives: ", r); cmd = modp->cmds; if (cmd) { while (cmd) { if (cmd->name) { ap_rprintf(r, "
%s - ", mod_info_html_cmd_string(cmd->name, buf, sizeof(buf))); if (cmd->errmsg) { ap_rputs(cmd->errmsg, r); } ap_rputs("\n", r); } else { break; } cmd++; } ap_rputs("
Current Configuration:\n", r); mod_info_module_cmds(r, mod_info_cfg_httpd, modp->cmds, "httpd.conf"); mod_info_module_cmds(r, mod_info_cfg_srm, modp->cmds, "srm.conf"); mod_info_module_cmds(r, mod_info_cfg_access, modp->cmds, "access.conf"); } else { ap_rputs(" none\n", r); } more_info = find_more_info(serv, modp->name); if (more_info) { ap_rputs("
Additional Information:\n
", r); ap_rputs(more_info, r); } ap_rputs("

\n", r); if (r->args) { break; } } } if (!modp && r->args && strcasecmp(r->args, "server")) { ap_rputs("No such module\n", r); } } else { for (modp = top_module; modp; modp = modp->next) { ap_rputs(modp->name, r); if (modp->next) { ap_rputs("
", r); } } } ap_rputs("
\n", r); ap_rputs(ap_psignature("",r), r); ap_rputs("\n", r); /* Done, turn off timeout, close file and return */ return 0; } static const char *add_module_info(cmd_parms *cmd, void *dummy, char *name, char *info) { server_rec *s = cmd->server; info_svr_conf *conf = (info_svr_conf *) ap_get_module_config(s->module_config, &info_module); info_entry *new = ap_push_array(conf->more_info); new->name = name; new->info = info; return NULL; } static const command_rec info_cmds[] = { {"AddModuleInfo", add_module_info, NULL, RSRC_CONF, TAKE2, "a module name and additional information on that module"}, {NULL} }; static const handler_rec info_handlers[] = { {"server-info", display_info}, {NULL} }; module MODULE_VAR_EXPORT info_module = { STANDARD_MODULE_STUFF, NULL, /* initializer */ NULL, /* dir config creater */ NULL, /* dir merger --- default is to override */ create_info_config, /* server config */ merge_info_config, /* merge server config */ info_cmds, /* command ap_table_t */ info_handlers, /* handlers */ NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ NULL, /* logger */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */ NULL /* post read-request */ };