diff options
Diffstat (limited to 'modules')
241 files changed, 0 insertions, 89931 deletions
diff --git a/modules/.cvsignore b/modules/.cvsignore deleted file mode 100644 index 59d7d334c8..0000000000 --- a/modules/.cvsignore +++ /dev/null @@ -1,4 +0,0 @@ -Makefile -.deps -Debug -Release diff --git a/modules/Makefile.in b/modules/Makefile.in deleted file mode 100644 index ecb043547b..0000000000 --- a/modules/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -SUBDIRS = $(MODULE_DIRS) - -include $(top_srcdir)/build/rules.mk - diff --git a/modules/README b/modules/README deleted file mode 100644 index 51624a67f7..0000000000 --- a/modules/README +++ /dev/null @@ -1,55 +0,0 @@ -The directory structure for this level is as follows: - -aaa/ - This directory contains modules dealing with authorization and - authentication. - -arch/ - -cache/ - This directory houses modules that implement file and data caching - capability. - -dav/ - This directory houses modules that implement WebDAV functionality. - -echo/ - -experimental/ - In this directory we've placed some modules which we think - provide some pretty interesting functionality, but which - are still in the early stages of development and could - evolve radically in the future. This code isn't supported - officially. - -filters/ - This directory houses modules that perform general inline data filtering. - -generators/ - This directory houses modules that perform data generation functions. - -http/ - This directory houses modules that basic HTTP protocol implementation. - -loggers/ - This directory houses modules that handle logging functions. - -mappers/ - This directory houses modules that handle URL mapping and - rewriting. - -metadata/ - This directory houses modules that deal with Header metadata. - -proxy/ - This houses the code for the proxy module for Apache. - -ssl/ - -test/ - This directory houses modules which test various components - of Apache. You should not compile these into a production - server. - -tls/ - This directory houses code for OpenSSL functionality. diff --git a/modules/aaa/.cvsignore b/modules/aaa/.cvsignore deleted file mode 100644 index 65f0cc30cf..0000000000 --- a/modules/aaa/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -.deps -.libs -*.la -modules.mk -Makefile -*.lo -*.slo -*.so -Debug -Release diff --git a/modules/aaa/.indent.pro b/modules/aaa/.indent.pro deleted file mode 100644 index a9fbe9f9a1..0000000000 --- a/modules/aaa/.indent.pro +++ /dev/null @@ -1,54 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 --TBUFF --TFILE --TTRANS --TUINT4 --T_trans --Tallow_options_t --Tapache_sfio --Tarray_header --Tbool_int --Tbuf_area --Tbuff_struct --Tbuffy --Tcmd_how --Tcmd_parms --Tcommand_rec --Tcommand_struct --Tconn_rec --Tcore_dir_config --Tcore_server_config --Tdir_maker_func --Tevent --Tglobals_s --Thandler_func --Thandler_rec --Tjoblist_s --Tlisten_rec --Tmerger_func --Tmode_t --Tmodule --Tmodule_struct --Tmutex --Tn_long --Tother_child_rec --Toverrides_t --Tparent_score --Tpid_t --Tpiped_log --Tpool --Trequest_rec --Trequire_line --Trlim_t --Tscoreboard --Tsemaphore --Tserver_addr_rec --Tserver_rec --Tserver_rec_chain --Tshort_score --Ttable --Ttable_entry --Tthread --Tu_wide_int --Tvtime_t --Twide_int diff --git a/modules/aaa/Makefile.in b/modules/aaa/Makefile.in deleted file mode 100644 index 167b343d0d..0000000000 --- a/modules/aaa/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ - -include $(top_srcdir)/build/special.mk - diff --git a/modules/aaa/config.m4 b/modules/aaa/config.m4 deleted file mode 100644 index b8b359f9b1..0000000000 --- a/modules/aaa/config.m4 +++ /dev/null @@ -1,21 +0,0 @@ -dnl modules enabled in this directory by default - -dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]]) - -APACHE_MODPATH_INIT(aaa) - -APACHE_MODULE(access, host-based access control, , , yes) -APACHE_MODULE(auth, user-based access control, , , yes) -APACHE_MODULE(auth_anon, anonymous user access, , , most) -APACHE_MODULE(auth_dbm, DBM-based access databases, , , most) - -APACHE_MODULE(auth_db, DB-based access databases, , , , [ - AC_CHECK_HEADERS(db.h) - AC_CHECK_LIB(db,main) -]) - -APACHE_MODULE(auth_digest, RFC2617 Digest authentication, , , most) - -APR_ADDTO(LTFLAGS,-export-dynamic) - -APACHE_MODPATH_FINISH diff --git a/modules/aaa/mod_access.c b/modules/aaa/mod_access.c deleted file mode 100644 index d51df93a40..0000000000 --- a/modules/aaa/mod_access.c +++ /dev/null @@ -1,345 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * Security options etc. - * - * Module derived from code originally written by Rob McCool - * - */ - -#include "apr_strings.h" -#include "apr_network_io.h" -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#define APR_WANT_BYTEFUNC -#include "apr_want.h" - -#include "ap_config.h" -#include "httpd.h" -#include "http_core.h" -#include "http_config.h" -#include "http_log.h" -#include "http_request.h" - -#if APR_HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif - -enum allowdeny_type { - T_ENV, - T_ALL, - T_IP, - T_HOST, - T_FAIL -}; - -typedef struct { - int limited; - union { - char *from; - apr_ipsubnet_t *ip; - } x; - enum allowdeny_type type; -} allowdeny; - -/* things in the 'order' array */ -#define DENY_THEN_ALLOW 0 -#define ALLOW_THEN_DENY 1 -#define MUTUAL_FAILURE 2 - -typedef struct { - int order[METHODS]; - apr_array_header_t *allows; - apr_array_header_t *denys; -} access_dir_conf; - -module AP_MODULE_DECLARE_DATA access_module; - -static void *create_access_dir_config(apr_pool_t *p, char *dummy) -{ - access_dir_conf *conf = - (access_dir_conf *) apr_pcalloc(p, sizeof(access_dir_conf)); - int i; - - for (i = 0; i < METHODS; ++i) - conf->order[i] = DENY_THEN_ALLOW; - conf->allows = apr_array_make(p, 1, sizeof(allowdeny)); - conf->denys = apr_array_make(p, 1, sizeof(allowdeny)); - - return (void *) conf; -} - -static const char *order(cmd_parms *cmd, void *dv, const char *arg) -{ - access_dir_conf *d = (access_dir_conf *) dv; - int i, o; - - if (!strcasecmp(arg, "allow,deny")) - o = ALLOW_THEN_DENY; - else if (!strcasecmp(arg, "deny,allow")) - o = DENY_THEN_ALLOW; - else if (!strcasecmp(arg, "mutual-failure")) - o = MUTUAL_FAILURE; - else - return "unknown order"; - - for (i = 0; i < METHODS; ++i) - if (cmd->limited & (1 << i)) - d->order[i] = o; - - return NULL; -} - -static const char *allow_cmd(cmd_parms *cmd, void *dv, const char *from, - const char *where_c) -{ - access_dir_conf *d = (access_dir_conf *) dv; - allowdeny *a; - char *where = apr_pstrdup(cmd->pool, where_c); - char *s; - char msgbuf[120]; - apr_status_t rv; - - if (strcasecmp(from, "from")) - return "allow and deny must be followed by 'from'"; - - a = (allowdeny *) apr_array_push(cmd->info ? d->allows : d->denys); - a->x.from = where; - a->limited = cmd->limited; - - if (!strncasecmp(where, "env=", 4)) { - a->type = T_ENV; - a->x.from += 4; - - } - else if (!strcasecmp(where, "all")) { - a->type = T_ALL; - } - else if ((s = strchr(where, '/'))) { - *s++ = '\0'; - rv = apr_ipsubnet_create(&a->x.ip, where, s, cmd->pool); - if(APR_STATUS_IS_EINVAL(rv)) { - /* looked nothing like an IP address */ - return "An IP address was expected"; - } - else if (rv != APR_SUCCESS) { - apr_strerror(rv, msgbuf, sizeof msgbuf); - return apr_pstrdup(cmd->pool, msgbuf); - } - a->type = T_IP; - } - else if (!APR_STATUS_IS_EINVAL(rv = apr_ipsubnet_create(&a->x.ip, where, NULL, cmd->pool))) { - if (rv != APR_SUCCESS) { - apr_strerror(rv, msgbuf, sizeof msgbuf); - return apr_pstrdup(cmd->pool, msgbuf); - } - a->type = T_IP; - } - else { /* no slash, didn't look like an IP address => must be a host */ - a->type = T_HOST; - } - - return NULL; -} - -static char its_an_allow; - -static const command_rec access_cmds[] = -{ - AP_INIT_TAKE1("order", order, NULL, OR_LIMIT, - "'allow,deny', 'deny,allow', or 'mutual-failure'"), - AP_INIT_ITERATE2("allow", allow_cmd, &its_an_allow, OR_LIMIT, - "'from' followed by hostnames or IP-address wildcards"), - AP_INIT_ITERATE2("deny", allow_cmd, NULL, OR_LIMIT, - "'from' followed by hostnames or IP-address wildcards"), - {NULL} -}; - -static int in_domain(const char *domain, const char *what) -{ - int dl = strlen(domain); - int wl = strlen(what); - - if ((wl - dl) >= 0) { - if (strcasecmp(domain, &what[wl - dl]) != 0) - return 0; - - /* Make sure we matched an *entire* subdomain --- if the user - * said 'allow from good.com', we don't want people from nogood.com - * to be able to get in. - */ - - if (wl == dl) - return 1; /* matched whole thing */ - else - return (domain[0] == '.' || what[wl - dl - 1] == '.'); - } - else - return 0; -} - -static int find_allowdeny(request_rec *r, apr_array_header_t *a, int method) -{ - allowdeny *ap = (allowdeny *) a->elts; - int mmask = (1 << method); - int i; - int gothost = 0; - const char *remotehost = NULL; - - for (i = 0; i < a->nelts; ++i) { - if (!(mmask & ap[i].limited)) - continue; - - switch (ap[i].type) { - case T_ENV: - if (apr_table_get(r->subprocess_env, ap[i].x.from)) { - return 1; - } - break; - - case T_ALL: - return 1; - - case T_IP: - if (apr_ipsubnet_test(ap[i].x.ip, r->connection->remote_addr)) { - return 1; - } - break; - - case T_HOST: - if (!gothost) { - int remotehost_is_ip; - - remotehost = ap_get_remote_host(r->connection, r->per_dir_config, - REMOTE_DOUBLE_REV, &remotehost_is_ip); - - if ((remotehost == NULL) || remotehost_is_ip) - gothost = 1; - else - gothost = 2; - } - - if ((gothost == 2) && in_domain(ap[i].x.from, remotehost)) - return 1; - break; - - case T_FAIL: - /* do nothing? */ - break; - } - } - - return 0; -} - -static int check_dir_access(request_rec *r) -{ - int method = r->method_number; - access_dir_conf *a = - (access_dir_conf *) - ap_get_module_config(r->per_dir_config, &access_module); - int ret = OK; - - if (a->order[method] == ALLOW_THEN_DENY) { - ret = HTTP_FORBIDDEN; - if (find_allowdeny(r, a->allows, method)) - ret = OK; - if (find_allowdeny(r, a->denys, method)) - ret = HTTP_FORBIDDEN; - } - else if (a->order[method] == DENY_THEN_ALLOW) { - if (find_allowdeny(r, a->denys, method)) - ret = HTTP_FORBIDDEN; - if (find_allowdeny(r, a->allows, method)) - ret = OK; - } - else { - if (find_allowdeny(r, a->allows, method) - && !find_allowdeny(r, a->denys, method)) - ret = OK; - else - ret = HTTP_FORBIDDEN; - } - - if (ret == HTTP_FORBIDDEN - && (ap_satisfies(r) != SATISFY_ANY || !ap_some_auth_required(r))) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "client denied by server configuration: %s", - r->filename); - } - - return ret; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_access_checker(check_dir_access,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA access_module = -{ - STANDARD20_MODULE_STUFF, - create_access_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - access_cmds, - register_hooks /* register hooks */ -}; diff --git a/modules/aaa/mod_access.exp b/modules/aaa/mod_access.exp deleted file mode 100644 index f8aff339da..0000000000 --- a/modules/aaa/mod_access.exp +++ /dev/null @@ -1 +0,0 @@ -access_module diff --git a/modules/aaa/mod_auth.c b/modules/aaa/mod_auth.c deleted file mode 100644 index c3768a45fb..0000000000 --- a/modules/aaa/mod_auth.c +++ /dev/null @@ -1,338 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_auth: authentication - * - * Rob McCool - * - * Adapted to Apache by rst. - * - * dirkx - Added Authoritative control to allow passing on to lower - * modules if and only if the userid is not known to this - * module. A known user with a faulty or absent password still - * causes an AuthRequired. The default is 'Authoritative', i.e. - * no control is passed along. - */ - -#include "apr_strings.h" -#include "apr_lib.h" /* for apr_password_validate */ - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_protocol.h" -#include "http_request.h" - - -typedef struct { - char *auth_pwfile; - char *auth_grpfile; - int auth_authoritative; -} auth_config_rec; - -static void *create_auth_dir_config(apr_pool_t *p, char *d) -{ - auth_config_rec *conf = apr_pcalloc(p, sizeof(*conf)); - - conf->auth_pwfile = NULL; /* just to illustrate the default really */ - conf->auth_grpfile = NULL; /* unless you have a broken HP cc */ - conf->auth_authoritative = 1; /* keep the fortress secure by default */ - return conf; -} - -static const char *set_auth_slot(cmd_parms *cmd, void *offset, const char *f, - const char *t) -{ - if (t && strcmp(t, "standard")) - return apr_pstrcat(cmd->pool, "Invalid auth file type: ", t, NULL); - - return ap_set_file_slot(cmd, offset, f); -} - -static const command_rec auth_cmds[] = -{ - AP_INIT_TAKE12("AuthUserFile", set_auth_slot, - (void *) XtOffsetOf(auth_config_rec, auth_pwfile), OR_AUTHCFG, - "text file containing user IDs and passwords"), - AP_INIT_TAKE12("AuthGroupFile", set_auth_slot, - (void *) XtOffsetOf(auth_config_rec, auth_grpfile), OR_AUTHCFG, - "text file containing group names and member user IDs"), - AP_INIT_FLAG("AuthAuthoritative", ap_set_flag_slot, - (void *) XtOffsetOf(auth_config_rec, auth_authoritative), - OR_AUTHCFG, - "Set to 'no' to allow access control to be passed along to lower " - "modules if the UserID is not known to this module"), - {NULL} -}; - -module AP_MODULE_DECLARE_DATA auth_module; - -static char *get_pw(request_rec *r, char *user, char *auth_pwfile) -{ - ap_configfile_t *f; - char l[MAX_STRING_LEN]; - const char *rpw, *w; - apr_status_t status; - - if ((status = ap_pcfg_openfile(&f, r->pool, auth_pwfile)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, - "Could not open password file: %s", auth_pwfile); - return NULL; - } - while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) { - if ((l[0] == '#') || (!l[0])) - continue; - rpw = l; - w = ap_getword(r->pool, &rpw, ':'); - - if (!strcmp(user, w)) { - ap_cfg_closefile(f); - return ap_getword(r->pool, &rpw, ':'); - } - } - ap_cfg_closefile(f); - return NULL; -} - -static apr_table_t *groups_for_user(apr_pool_t *p, char *user, char *grpfile) -{ - ap_configfile_t *f; - apr_table_t *grps = apr_table_make(p, 15); - apr_pool_t *sp; - char l[MAX_STRING_LEN]; - const char *group_name, *ll, *w; - apr_status_t status; - - if ((status = ap_pcfg_openfile(&f, p, grpfile)) != APR_SUCCESS) { -/*add? aplog_error(APLOG_MARK, APLOG_ERR, NULL, - "Could not open group file: %s", grpfile);*/ - return NULL; - } - - apr_pool_create(&sp, p); - - while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) { - if ((l[0] == '#') || (!l[0])) - continue; - ll = l; - apr_pool_clear(sp); - - group_name = ap_getword(sp, &ll, ':'); - - while (ll[0]) { - w = ap_getword_conf(sp, &ll); - if (!strcmp(w, user)) { - apr_table_setn(grps, apr_pstrdup(p, group_name), "in"); - break; - } - } - } - ap_cfg_closefile(f); - apr_pool_destroy(sp); - return grps; -} - -/* These functions return 0 if client is OK, and proper error status - * if not... either HTTP_UNAUTHORIZED, if we made a check, and it failed, or - * HTTP_INTERNAL_SERVER_ERROR, if things are so totally confused that we - * couldn't figure out how to tell if the client is authorized or not. - * - * If they return DECLINED, and all other modules also decline, that's - * treated by the server core as a configuration error, logged and - * reported as such. - */ - -/* Determine user ID, and check if it really is that user, for HTTP - * basic authentication... - */ - -static int authenticate_basic_user(request_rec *r) -{ - auth_config_rec *conf = ap_get_module_config(r->per_dir_config, - &auth_module); - const char *sent_pw; - char *real_pw; - apr_status_t invalid_pw; - int res; - - if ((res = ap_get_basic_auth_pw(r, &sent_pw))) - return res; - - if (!conf->auth_pwfile) - return DECLINED; - - if (!(real_pw = get_pw(r, r->user, conf->auth_pwfile))) { - if (!(conf->auth_authoritative)) - return DECLINED; - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "user %s not found: %s", r->user, r->uri); - ap_note_basic_auth_failure(r); - return HTTP_UNAUTHORIZED; - } - invalid_pw = apr_password_validate(sent_pw, real_pw); - if (invalid_pw != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "user %s: authentication failure for \"%s\": " - "Password Mismatch", - r->user, r->uri); - ap_note_basic_auth_failure(r); - return HTTP_UNAUTHORIZED; - } - return OK; -} - -/* Checking ID */ - -static int check_user_access(request_rec *r) -{ - auth_config_rec *conf = ap_get_module_config(r->per_dir_config, - &auth_module); - char *user = r->user; - int m = r->method_number; - int method_restricted = 0; - register int x; - const char *t, *w; - apr_table_t *grpstatus; - const apr_array_header_t *reqs_arr = ap_requires(r); - require_line *reqs; - - /* BUG FIX: tadc, 11-Nov-1995. If there is no "requires" directive, - * then any user will do. - */ - if (!reqs_arr) - return (OK); - reqs = (require_line *) reqs_arr->elts; - - if (conf->auth_grpfile) - grpstatus = groups_for_user(r->pool, user, conf->auth_grpfile); - else - grpstatus = NULL; - - for (x = 0; x < reqs_arr->nelts; x++) { - - if (!(reqs[x].method_mask & (1 << m))) - continue; - - method_restricted = 1; - - t = reqs[x].requirement; - w = ap_getword_white(r->pool, &t); - if (!strcmp(w, "valid-user")) - return OK; - if (!strcmp(w, "user")) { - while (t[0]) { - w = ap_getword_conf(r->pool, &t); - if (!strcmp(user, w)) - return OK; - } - } - else if (!strcmp(w, "group")) { - if (!grpstatus) - return DECLINED; /* DBM group? Something else? */ - - while (t[0]) { - w = ap_getword_conf(r->pool, &t); - if (apr_table_get(grpstatus, w)) - return OK; - } - } else if (conf->auth_authoritative) { - /* if we aren't authoritative, any require directive could be - * valid even if we don't grok it. However, if we are - * authoritative, we can warn the user they did something wrong. - * That something could be a missing "AuthAuthoritative off", but - * more likely is a typo in the require directive. - */ - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "access to %s failed, reason: unknown require directive:" - "\"%s\"", r->uri, reqs[x].requirement); - } - } - - if (!method_restricted) - return OK; - - if (!(conf->auth_authoritative)) - return DECLINED; - - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "access to %s failed, reason: user %s not allowed access", - r->uri, user); - - ap_note_basic_auth_failure(r); - return HTTP_UNAUTHORIZED; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_check_user_id(authenticate_basic_user,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_auth_checker(check_user_access,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA auth_module = -{ - STANDARD20_MODULE_STUFF, - create_auth_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - auth_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/aaa/mod_auth.exp b/modules/aaa/mod_auth.exp deleted file mode 100644 index 76adad0a66..0000000000 --- a/modules/aaa/mod_auth.exp +++ /dev/null @@ -1 +0,0 @@ -auth_module diff --git a/modules/aaa/mod_auth_anon.c b/modules/aaa/mod_auth_anon.c deleted file mode 100644 index 5b008ae6ce..0000000000 --- a/modules/aaa/mod_auth_anon.c +++ /dev/null @@ -1,313 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_auth: authentication - * - * Rob McCool & Brian Behlendorf. - * - * Adapted to Apache by rst. - * - * Version 0.5 May 1996 - * - * Modified by Dirk.vanGulik@jrc.it to - * - * Adapted to allow anonymous logins, just like with Anon-FTP, when - * one gives the magic user name 'anonymous' and ones email address - * as the password. - * - * Just add the following tokes to your <directory> setup: - * - * Anonymous magic-userid [magic-userid]... - * - * Anonymous_MustGiveEmail [ on | off ] default = on - * Anonymous_LogEmail [ on | off ] default = on - * Anonymous_VerifyEmail [ on | off ] default = off - * Anonymous_NoUserId [ on | off ] default = off - * Anonymous_Authoritative [ on | off ] default = off - * - * The magic user id is something like 'anonymous', it is NOT case sensitive. - * - * The MustGiveEmail flag can be used to force users to enter something - * in the password field (like an email address). Default is on. - * - * Furthermore the 'NoUserID' flag can be set to allow completely empty - * usernames in as well; this can be is convenient as a single return - * in broken GUIs like W95 is often given by the user. The Default is off. - * - * Dirk.vanGulik@jrc.it; http://ewse.ceo.org; http://me-www.jrc.it/~dirkx - * - */ - -#include "apr_strings.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_request.h" -#include "http_protocol.h" - - -typedef struct anon_auth { - char *password; - struct anon_auth *next; -} anon_auth; - -typedef struct { - - anon_auth *anon_auth_passwords; - int anon_auth_nouserid; - int anon_auth_logemail; - int anon_auth_verifyemail; - int anon_auth_mustemail; - int anon_auth_authoritative; - -} anon_auth_config_rec; - - -static void *create_anon_auth_dir_config(apr_pool_t *p, char *d) -{ - anon_auth_config_rec *conf = apr_pcalloc(p, sizeof(*conf)); - - /* just to illustrate the defaults really. */ - conf->anon_auth_passwords = NULL; - - conf->anon_auth_nouserid = 0; - conf->anon_auth_logemail = 1; - conf->anon_auth_verifyemail = 0; - conf->anon_auth_mustemail = 1; - conf->anon_auth_authoritative = 0; - return conf; -} - -static const char *anon_set_passwd_flag(cmd_parms *cmd, - void *my_config, int arg) -{ - anon_auth_config_rec *conf = my_config; - conf->anon_auth_mustemail = arg; - return NULL; -} - -static const char *anon_set_userid_flag(cmd_parms *cmd, - void *my_config, int arg) -{ - anon_auth_config_rec *conf = my_config; - conf->anon_auth_nouserid = arg; - return NULL; -} - -static const char *anon_set_logemail_flag(cmd_parms *cmd, - void *my_config, int arg) -{ - anon_auth_config_rec *conf = my_config; - conf->anon_auth_logemail = arg; - return NULL; -} - -static const char *anon_set_verifyemail_flag(cmd_parms *cmd, - void *my_config, int arg) -{ - anon_auth_config_rec *conf = my_config; - conf->anon_auth_verifyemail = arg; - return NULL; -} -static const char *anon_set_authoritative_flag(cmd_parms *cmd, - void *my_config, int arg) -{ - anon_auth_config_rec *conf = my_config; - conf->anon_auth_authoritative = arg; - return NULL; -} - -static const char *anon_set_string_slots(cmd_parms *cmd, - void *my_config, const char *arg) -{ - anon_auth_config_rec *conf = my_config; - anon_auth *first; - - if (!(*arg)) - return "Anonymous string cannot be empty, use Anonymous_NoUserId instead"; - - /* squeeze in a record */ - first = conf->anon_auth_passwords; - - if (!(conf->anon_auth_passwords = apr_palloc(cmd->pool, sizeof(anon_auth))) || - !(conf->anon_auth_passwords->password = apr_pstrdup(cmd->pool, arg))) - return "Failed to claim memory for an anonymous password..."; - - /* and repair the next */ - conf->anon_auth_passwords->next = first; - - return NULL; -} - -static const command_rec anon_auth_cmds[] = -{ - AP_INIT_ITERATE("Anonymous", anon_set_string_slots, NULL, OR_AUTHCFG, - "a space-separated list of user IDs"), - AP_INIT_FLAG("Anonymous_MustGiveEmail", anon_set_passwd_flag, NULL, - OR_AUTHCFG, "Limited to 'on' or 'off'"), - AP_INIT_FLAG("Anonymous_NoUserId", anon_set_userid_flag, NULL, OR_AUTHCFG, - "Limited to 'on' or 'off'"), - AP_INIT_FLAG("Anonymous_VerifyEmail", anon_set_verifyemail_flag, NULL, - OR_AUTHCFG, "Limited to 'on' or 'off'"), - AP_INIT_FLAG("Anonymous_LogEmail", anon_set_logemail_flag, NULL, OR_AUTHCFG, - "Limited to 'on' or 'off'"), - AP_INIT_FLAG("Anonymous_Authoritative", anon_set_authoritative_flag, NULL, - OR_AUTHCFG, "Limited to 'on' or 'off'"), - {NULL} -}; - -module AP_MODULE_DECLARE_DATA auth_anon_module; - -static int anon_authenticate_basic_user(request_rec *r) -{ - anon_auth_config_rec *conf = ap_get_module_config(r->per_dir_config, - &auth_anon_module); - const char *sent_pw; - int res = DECLINED; - - if ((res = ap_get_basic_auth_pw(r, &sent_pw))) - return res; - - /* Ignore if we are not configured */ - if (!conf->anon_auth_passwords) - return DECLINED; - - /* Do we allow an empty userID and/or is it the magic one - */ - - if ((!(r->user[0])) && (conf->anon_auth_nouserid)) { - res = OK; - } - else { - anon_auth *p = conf->anon_auth_passwords; - res = DECLINED; - while ((res == DECLINED) && (p != NULL)) { - if (!(strcasecmp(r->user, p->password))) - res = OK; - p = p->next; - } - } - if ( - /* username is OK */ - (res == OK) - /* password been filled out ? */ - && ((!conf->anon_auth_mustemail) || strlen(sent_pw)) - /* does the password look like an email address ? */ - && ((!conf->anon_auth_verifyemail) - || ((strpbrk("@", sent_pw) != NULL) - && (strpbrk(".", sent_pw) != NULL)))) { - if (conf->anon_auth_logemail && ap_is_initial_req(r)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, r, - "Anonymous: Passwd <%s> Accepted", - sent_pw ? sent_pw : "\'none\'"); - } - return OK; - } - else { - if (conf->anon_auth_authoritative) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, APR_SUCCESS, r, - "Anonymous: Authoritative, Passwd <%s> not accepted", - sent_pw ? sent_pw : "\'none\'"); - return HTTP_UNAUTHORIZED; - } - /* Drop out the bottom to return DECLINED */ - } - - return DECLINED; -} - -static int check_anon_access(request_rec *r) -{ -#ifdef NOTYET - conn_rec *c = r->connection; - anon_auth_config_rec *conf = ap_get_module_config(r->per_dir_config, - &auth_anon_module); - - if (!conf->anon_auth) - return DECLINED; - - if (strcasecmp(r->connection->user, conf->anon_auth)) - return DECLINED; - - return OK; -#endif - return DECLINED; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_check_user_id(anon_authenticate_basic_user,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_auth_checker(check_anon_access,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA auth_anon_module = -{ - STANDARD20_MODULE_STUFF, - create_anon_auth_dir_config,/* dir config creater */ - NULL, /* dir merger ensure strictness */ - NULL, /* server config */ - NULL, /* merge server config */ - anon_auth_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/aaa/mod_auth_anon.dsp b/modules/aaa/mod_auth_anon.dsp deleted file mode 100644 index 9971dac259..0000000000 --- a/modules/aaa/mod_auth_anon.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_auth_anon" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_auth_anon - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_auth_anon.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_auth_anon.mak" CFG="mod_auth_anon - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_auth_anon - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_auth_anon - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_auth_anon - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_auth_anon" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_auth_anon.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_auth_anon -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_auth_anon.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_auth_anon - -!ELSEIF "$(CFG)" == "mod_auth_anon - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "..\..\srclib\apr-util\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_auth_anon" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_auth_anon.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_auth_anon -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_auth_anon.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_auth_anon - -!ENDIF - -# Begin Target - -# Name "mod_auth_anon - Win32 Release" -# Name "mod_auth_anon - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_auth_anon.c -# End Source File -# End Target -# End Project diff --git a/modules/aaa/mod_auth_anon.exp b/modules/aaa/mod_auth_anon.exp deleted file mode 100644 index 63282532a9..0000000000 --- a/modules/aaa/mod_auth_anon.exp +++ /dev/null @@ -1 +0,0 @@ -auth_anon_module diff --git a/modules/aaa/mod_auth_anon.mak b/modules/aaa/mod_auth_anon.mak deleted file mode 100644 index cc7fba0b46..0000000000 --- a/modules/aaa/mod_auth_anon.mak +++ /dev/null @@ -1,330 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_auth_anon.dsp -!IF "$(CFG)" == "" -CFG=mod_auth_anon - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_auth_anon - Win32\ - Release. -!ENDIF - -!IF "$(CFG)" != "mod_auth_anon - Win32 Release" && "$(CFG)" !=\ - "mod_auth_anon - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_auth_anon.mak" CFG="mod_auth_anon - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_auth_anon - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_auth_anon - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_auth_anon - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_auth_anon.so" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libapr - Win32 Release"\ - "$(OUTDIR)\mod_auth_anon.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_auth_anon.idb" - -@erase "$(INTDIR)\mod_auth_anon.obj" - -@erase "$(OUTDIR)\mod_auth_anon.exp" - -@erase "$(OUTDIR)\mod_auth_anon.lib" - -@erase "$(OUTDIR)\mod_auth_anon.map" - -@erase "$(OUTDIR)\mod_auth_anon.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_auth_anon" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_auth_anon.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_auth_anon.pdb" /map:"$(INTDIR)\mod_auth_anon.map"\ - /machine:I386 /out:"$(OUTDIR)\mod_auth_anon.so"\ - /implib:"$(OUTDIR)\mod_auth_anon.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_auth_anon -LINK32_OBJS= \ - "$(INTDIR)\mod_auth_anon.obj" \ - "..\..\Release\libhttpd.lib" \ - "..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_auth_anon.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_auth_anon - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_auth_anon.so" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libapr - Win32 Debug"\ - "$(OUTDIR)\mod_auth_anon.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_auth_anon.idb" - -@erase "$(INTDIR)\mod_auth_anon.obj" - -@erase "$(OUTDIR)\mod_auth_anon.exp" - -@erase "$(OUTDIR)\mod_auth_anon.lib" - -@erase "$(OUTDIR)\mod_auth_anon.map" - -@erase "$(OUTDIR)\mod_auth_anon.pdb" - -@erase "$(OUTDIR)\mod_auth_anon.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "..\..\srclib\apr-util\include" /D "_DEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_auth_anon" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_auth_anon.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_auth_anon.pdb" /map:"$(INTDIR)\mod_auth_anon.map" /debug\ - /machine:I386 /out:"$(OUTDIR)\mod_auth_anon.so"\ - /implib:"$(OUTDIR)\mod_auth_anon.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_auth_anon -LINK32_OBJS= \ - "$(INTDIR)\mod_auth_anon.obj" \ - "..\..\Debug\libhttpd.lib" \ - "..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_auth_anon.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_auth_anon - Win32 Release" || "$(CFG)" ==\ - "mod_auth_anon - Win32 Debug" - -!IF "$(CFG)" == "mod_auth_anon - Win32 Release" - -"libapr - Win32 Release" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Release" - cd "..\..\modules\aaa" - -"libapr - Win32 ReleaseCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\aaa" - -!ELSEIF "$(CFG)" == "mod_auth_anon - Win32 Debug" - -"libapr - Win32 Debug" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Debug" - cd "..\..\modules\aaa" - -"libapr - Win32 DebugCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\aaa" - -!ENDIF - -!IF "$(CFG)" == "mod_auth_anon - Win32 Release" - -"libhttpd - Win32 Release" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Release" - cd ".\modules\aaa" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Release"\ - RECURSE=1 - cd ".\modules\aaa" - -!ELSEIF "$(CFG)" == "mod_auth_anon - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Debug" - cd ".\modules\aaa" - -"libhttpd - Win32 DebugCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\aaa" - -!ENDIF - -SOURCE=.\mod_auth_anon.c -DEP_CPP_MOD_A=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\http_request.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\srclib\apr-util\include\apu.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_dso.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lock.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\include\apr_user.h"\ - "..\..\srclib\apr\include\apr_want.h"\ - -NODEP_CPP_MOD_A=\ - "..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\mod_auth_anon.obj" : $(SOURCE) $(DEP_CPP_MOD_A) "$(INTDIR)" - - - -!ENDIF - diff --git a/modules/aaa/mod_auth_db.c b/modules/aaa/mod_auth_db.c deleted file mode 100644 index a1925a8298..0000000000 --- a/modules/aaa/mod_auth_db.c +++ /dev/null @@ -1,419 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_auth_db: authentication - * - * Original work by Rob McCool & Brian Behlendorf. - * - * Adapted to Apache by rst (mod_auth_dbm) - * - * Adapted for Berkeley DB by Andrew Cohen - * - * apache 2 port by Brian Martin - * - * mod_auth_db was based on mod_auth_dbm. - * - * Warning, this is not a drop in replacement for mod_auth_dbm, - * for people wanting to switch from dbm to Berkeley DB. - * It requires the use of AuthDBUserFile and AuthDBGroupFile - * instead of AuthDBMUserFile AuthDBMGroupFile - * - * Also, in the configuration file you need to specify - * auth_db_module rather than auth_dbm_module - * - * On some BSD systems (e.g. FreeBSD and NetBSD) dbm is automatically - * mapped to Berkeley DB. You can use either mod_auth_dbm or - * mod_auth_db. The latter makes it more obvious that it's Berkeley. - * On other platforms where you want to use the DB library you - * usually have to install it first. See http://www.sleepycat.com/ - * for the distribution. The interface this module uses is the - * one from DB version 1.85 and 1.86, but DB version 2.x - * can also be used when compatibility mode is enabled. - * - * dirkx - Added Authoritative control to allow passing on to lower - * modules if and only if the userid is not known to this - * module. A known user with a faulty or absent password still - * causes an AuthRequired. The default is 'Authoritative', i.e. - * no control is passed along. - */ - -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_protocol.h" -#include "http_request.h" /* for ap_hook_(check_user_id | auth_check) */ - -#ifdef HAVE_DB_H -#include <db.h> -#endif - -#if defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 3) -#define DB_VER 3 -#elif defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 2) -#define DB_VER 2 -#else -#define DB_VER 1 -#endif - -typedef struct { - - char *auth_dbpwfile; - char *auth_dbgrpfile; - int auth_dbauthoritative; -} db_auth_config_rec; - -static void *create_db_auth_dir_config(apr_pool_t *p, char *d) -{ - db_auth_config_rec *conf = apr_pcalloc(p, sizeof(*conf)); - - conf->auth_dbpwfile = NULL; - conf->auth_dbgrpfile = NULL; - conf->auth_dbauthoritative = 1; /* fortress is secure by default */ - return conf; -} - -static const char *set_db_slot(cmd_parms *cmd, void *offset, const char *f, const char *t) -{ - if (!t || strcmp(t, "db")) - return DECLINE_CMD; - - return ap_set_file_slot(cmd, offset, f); -} - -static const command_rec db_auth_cmds[] = -{ - AP_INIT_TAKE1("AuthDBUserFile", ap_set_file_slot, - (void *) XtOffsetOf(db_auth_config_rec, auth_dbpwfile), - OR_AUTHCFG, NULL), - AP_INIT_TAKE1("AuthDBGroupFile", ap_set_file_slot, - (void *) XtOffsetOf(db_auth_config_rec, auth_dbgrpfile), - OR_AUTHCFG, NULL), - AP_INIT_TAKE12("AuthUserFile", set_db_slot, - (void *) XtOffsetOf(db_auth_config_rec, auth_dbpwfile), - OR_AUTHCFG, NULL), - AP_INIT_TAKE12("AuthGroupFile", set_db_slot, - (void *) XtOffsetOf(db_auth_config_rec, auth_dbgrpfile), - OR_AUTHCFG, NULL), - AP_INIT_FLAG("AuthDBAuthoritative", ap_set_flag_slot, - (void *) XtOffsetOf(db_auth_config_rec, auth_dbauthoritative), - OR_AUTHCFG, - "Set to 'no' to allow access control to be passed along to lower modules if the userID is not known to this module"), - {NULL} -}; - -module auth_db_module; - -static char *get_db_pw(request_rec *r, char *user, const char *auth_dbpwfile) -{ - DB *f; - DBT d, q; - char *pw = NULL; -#if DB_VER > 1 - int retval; -#endif - - memset(&d, 0, sizeof(d)); - memset(&q, 0, sizeof(q)); - - q.data = user; - q.size = strlen(q.data); - -#if DB_VER == 3 - db_create(&f, NULL, 0); - if ((retval = f->open(f, auth_dbpwfile, NULL, DB_HASH, DB_RDONLY, 0664)) != 0) { - char * reason; - switch(retval) { - case DB_OLD_VERSION: - reason = "Old database version. Upgrade to version 3"; - break; - - case EEXIST: - reason = "DB_CREATE and DB_EXCL were specified and the file exists"; - break; - - case EINVAL: - reason = "An invalid flag value or parameter was specified"; - break; - - case ENOENT: - reason = "A non-existent re_source file was specified"; - break; - - default: - reason = "And I don't know why"; - break; - } - ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, - "could not open db auth file %s: %s", - auth_dbpwfile, reason); - return NULL; - } -#elif DB_VER == 2 - if ((retval = db_open(auth_dbpwfile, DB_HASH, DB_RDONLY, 0664, NULL, NULL, &f)) != 0) { - char * reason; - switch(retval) { - - case EEXIST: - reason = "DB_CREATE and DB_EXCL were specified and the file exists."; - break; - - case EINVAL: - reason = "An invalid flag value or parameter was specified"; - break; - - case ENOENT: - reason = "A non-existent re_source file was specified"; - break; - - default: - reason = "And I don't know why"; - break; - } - ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, - "could not open db auth file %s: %s", - auth_dbpwfile, reason); - return NULL; - } -#else - if (!(f = dbopen(auth_dbpwfile, O_RDONLY, 0664, DB_HASH, NULL))) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, - "could not open db auth file: %s", auth_dbpwfile); - return NULL; - } -#endif - -#if DB_VER == 3 || DB_VER == 2 - if (!((f->get) (f, NULL, &q, &d, 0))) { -#else - if (!((f->get) (f, &q, &d, 0))) { -#endif - pw = apr_palloc(r->pool, d.size + 1); - strncpy(pw, d.data, d.size); - pw[d.size] = '\0'; /* Terminate the string */ - } - -#if DB_VER == 3 || DB_VER == 2 - (f->close) (f, 0); -#else - (f->close) (f); -#endif - return pw; -} - -/* We do something strange with the group file. If the group file - * contains any : we assume the format is - * key=username value=":"groupname [":"anything here is ignored] - * otherwise we now (0.8.14+) assume that the format is - * key=username value=groupname - * The first allows the password and group files to be the same - * physical DB file; key=username value=password":"groupname[":"anything] - * - * mark@telescope.org, 22Sep95 - */ - -static char *get_db_grp(request_rec *r, char *user, const char *auth_dbgrpfile) -{ - char *grp_data = get_db_pw(r, user, auth_dbgrpfile); - char *grp_colon; - char *grp_colon2; - - if (grp_data == NULL) - return NULL; - - if ((grp_colon = strchr(grp_data, ':')) != NULL) { - grp_colon2 = strchr(++grp_colon, ':'); - if (grp_colon2) - *grp_colon2 = '\0'; - return grp_colon; - } - return grp_data; -} - -static int db_authenticate_basic_user(request_rec *r) -{ - db_auth_config_rec *conf = ap_get_module_config(r->per_dir_config, - &auth_db_module); - const char *sent_pw; - char *real_pw, *colon_pw; - apr_status_t invalid_pw; - int res; - - if ((res = ap_get_basic_auth_pw(r, &sent_pw))) - return res; - - if (!conf->auth_dbpwfile) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "DB file %s not found", conf->auth_dbpwfile); - return DECLINED; - } - - if (!(real_pw = get_db_pw(r, r->user, conf->auth_dbpwfile))) { - if (!(conf->auth_dbauthoritative)) - return DECLINED; - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "DB user %s not found: %s", r->user, r->filename); - ap_note_basic_auth_failure(r); - return HTTP_UNAUTHORIZED; - } - /* Password is up to first : if exists */ - colon_pw = strchr(real_pw, ':'); - if (colon_pw) { - *colon_pw = '\0'; - } - - invalid_pw = apr_password_validate(sent_pw, real_pw); - - if (invalid_pw != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "DB user %s: authentication failure for \"%s\": " - "Password Mismatch", - r->user, r->uri); - ap_note_basic_auth_failure(r); - return HTTP_UNAUTHORIZED; - } - return OK; -} - -/* Checking ID */ - -static int db_check_auth(request_rec *r) -{ - db_auth_config_rec *conf = ap_get_module_config(r->per_dir_config, - &auth_db_module); - char *user = r->user; - int m = r->method_number; - - const apr_array_header_t *reqs_arr = ap_requires(r); - require_line *reqs = reqs_arr ? (require_line *) reqs_arr->elts : NULL; - - register int x; - const char *t; - char *w; - - if (!conf->auth_dbgrpfile) - return DECLINED; - if (!reqs_arr) - return DECLINED; - - for (x = 0; x < reqs_arr->nelts; x++) { - - if (!(reqs[x].method_mask & (1 << m))) - continue; - - t = reqs[x].requirement; - w = ap_getword_white(r->pool, &t); - - if (!strcmp(w, "group") && conf->auth_dbgrpfile) { - const char *orig_groups, *groups; - char *v; - - if (!(groups = get_db_grp(r, user, conf->auth_dbgrpfile))) { - if (!(conf->auth_dbauthoritative)) - return DECLINED; - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "user %s not in DB group file %s: %s", - user, conf->auth_dbgrpfile, r->filename); - ap_note_basic_auth_failure(r); - return HTTP_UNAUTHORIZED; - } - orig_groups = groups; - while (t[0]) { - w = ap_getword_white(r->pool, &t); - groups = orig_groups; - while (groups[0]) { - v = ap_getword(r->pool, &groups, ','); - if (!strcmp(v, w)) - return OK; - } - } - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "user %s not in right group: %s", user, r->filename); - ap_note_basic_auth_failure(r); - return HTTP_UNAUTHORIZED; - } - } - - return DECLINED; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_check_user_id(db_authenticate_basic_user, NULL, NULL, - APR_HOOK_MIDDLE); - ap_hook_auth_checker(db_check_auth, NULL, NULL, APR_HOOK_MIDDLE); -} - -module auth_db_module = -{ - STANDARD20_MODULE_STUFF, - create_db_auth_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - db_auth_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; - diff --git a/modules/aaa/mod_auth_db.module b/modules/aaa/mod_auth_db.module deleted file mode 100644 index 525075c3f1..0000000000 --- a/modules/aaa/mod_auth_db.module +++ /dev/null @@ -1,37 +0,0 @@ -Name: db_auth_module -ConfigStart - # XXX: this needs updating for apache-2.0 configuration method - DB_VERSION='' - DB_LIB='' - if ./build/TestCompile func db_open; then - DB_VERSION='Berkeley-DB/2.x' - else - if ./build/TestCompile lib db db_open; then - DB_VERSION='Berkeley-DB/2.x' - DB_LIB='-ldb' - else - if ./build/TestCompile func dbopen; then - DB_VERSION='Berkeley-DB/1.x' - else - if ./build/TestCompile lib db dbopen; then - DB_VERSION='Berkeley-DB/1.x' - DB_LIB='-ldb' - fi - fi - fi - fi - if [ ".$DB_VERSION" != . ]; then - if [ ".$DB_LIB" != . ]; then - LIBS="$LIBS $DB_LIB" - echo " using $DB_VERSION for mod_auth_db ($DB_LIB)" - else - echo " using $DB_VERSION for mod_auth_db (-lc)" - fi - else - echo "Error: Neither Berkeley-DB/1.x nor Berkeley-DB/2.x library found." - echo " Either disable mod_auth_db or provide us with the paths" - echo " to the Berkeley-DB include and library files." - echo " (Hint: INCLUDES, LDFLAGS, LIBS)" - exit 1 - fi -ConfigEnd diff --git a/modules/aaa/mod_auth_dbm.c b/modules/aaa/mod_auth_dbm.c deleted file mode 100644 index 0b9fcb4273..0000000000 --- a/modules/aaa/mod_auth_dbm.c +++ /dev/null @@ -1,358 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_auth: authentication - * - * Rob McCool & Brian Behlendorf. - * - * Adapted to Apache by rst. - * - * dirkx - Added Authoritative control to allow passing on to lower - * modules if and only if the userid is not known to this - * module. A known user with a faulty or absent password still - * causes an AuthRequired. The default is 'Authoritative', i.e. - * no control is passed along. - */ - -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if defined(AP_AUTH_DBM_USE_APR) -#include "apr_dbm.h" -#define DBM apr_dbm_t -#define datum apr_datum_t -#define dbm_open apr_dbm_open -#define dbm_fetch apr_dbm_fetch -#define dbm_close apr_dbm_close -#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) \ - && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 -#include <db1/ndbm.h> -#else -#include <ndbm.h> -#endif - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_protocol.h" -#include "http_request.h" /* for ap_hook_(check_user_id | auth_checker)*/ - - -/* - * Module definition information - the part between the -START and -END - * lines below is used by Configure. This could be stored in a separate - * instead. - * - * XXX: this needs updating for apache-2.0 configuration method - * MODULE-DEFINITION-START - * Name: auth_dbm_module - * ConfigStart - . ./build/find-dbm-lib - * ConfigEnd - * MODULE-DEFINITION-END - */ - -typedef struct { - - char *auth_dbmpwfile; - char *auth_dbmgrpfile; - int auth_dbmauthoritative; - -} dbm_auth_config_rec; - -static void *create_dbm_auth_dir_config(apr_pool_t *p, char *d) -{ - dbm_auth_config_rec *conf = apr_pcalloc(p, sizeof(*conf)); - - conf->auth_dbmpwfile = NULL; - conf->auth_dbmgrpfile = NULL; - conf->auth_dbmauthoritative = 1; /* fortress is secure by default */ - - return conf; -} - -static const char *set_dbm_slot(cmd_parms *cmd, void *offset, - const char *f, const char *t) -{ - if (!t || strcmp(t, "dbm")) - return DECLINE_CMD; - - return ap_set_file_slot(cmd, offset, f); -} - -static const command_rec dbm_auth_cmds[] = -{ - AP_INIT_TAKE1("AuthDBMUserFile", ap_set_file_slot, - (void *) XtOffsetOf(dbm_auth_config_rec, auth_dbmpwfile), - OR_AUTHCFG, NULL), - AP_INIT_TAKE1("AuthDBMGroupFile", ap_set_file_slot, - (void *) XtOffsetOf(dbm_auth_config_rec, auth_dbmgrpfile), - OR_AUTHCFG, NULL), - AP_INIT_TAKE12("AuthUserFile", set_dbm_slot, - (void *) XtOffsetOf(dbm_auth_config_rec, auth_dbmpwfile), - OR_AUTHCFG, NULL), - AP_INIT_TAKE12("AuthGroupFile", set_dbm_slot, - (void *) XtOffsetOf(dbm_auth_config_rec, auth_dbmgrpfile), - OR_AUTHCFG, NULL), - AP_INIT_FLAG("AuthDBMAuthoritative", ap_set_flag_slot, - (void *) XtOffsetOf(dbm_auth_config_rec, auth_dbmauthoritative), - OR_AUTHCFG, "Set to 'no' to allow access control to be passed along to lower modules, if the UserID is not known in this module"), - {NULL} -}; - -module AP_MODULE_DECLARE_DATA auth_dbm_module; - -static char *get_dbm_pw(request_rec *r, char *user, char *auth_dbmpwfile) -{ - DBM *f; - datum d, q; - char *pw = NULL; -#ifdef AP_AUTH_DBM_USE_APR - apr_status_t retval; -#endif - q.dptr = user; -#ifndef NETSCAPE_DBM_COMPAT - q.dsize = strlen(q.dptr); -#else - q.dsize = strlen(q.dptr) + 1; -#endif - -#ifdef AP_AUTH_DBM_USE_APR - if (!(retval = dbm_open(&f, auth_dbmpwfile, APR_DBM_READONLY, APR_OS_DEFAULT, r->pool))) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, retval, r, - "could not open sdbm auth file: %s", auth_dbmpwfile); - return NULL; - } - if (dbm_fetch(f, q, &d) == APR_SUCCESS) - /* sorry for the obscurity ... falls through to the - * if (d.dptr) { block ... - */ - -#else - if (!(f = dbm_open(auth_dbmpwfile, O_RDONLY, 0664))) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, - "could not open dbm auth file: %s", auth_dbmpwfile); - return NULL; - } - d = dbm_fetch(f, q); - -#endif - - if (d.dptr) { - pw = apr_palloc(r->pool, d.dsize + 1); - strncpy(pw, d.dptr, d.dsize); - pw[d.dsize] = '\0'; /* Terminate the string */ - } - - dbm_close(f); - return pw; -} - -/* We do something strange with the group file. If the group file - * contains any : we assume the format is - * key=username value=":"groupname [":"anything here is ignored] - * otherwise we now (0.8.14+) assume that the format is - * key=username value=groupname - * The first allows the password and group files to be the same - * physical DBM file; key=username value=password":"groupname[":"anything] - * - * mark@telescope.org, 22Sep95 - */ - -static char *get_dbm_grp(request_rec *r, char *user, char *auth_dbmgrpfile) -{ - char *grp_data = get_dbm_pw(r, user, auth_dbmgrpfile); - char *grp_colon; - char *grp_colon2; - - if (grp_data == NULL) - return NULL; - - if ((grp_colon = strchr(grp_data, ':')) != NULL) { - grp_colon2 = strchr(++grp_colon, ':'); - if (grp_colon2) - *grp_colon2 = '\0'; - return grp_colon; - } - return grp_data; -} - -static int dbm_authenticate_basic_user(request_rec *r) -{ - dbm_auth_config_rec *conf = ap_get_module_config(r->per_dir_config, - &auth_dbm_module); - const char *sent_pw; - char *real_pw, *colon_pw; - apr_status_t invalid_pw; - int res; - - if ((res = ap_get_basic_auth_pw(r, &sent_pw))) - return res; - - if (!conf->auth_dbmpwfile) - return DECLINED; - - if (!(real_pw = get_dbm_pw(r, r->user, conf->auth_dbmpwfile))) { - if (!(conf->auth_dbmauthoritative)) - return DECLINED; - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "DBM user %s not found: %s", r->user, r->filename); - ap_note_basic_auth_failure(r); - return HTTP_UNAUTHORIZED; - } - /* Password is up to first : if exists */ - colon_pw = strchr(real_pw, ':'); - if (colon_pw) { - *colon_pw = '\0'; - } - invalid_pw = apr_password_validate(sent_pw, real_pw); - if (invalid_pw != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "DBM user %s: authentication failure for \"%s\": " - "Password Mismatch", - r->user, r->uri); - ap_note_basic_auth_failure(r); - return HTTP_UNAUTHORIZED; - } - return OK; -} - -/* Checking ID */ - -static int dbm_check_auth(request_rec *r) -{ - dbm_auth_config_rec *conf = ap_get_module_config(r->per_dir_config, - &auth_dbm_module); - char *user = r->user; - int m = r->method_number; - - const apr_array_header_t *reqs_arr = ap_requires(r); - require_line *reqs = reqs_arr ? (require_line *) reqs_arr->elts : NULL; - - register int x; - const char *t; - char *w; - - if (!conf->auth_dbmgrpfile) - return DECLINED; - if (!reqs_arr) - return DECLINED; - - for (x = 0; x < reqs_arr->nelts; x++) { - - if (!(reqs[x].method_mask & (1 << m))) - continue; - - t = reqs[x].requirement; - w = ap_getword_white(r->pool, &t); - - if (!strcmp(w, "group") && conf->auth_dbmgrpfile) { - const char *orig_groups, *groups; - char *v; - - if (!(groups = get_dbm_grp(r, user, conf->auth_dbmgrpfile))) { - if (!(conf->auth_dbmauthoritative)) - return DECLINED; - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "user %s not in DBM group file %s: %s", - user, conf->auth_dbmgrpfile, r->filename); - ap_note_basic_auth_failure(r); - return HTTP_UNAUTHORIZED; - } - orig_groups = groups; - while (t[0]) { - w = ap_getword_white(r->pool, &t); - groups = orig_groups; - while (groups[0]) { - v = ap_getword(r->pool, &groups, ','); - if (!strcmp(v, w)) - return OK; - } - } - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "user %s not in right group: %s", - user, r->filename); - ap_note_basic_auth_failure(r); - return HTTP_UNAUTHORIZED; - } - } - - return DECLINED; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_check_user_id(dbm_authenticate_basic_user, NULL, NULL, - APR_HOOK_MIDDLE); - ap_hook_auth_checker(dbm_check_auth, NULL, NULL, APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA auth_dbm_module = -{ - STANDARD20_MODULE_STUFF, - create_dbm_auth_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - dbm_auth_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/aaa/mod_auth_dbm.dsp b/modules/aaa/mod_auth_dbm.dsp deleted file mode 100644 index 93fa4abc6d..0000000000 --- a/modules/aaa/mod_auth_dbm.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_auth_dbm" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_auth_dbm - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_auth_dbm.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_auth_dbm.mak" CFG="mod_auth_dbm - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_auth_dbm - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_auth_dbm - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_auth_dbm - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /I "..\..\srclib\sdbm" /I "..\..\os\win32" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "AP_AUTH_DBM_USE_APR" /Fd"Release\mod_auth_dbm" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_auth_dbm.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_auth_dbm -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_auth_dbm.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_auth_dbm - -!ELSEIF "$(CFG)" == "mod_auth_dbm - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /I "..\..\srclib\sdbm" /I "..\..\os\win32" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "AP_AUTH_DBM_USE_APR" /Fd"Debug\mod_auth_dbm" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_auth_dbm.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_auth_dbm -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_auth_dbm.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_auth_dbm - -!ENDIF - -# Begin Target - -# Name "mod_auth_dbm - Win32 Release" -# Name "mod_auth_dbm - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_auth_dbm.c -# End Source File -# End Target -# End Project diff --git a/modules/aaa/mod_auth_dbm.exp b/modules/aaa/mod_auth_dbm.exp deleted file mode 100644 index 7038e8047d..0000000000 --- a/modules/aaa/mod_auth_dbm.exp +++ /dev/null @@ -1 +0,0 @@ -auth_dbm_module diff --git a/modules/aaa/mod_auth_dbm.mak b/modules/aaa/mod_auth_dbm.mak deleted file mode 100644 index 11d7970042..0000000000 --- a/modules/aaa/mod_auth_dbm.mak +++ /dev/null @@ -1,366 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_auth_dbm.dsp -!IF "$(CFG)" == "" -CFG=mod_auth_dbm - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_auth_dbm - Win32\ - Release. -!ENDIF - -!IF "$(CFG)" != "mod_auth_dbm - Win32 Release" && "$(CFG)" !=\ - "mod_auth_dbm - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_auth_dbm.mak" CFG="mod_auth_dbm - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_auth_dbm - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_auth_dbm - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_auth_dbm - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_auth_dbm.so" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release"\ - "libapr - Win32 Release" "$(OUTDIR)\mod_auth_dbm.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN"\ - "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_auth_dbm.idb" - -@erase "$(INTDIR)\mod_auth_dbm.obj" - -@erase "$(OUTDIR)\mod_auth_dbm.exp" - -@erase "$(OUTDIR)\mod_auth_dbm.lib" - -@erase "$(OUTDIR)\mod_auth_dbm.map" - -@erase "$(OUTDIR)\mod_auth_dbm.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\srclib\apr\include"\ - /I "../../srclib/apr-util/include" /I "..\..\srclib\sdbm" /I "..\..\os\win32"\ - /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "AP_AUTH_DBM_USE_APR" /Fo"$(INTDIR)\\"\ - /Fd"$(INTDIR)\mod_auth_dbm" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_auth_dbm.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_auth_dbm.pdb" /map:"$(INTDIR)\mod_auth_dbm.map"\ - /machine:I386 /out:"$(OUTDIR)\mod_auth_dbm.so"\ - /implib:"$(OUTDIR)\mod_auth_dbm.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_auth_dbm -LINK32_OBJS= \ - "$(INTDIR)\mod_auth_dbm.obj" \ - "..\..\Release\libhttpd.lib" \ - "..\..\srclib\apr-util\Release\libaprutil.lib" \ - "..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_auth_dbm.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_auth_dbm - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_auth_dbm.so" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug"\ - "libapr - Win32 Debug" "$(OUTDIR)\mod_auth_dbm.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN"\ - "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_auth_dbm.idb" - -@erase "$(INTDIR)\mod_auth_dbm.obj" - -@erase "$(OUTDIR)\mod_auth_dbm.exp" - -@erase "$(OUTDIR)\mod_auth_dbm.lib" - -@erase "$(OUTDIR)\mod_auth_dbm.map" - -@erase "$(OUTDIR)\mod_auth_dbm.pdb" - -@erase "$(OUTDIR)\mod_auth_dbm.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /I\ - "..\..\srclib\sdbm" /I "..\..\os\win32" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D\ - "AP_AUTH_DBM_USE_APR" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_auth_dbm" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_auth_dbm.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_auth_dbm.pdb" /map:"$(INTDIR)\mod_auth_dbm.map" /debug\ - /machine:I386 /out:"$(OUTDIR)\mod_auth_dbm.so"\ - /implib:"$(OUTDIR)\mod_auth_dbm.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_auth_dbm -LINK32_OBJS= \ - "$(INTDIR)\mod_auth_dbm.obj" \ - "..\..\Debug\libhttpd.lib" \ - "..\..\srclib\apr-util\Debug\libaprutil.lib" \ - "..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_auth_dbm.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_auth_dbm - Win32 Release" || "$(CFG)" ==\ - "mod_auth_dbm - Win32 Debug" - -!IF "$(CFG)" == "mod_auth_dbm - Win32 Release" - -"libapr - Win32 Release" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Release" - cd "..\..\modules\aaa" - -"libapr - Win32 ReleaseCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\aaa" - -!ELSEIF "$(CFG)" == "mod_auth_dbm - Win32 Debug" - -"libapr - Win32 Debug" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Debug" - cd "..\..\modules\aaa" - -"libapr - Win32 DebugCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\aaa" - -!ENDIF - -!IF "$(CFG)" == "mod_auth_dbm - Win32 Release" - -"libaprutil - Win32 Release" : - cd "..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"\ - - cd "..\..\modules\aaa" - -"libaprutil - Win32 ReleaseCLEAN" : - cd "..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libaprutil.mak"\ - CFG="libaprutil - Win32 Release" RECURSE=1 - cd "..\..\modules\aaa" - -!ELSEIF "$(CFG)" == "mod_auth_dbm - Win32 Debug" - -"libaprutil - Win32 Debug" : - cd "..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" - cd "..\..\modules\aaa" - -"libaprutil - Win32 DebugCLEAN" : - cd "..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libaprutil.mak"\ - CFG="libaprutil - Win32 Debug" RECURSE=1 - cd "..\..\modules\aaa" - -!ENDIF - -!IF "$(CFG)" == "mod_auth_dbm - Win32 Release" - -"libhttpd - Win32 Release" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Release" - cd ".\modules\aaa" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Release"\ - RECURSE=1 - cd ".\modules\aaa" - -!ELSEIF "$(CFG)" == "mod_auth_dbm - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Debug" - cd ".\modules\aaa" - -"libhttpd - Win32 DebugCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\aaa" - -!ENDIF - -SOURCE=.\mod_auth_dbm.c -DEP_CPP_MOD_A=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\http_request.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\srclib\apr-util\include\apr_dbm.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\srclib\apr-util\include\apu.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_dso.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_lock.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\include\apr_user.h"\ - "..\..\srclib\apr\include\apr_want.h"\ - -NODEP_CPP_MOD_A=\ - "..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\mod_auth_dbm.obj" : $(SOURCE) $(DEP_CPP_MOD_A) "$(INTDIR)" - - - -!ENDIF - diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c deleted file mode 100644 index 2b0e233172..0000000000 --- a/modules/aaa/mod_auth_digest.c +++ /dev/null @@ -1,2083 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_auth_digest: MD5 digest authentication - * - * Originally by Alexei Kosut <akosut@nueva.pvt.k12.ca.us> - * Updated to RFC-2617 by Ronald Tschalär <ronald@innovation.ch> - * based on mod_auth, by Rob McCool and Robert S. Thau - * - * This module an updated version of modules/standard/mod_digest.c - * It is still fairly new and problems may turn up - submit problem - * reports to the Apache bug-database, or send them directly to me - * at ronald@innovation.ch. - * - * Requires either /dev/random (or equivalent) or the truerand library, - * available for instance from - * ftp://research.att.com/dist/mab/librand.shar - * - * Open Issues: - * - qop=auth-int (when streams and trailer support available) - * - nonce-format configurability - * - Proxy-Authorization-Info header is set by this module, but is - * currently ignored by mod_proxy (needs patch to mod_proxy) - * - generating the secret takes a while (~ 8 seconds) if using the - * truerand library - * - The source of the secret should be run-time directive (with server - * scope: RSRC_CONF). However, that could be tricky when trying to - * choose truerand vs. file... - * - shared-mem not completely tested yet. Seems to work ok for me, - * but... (definitely won't work on Windoze) - * - Sharing a realm among multiple servers has following problems: - * o Server name and port can't be included in nonce-hash - * (we need two nonce formats, which must be configured explicitly) - * o Nonce-count check can't be for equal, or then nonce-count checking - * must be disabled. What we could do is the following: - * (expected < received) ? set expected = received : issue error - * The only problem is that it allows replay attacks when somebody - * captures a packet sent to one server and sends it to another - * one. Should we add "AuthDigestNcCheck Strict"? - * - expired nonces give amaya fits. - */ - -#include "apr_sha1.h" -#include "apr_base64.h" -#include "apr_lib.h" -#include "apr_time.h" -#include "apr_errno.h" -#include "apr_lock.h" -#include "apr_strings.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_request.h" -#include "http_log.h" -#include "http_protocol.h" -#include "util_uri.h" -#include "util_md5.h" - -#if APR_HAS_SHARED_MEMORY -#include "apr_shmem.h" -#else -/* just provide dummies - the code does run-time checks anyway */ -typedef void apr_shmem_t; -typedef void apr_shm_name_t; - -apr_status_t apr_shm_init(apr_shmem_t **m, apr_size_t reqsize, const char *file, apr_pool_t *cont) { - return APR_ENOTIMPL; -} -apr_status_t apr_shm_destroy(apr_shmem_t *m) { - return APR_ENOTIMPL; -} -void *apr_shm_malloc(apr_shmem_t *c, apr_size_t reqsize) { - return NULL; -} -void *apr_shm_calloc(apr_shmem_t *shared, apr_size_t size) { - return NULL; -} -apr_status_t apr_shm_free(apr_shmem_t *shared, void *free) { - return APR_ENOTIMPL; -} -apr_status_t apr_shm_name_get(apr_shmem_t *c, apr_shm_name_t **name) { - return APR_ENOTIMPL; -} -apr_status_t apr_shm_name_set(apr_shmem_t *c, apr_shm_name_t *name) { - return APR_ENOTIMPL; -} -apr_status_t apr_shm_open(apr_shmem_t *c) { - return APR_ENOTIMPL; -} -apr_status_t apr_shm_avail(apr_shmem_t *c, apr_size_t *avail) { - return APR_ENOTIMPL; -} -#endif /* APR_HAS_SHARED_MEMORY */ - - -/* struct to hold the configuration info */ - -typedef struct digest_config_struct { - const char *dir_name; - const char *pwfile; - const char *grpfile; - const char *realm; - char **qop_list; - apr_sha1_ctx_t nonce_ctx; - apr_time_t nonce_lifetime; - const char *nonce_format; - int check_nc; - const char *algorithm; - char *uri_list; - const char *ha1; -} digest_config_rec; - - -#define DFLT_ALGORITHM "MD5" - -#define DFLT_NONCE_LIFE (300*APR_USEC_PER_SEC) -#define NEXTNONCE_DELTA (30*APR_USEC_PER_SEC) - - -#define NONCE_TIME_LEN (((sizeof(apr_time_t)+2)/3)*4) -#define NONCE_HASH_LEN (2*APR_SHA1_DIGESTSIZE) -#define NONCE_LEN (NONCE_TIME_LEN + NONCE_HASH_LEN) - -#define SECRET_LEN 20 - - -/* client list definitions */ - -typedef struct hash_entry { - unsigned long key; /* the key for this entry */ - struct hash_entry *next; /* next entry in the bucket */ - unsigned long nonce_count; /* for nonce-count checking */ - char ha1[2*MD5_DIGESTSIZE+1]; /* for algorithm=MD5-sess */ - char last_nonce[NONCE_LEN+1]; /* for one-time nonce's */ -} client_entry; - -static struct hash_table { - client_entry **table; - unsigned long tbl_len; - unsigned long num_entries; - unsigned long num_created; - unsigned long num_removed; - unsigned long num_renewed; -} *client_list; - - -/* struct to hold a parsed Authorization header */ - -enum hdr_sts { NO_HEADER, NOT_DIGEST, INVALID, VALID }; - -typedef struct digest_header_struct { - const char *scheme; - const char *realm; - const char *username; - char *nonce; - const char *uri; - const char *digest; - const char *algorithm; - const char *cnonce; - const char *opaque; - unsigned long opaque_num; - const char *message_qop; - const char *nonce_count; - /* the following fields are not (directly) from the header */ - apr_time_t nonce_time; - enum hdr_sts auth_hdr_sts; - const char *raw_request_uri; - uri_components *psd_request_uri; - int needed_auth; - client_entry *client; -} digest_header_rec; - - -/* (mostly) nonce stuff */ - -typedef union time_union { - apr_time_t time; - unsigned char arr[sizeof(apr_time_t)]; -} time_rec; - - -static unsigned char secret[SECRET_LEN]; -static int call_cnt = 0; - - -/* client-list, opaque, and one-time-nonce stuff */ - -static apr_shmem_t *client_shm = NULL; -static unsigned long *opaque_cntr; -static apr_time_t *otn_counter; /* one-time-nonce counter */ -static apr_lock_t *client_lock = NULL; -static apr_lock_t *opaque_lock = NULL; -static char client_lock_name[L_tmpnam]; -static char opaque_lock_name[L_tmpnam]; - -#define DEF_SHMEM_SIZE 1000L /* ~ 12 entries */ -#define DEF_NUM_BUCKETS 15L -#define HASH_DEPTH 5 - -static long shmem_size = DEF_SHMEM_SIZE; -static long num_buckets = DEF_NUM_BUCKETS; - - -module AP_MODULE_DECLARE_DATA auth_digest_module; - -/* - * initialization code - */ - -static apr_status_t cleanup_tables(void *not_used) -{ - ap_log_rerror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Digest: cleaning up shared memory"); - fflush(stderr); - - if (client_shm) { - apr_shm_destroy(client_shm); - client_shm = NULL; - } - - if (client_lock) { - apr_lock_destroy(client_lock); - client_lock = NULL; - } - - if (opaque_lock) { - apr_lock_destroy(opaque_lock); - opaque_lock = NULL; - } - - return APR_SUCCESS; -} - -static void initialize_secret(server_rec *s) -{ - apr_status_t status; - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, s, - "Digest: generating secret for digest authentication ..."); - -#if APR_HAS_RANDOM - status = apr_generate_random_bytes(secret, sizeof(secret)); -#else -#error APR random number support is missing; you probably need to install the truerand library. -#endif - - if(!(status == APR_SUCCESS)) { - char buf[120]; - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, 0, s, - "Digest: error generating secret: %s", - apr_strerror(status, buf, sizeof(buf))); - exit(1); - } - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, s, "Digest: done"); -} - -static void log_error_and_cleanup(char *msg, apr_status_t sts, server_rec *s) -{ - ap_log_error(APLOG_MARK, APLOG_ERR, sts, s, - "Digest: %s - all nonce-count checking, one-time nonces, and " - "MD5-sess algorithm disabled", msg); - - cleanup_tables(NULL); -} - -#if APR_HAS_SHARED_MEMORY - -static void initialize_tables(server_rec *s, apr_pool_t *ctx) -{ - unsigned long idx; - apr_status_t sts; - - /* set up client list */ - - sts = apr_shm_init(&client_shm, shmem_size, tmpnam(NULL), ctx); - if (sts != APR_SUCCESS) { - log_error_and_cleanup("failed to create shared memory segments", sts, s); - return; - } - - client_list = apr_shm_malloc(client_shm, sizeof(*client_list) + - sizeof(client_entry*)*num_buckets); - if (!client_list) { - log_error_and_cleanup("failed to allocate shared memory", -1, s); - return; - } - client_list->table = (client_entry**) (client_list + 1); - for (idx=0; idx<num_buckets; idx++) - client_list->table[idx] = NULL; - client_list->tbl_len = num_buckets; - client_list->num_entries = 0; - - tmpnam(client_lock_name); - sts = apr_lock_create(&client_lock, APR_READWRITE, APR_LOCKALL, - client_lock_name, ctx); - if (sts != APR_SUCCESS) { - log_error_and_cleanup("failed to create lock", sts, s); - return; - } - - - /* setup opaque */ - - opaque_cntr = apr_shm_malloc(client_shm, sizeof(*opaque_cntr)); - if (opaque_cntr == NULL) { - log_error_and_cleanup("failed to allocate shared memory", -1, s); - return; - } - *opaque_cntr = 1UL; - - tmpnam(opaque_lock_name); - sts = apr_lock_create(&opaque_lock, APR_MUTEX, APR_LOCKALL, - opaque_lock_name, ctx); - if (sts != APR_SUCCESS) { - log_error_and_cleanup("failed to create lock", sts, s); - return; - } - - - /* setup one-time-nonce counter */ - - otn_counter = apr_shm_malloc(client_shm, sizeof(*otn_counter)); - if (otn_counter == NULL) { - log_error_and_cleanup("failed to allocate shared memory", -1, s); - return; - } - *otn_counter = 0; - /* no lock here */ - - - /* success */ - return; -} - -#endif /* APR_HAS_SHARED_MEMORY */ - - -static void initialize_module(apr_pool_t *p, apr_pool_t *plog, - apr_pool_t *ptemp, server_rec *s) -{ - /* keep from doing the init more than once at startup, and delay - * the init until the second round - */ - if (++call_cnt < 2) - return; - - /* only initialize the secret on startup, not on restarts */ - if (call_cnt == 2) - initialize_secret(s); - -/* Disable shmem until pools/init gets sorted out - remove next line when fixed */ -#undef APR_HAS_SHARED_MEMORY -#define APR_HAS_SHARED_MEMORY 0 - -#if APR_HAS_SHARED_MEMORY - /* Note: this stuff is currently fixed for the lifetime of the server, - * i.e. even across restarts. This means that A) any shmem-size - * configuration changes are ignored, and B) certain optimizations, - * such as only allocating the smallest necessary entry for each - * client, can't be done. However, the alternative is a nightmare: - * we can't call apr_shm_destroy on a graceful restart because there - * will be children using the tables, and we also don't know when the - * last child dies. Therefore we can never clean up the old stuff, - * creating a creeping memory leak. - */ - initialize_tables(s, p); - apr_pool_cleanup_register(p, NULL, cleanup_tables, apr_pool_cleanup_null); -#endif /* APR_HAS_SHARED_MEMORY */ -} - -static void initialize_child(apr_pool_t *p, server_rec *s) -{ - apr_status_t sts; - - if (!client_shm) - return; - - if ((sts = apr_lock_child_init(&client_lock, client_lock_name, p)) - != APR_SUCCESS - || (sts = apr_lock_child_init(&opaque_lock, opaque_lock_name, p)) - != APR_SUCCESS) { - log_error_and_cleanup("failed to create lock", sts, s); - return; - } -} - -/* - * configuration code - */ - -static void *create_digest_dir_config(apr_pool_t *p, char *dir) -{ - digest_config_rec *conf; - - if (dir == NULL) return NULL; - - conf = (digest_config_rec *) apr_pcalloc(p, sizeof(digest_config_rec)); - if (conf) { - conf->qop_list = apr_palloc(p, sizeof(char*)); - conf->qop_list[0] = NULL; - conf->nonce_lifetime = DFLT_NONCE_LIFE; - conf->dir_name = apr_pstrdup(p, dir); - conf->algorithm = DFLT_ALGORITHM; - } - - return conf; -} - -static const char *set_realm(cmd_parms *cmd, void *config, const char *realm) -{ - digest_config_rec *conf = (digest_config_rec *) config; - - /* The core already handles the realm, but it's just too convenient to - * grab it ourselves too and cache some setups. However, we need to - * let the core get at it too, which is why we decline at the end - - * this relies on the fact that http_core is last in the list. - */ - conf->realm = realm; - - /* we precompute the part of the nonce hash that is constant (well, - * the host:port would be too, but that varies for .htaccess files - * and directives outside a virtual host section) - */ - apr_sha1_init(&conf->nonce_ctx); - apr_sha1_update_binary(&conf->nonce_ctx, secret, sizeof(secret)); - apr_sha1_update_binary(&conf->nonce_ctx, (const unsigned char *) realm, - strlen(realm)); - - return DECLINE_CMD; -} - -static const char *set_digest_file(cmd_parms *cmd, void *config, - const char *file) -{ - ((digest_config_rec *) config)->pwfile = file; - return NULL; -} - -static const char *set_group_file(cmd_parms *cmd, void *config, - const char *file) -{ - ((digest_config_rec *) config)->grpfile = file; - return NULL; -} - -static const char *set_qop(cmd_parms *cmd, void *config, const char *op) -{ - digest_config_rec *conf = (digest_config_rec *) config; - char **tmp; - int cnt; - - if (!strcasecmp(op, "none")) { - if (conf->qop_list[0] == NULL) { - conf->qop_list = apr_palloc(cmd->pool, 2 * sizeof(char*)); - conf->qop_list[1] = NULL; - } - conf->qop_list[0] = "none"; - return NULL; - } - - if (!strcasecmp(op, "auth-int")) - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, cmd->server, - "Digest: WARNING: qop `auth-int' currently only works " - "correctly for responses with no entity"); - else if (strcasecmp(op, "auth")) - return apr_pstrcat(cmd->pool, "Unrecognized qop: ", op, NULL); - - for (cnt=0; conf->qop_list[cnt] != NULL; cnt++) - ; - tmp = apr_palloc(cmd->pool, (cnt+2)*sizeof(char*)); - memcpy(tmp, conf->qop_list, cnt*sizeof(char*)); - tmp[cnt] = apr_pstrdup(cmd->pool, op); - tmp[cnt+1] = NULL; - conf->qop_list = tmp; - - return NULL; -} - -static const char *set_nonce_lifetime(cmd_parms *cmd, void *config, - const char *t) -{ - char *endptr; - long lifetime; - - lifetime = strtol(t, &endptr, 10); - if (endptr < (t+strlen(t)) && !apr_isspace(*endptr)) - return apr_pstrcat(cmd->pool, "Invalid time in AuthDigestNonceLifetime: ", t, NULL); - - ((digest_config_rec *) config)->nonce_lifetime = lifetime * APR_USEC_PER_SEC; - return NULL; -} - -static const char *set_nonce_format(cmd_parms *cmd, void *config, - const char *fmt) -{ - ((digest_config_rec *) config)->nonce_format = fmt; - return "AuthDigestNonceFormat is not implemented (yet)"; -} - -static const char *set_nc_check(cmd_parms *cmd, void *config, int flag) -{ - if (flag && !client_shm) - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, - cmd->server, "Digest: WARNING: nonce-count checking " - "is not supported on platforms without shared-memory " - "support - disabling check"); - - ((digest_config_rec *) config)->check_nc = flag; - return NULL; -} - -static const char *set_algorithm(cmd_parms *cmd, void *config, const char *alg) -{ - if (!strcasecmp(alg, "MD5-sess")) { - if (!client_shm) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, - cmd->server, "Digest: WARNING: algorithm `MD5-sess' " - "is not supported on platforms without shared-memory " - "support - reverting to MD5"); - alg = "MD5"; - } - } - else if (strcasecmp(alg, "MD5")) - return apr_pstrcat(cmd->pool, "Invalid algorithm in AuthDigestAlgorithm: ", alg, NULL); - - ((digest_config_rec *) config)->algorithm = alg; - return NULL; -} - -static const char *set_uri_list(cmd_parms *cmd, void *config, const char *uri) -{ - digest_config_rec *c = (digest_config_rec *) config; - if (c->uri_list) { - c->uri_list[strlen(c->uri_list)-1] = '\0'; - c->uri_list = apr_pstrcat(cmd->pool, c->uri_list, " ", uri, "\"", NULL); - } - else - c->uri_list = apr_pstrcat(cmd->pool, ", domain=\"", uri, "\"", NULL); - return NULL; -} - -static const char *set_shmem_size(cmd_parms *cmd, void *config, - const char *size_str) -{ - char *endptr; - long size, min; - - size = strtol(size_str, &endptr, 10); - while (apr_isspace(*endptr)) endptr++; - if (*endptr == '\0' || *endptr == 'b' || *endptr == 'B') - ; - else if (*endptr == 'k' || *endptr == 'K') - size *= 1024; - else if (*endptr == 'm' || *endptr == 'M') - size *= 1048576; - else - return apr_pstrcat(cmd->pool, "Invalid size in AuthDigestShmemSize: ", - size_str, NULL); - - min = sizeof(*client_list) + sizeof(client_entry*) + sizeof(client_entry); - if (size < min) - return apr_psprintf(cmd->pool, "size in AuthDigestShmemSize too small: " - "%ld < %ld", size, min); - - shmem_size = size; - num_buckets = (size - sizeof(*client_list)) / - (sizeof(client_entry*) + HASH_DEPTH * sizeof(client_entry)); - if (num_buckets == 0) - num_buckets = 1; - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, 0, cmd->server, - "Digest: Set shmem-size: %ld, num-buckets: %ld", shmem_size, - num_buckets); - - return NULL; -} - -static const command_rec digest_cmds[] = -{ - AP_INIT_TAKE1("AuthName", set_realm, NULL, OR_AUTHCFG, - "The authentication realm (e.g. \"Members Only\")"), - AP_INIT_TAKE1("AuthDigestFile", set_digest_file, NULL, OR_AUTHCFG, - "The name of the file containing the usernames and password hashes"), - AP_INIT_TAKE1("AuthDigestGroupFile", set_group_file, NULL, OR_AUTHCFG, - "The name of the file containing the group names and members"), - AP_INIT_ITERATE("AuthDigestQop", set_qop, NULL, OR_AUTHCFG, - "A list of quality-of-protection options"), - AP_INIT_TAKE1("AuthDigestNonceLifetime", set_nonce_lifetime, NULL, OR_AUTHCFG, - "Maximum lifetime of the server nonce (seconds)"), - AP_INIT_TAKE1("AuthDigestNonceFormat", set_nonce_format, NULL, OR_AUTHCFG, - "The format to use when generating the server nonce"), - AP_INIT_FLAG("AuthDigestNcCheck", set_nc_check, NULL, OR_AUTHCFG, - "Whether or not to check the nonce-count sent by the client"), - AP_INIT_TAKE1("AuthDigestAlgorithm", set_algorithm, NULL, OR_AUTHCFG, - "The algorithm used for the hash calculation"), - AP_INIT_ITERATE("AuthDigestDomain", set_uri_list, NULL, OR_AUTHCFG, - "A list of URI's which belong to the same protection space as the current URI"), - AP_INIT_TAKE1("AuthDigestShmemSize", set_shmem_size, NULL, RSRC_CONF, - "The amount of shared memory to allocate for keeping track of clients"), - {NULL} -}; - - -/* - * client list code - * - * Each client is assigned a number, which is transfered in the opaque - * field of the WWW-Authenticate and Authorization headers. The number - * is just a simple counter which is incremented for each new client. - * Clients can't forge this number because it is hashed up into the - * server nonce, and that is checked. - * - * The clients are kept in a simple hash table, which consists of an - * array of client_entry's, each with a linked list of entries hanging - * off it. The client's number modulo the size of the array gives the - * bucket number. - * - * The clients are garbage collected whenever a new client is allocated - * but there is not enough space left in the shared memory segment. A - * simple semi-LRU is used for this: whenever a client entry is accessed - * it is moved to the beginning of the linked list in its bucket (this - * also makes for faster lookups for current clients). The garbage - * collecter then just removes the oldest entry (i.e. the one at the - * end of the list) in each bucket. - * - * The main advantages of the above scheme are that it's easy to implement - * and it keeps the hash table evenly balanced (i.e. same number of entries - * in each bucket). The major disadvantage is that you may be throwing - * entries out which are in active use. This is not tragic, as these - * clients will just be sent a new client id (opaque field) and nonce - * with a stale=true (i.e. it will just look like the nonce expired, - * thereby forcing an extra round trip). If the shared memory segment - * has enough headroom over the current client set size then this should - * not occur too often. - * - * To help tune the size of the shared memory segment (and see if the - * above algorithm is really sufficient) a set of counters is kept - * indicating the number of clients held, the number of garbage collected - * clients, and the number of erroneously purged clients. These are printed - * out at each garbage collection run. Note that access to the counters is - * not synchronized because they are just indicaters, and whether they are - * off by a few doesn't matter; and for the same reason no attempt is made - * to guarantee the num_renewed is correct in the face of clients spoofing - * the opaque field. - */ - -/* - * Get the client given its client number (the key). Returns the entry, - * or NULL if its not found. - * - * Access to the list itself is synchronized via locks. However, access - * to the entry returned by get_client() is NOT synchronized. This means - * that there are potentially problems if a client uses multiple, - * simultaneous connections to access url's within the same protection - * space. However, these problems are not new: when using multiple - * connections you have no guarantee of the order the requests are - * processed anyway, so you have problems with the nonce-count and - * one-time nonces anyway. - */ -static client_entry *get_client(unsigned long key, const request_rec *r) -{ - int bucket; - client_entry *entry, *prev = NULL; - - - if (!key || !client_shm) return NULL; - - bucket = key % client_list->tbl_len; - entry = client_list->table[bucket]; - - apr_lock_acquire(client_lock /*, MM_LOCK_RD */); - - while(entry && key != entry->key) { - prev = entry; - entry = entry->next; - } - - if (entry && prev) { /* move entry to front of list */ - prev->next = entry->next; - entry->next = client_list->table[bucket]; - client_list->table[bucket] = entry; - } - - apr_lock_release(client_lock); - - if (entry) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, 0, r, - "get_client(): client %lu found", key); - else - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, 0, r, - "get_client(): client %lu not found", key); - - return entry; -} - - -/* A simple garbage-collecter to remove unused clients. It removes the - * last entry in each bucket and updates the counters. Returns the - * number of removed entries. - */ -static long gc(void) -{ - client_entry *entry, *prev; - unsigned long num_removed = 0, idx; - - /* garbage collect all last entries */ - - for (idx=0; idx<client_list->tbl_len; idx++) { - entry = client_list->table[idx]; - prev = NULL; - while (entry->next) { /* find last entry */ - prev = entry; - entry = entry->next; - } - if (prev) prev->next = NULL; /* cut list */ - else client_list->table[idx] = NULL; - if (entry) { /* remove entry */ - apr_shm_free(client_shm, entry); - num_removed++; - } - } - - /* update counters and log */ - - client_list->num_entries -= num_removed; - client_list->num_removed += num_removed; - - return num_removed; -} - - -/* - * Add a new client to the list. Returns the entry if successful, NULL - * otherwise. This triggers the garbage collection if memory is low. - */ -static client_entry *add_client(unsigned long key, client_entry *info, - server_rec *s) -{ - int bucket; - client_entry *entry; - - - if (!key || !client_shm) return NULL; - - bucket = key % client_list->tbl_len; - entry = client_list->table[bucket]; - - apr_lock_acquire(client_lock /*, MM_LOCK_RW */); - - /* try to allocate a new entry */ - - entry = apr_shm_malloc(client_shm, sizeof(client_entry)); - if (!entry) { - long num_removed = gc(); - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, s, - "Digest: gc'd %ld client entries. Total new clients: " - "%ld; Total removed clients: %ld; Total renewed clients: " - "%ld", num_removed, - client_list->num_created - client_list->num_renewed, - client_list->num_removed, client_list->num_renewed); - entry = apr_shm_malloc(client_shm, sizeof(client_entry)); - if (!entry) return NULL; /* give up */ - } - - /* now add the entry */ - - memcpy(entry, info, sizeof(client_entry)); - entry->key = key; - entry->next = client_list->table[bucket]; - client_list->table[bucket] = entry; - client_list->num_created++; - client_list->num_entries++; - - apr_lock_release(client_lock); - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, 0, s, - "allocated new client %lu", key); - - return entry; -} - - -/* - * Authorization header parser code - */ - -/* Parse the Authorization header, if it exists */ -static int get_digest_rec(request_rec *r, digest_header_rec *resp) -{ - const char *auth_line; - size_t l; - int vk = 0, vv = 0; - char *key, *value; - - auth_line = apr_table_get(r->headers_in, - (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authorization" - : "Authorization"); - if (!auth_line) { - resp->auth_hdr_sts = NO_HEADER; - return !OK; - } - - resp->scheme = ap_getword_white(r->pool, &auth_line); - if (strcasecmp(resp->scheme, "Digest")) { - resp->auth_hdr_sts = NOT_DIGEST; - return !OK; - } - - l = strlen(auth_line); - - key = apr_palloc(r->pool, l+1); - value = apr_palloc(r->pool, l+1); - - while (auth_line[0] != '\0') { - - /* find key */ - - while (apr_isspace(auth_line[0])) auth_line++; - vk = 0; - while (auth_line[0] != '=' && auth_line[0] != ',' - && auth_line[0] != '\0' && !apr_isspace(auth_line[0])) - key[vk++] = *auth_line++; - key[vk] = '\0'; - while (apr_isspace(auth_line[0])) auth_line++; - - /* find value */ - - if (auth_line[0] == '=') { - auth_line++; - while (apr_isspace(auth_line[0])) auth_line++; - - vv = 0; - if (auth_line[0] == '\"') { /* quoted string */ - auth_line++; - while (auth_line[0] != '\"' && auth_line[0] != '\0') { - if (auth_line[0] == '\\' && auth_line[1] != '\0') - auth_line++; /* escaped char */ - value[vv++] = *auth_line++; - } - if (auth_line[0] != '\0') auth_line++; - } - else { /* token */ - while (auth_line[0] != ',' && auth_line[0] != '\0' - && !apr_isspace(auth_line[0])) - value[vv++] = *auth_line++; - } - value[vv] = '\0'; - } - - while (auth_line[0] != ',' && auth_line[0] != '\0') auth_line++; - if (auth_line[0] != '\0') auth_line++; - - if (!strcasecmp(key, "username")) - resp->username = apr_pstrdup(r->pool, value); - else if (!strcasecmp(key, "realm")) - resp->realm = apr_pstrdup(r->pool, value); - else if (!strcasecmp(key, "nonce")) - resp->nonce = apr_pstrdup(r->pool, value); - else if (!strcasecmp(key, "uri")) - resp->uri = apr_pstrdup(r->pool, value); - else if (!strcasecmp(key, "response")) - resp->digest = apr_pstrdup(r->pool, value); - else if (!strcasecmp(key, "algorithm")) - resp->algorithm = apr_pstrdup(r->pool, value); - else if (!strcasecmp(key, "cnonce")) - resp->cnonce = apr_pstrdup(r->pool, value); - else if (!strcasecmp(key, "opaque")) - resp->opaque = apr_pstrdup(r->pool, value); - else if (!strcasecmp(key, "qop")) - resp->message_qop = apr_pstrdup(r->pool, value); - else if (!strcasecmp(key, "nc")) - resp->nonce_count = apr_pstrdup(r->pool, value); - } - - if (!resp->username || !resp->realm || !resp->nonce || !resp->uri - || !resp->digest - || (resp->message_qop && (!resp->cnonce || !resp->nonce_count))) { - resp->auth_hdr_sts = INVALID; - return !OK; - } - - if (resp->opaque) - resp->opaque_num = (unsigned long) strtol(resp->opaque, NULL, 16); - - resp->auth_hdr_sts = VALID; - return OK; -} - - -/* Because the browser may preemptively send auth info, incrementing the - * nonce-count when it does, and because the client does not get notified - * if the URI didn't need authentication after all, we need to be sure to - * update the nonce-count each time we receive an Authorization header no - * matter what the final outcome of the request. Furthermore this is a - * convenient place to get the request-uri (before any subrequests etc - * are initiated) and to initialize the request_config. - * - * Note that this must be called after mod_proxy had its go so that - * r->proxyreq is set correctly. - */ -static int parse_hdr_and_update_nc(request_rec *r) -{ - digest_header_rec *resp; - int res; - - if (!ap_is_initial_req(r)) - return DECLINED; - - resp = apr_pcalloc(r->pool, sizeof(digest_header_rec)); - resp->raw_request_uri = r->unparsed_uri; - resp->psd_request_uri = &r->parsed_uri; - resp->needed_auth = 0; - ap_set_module_config(r->request_config, &auth_digest_module, resp); - - res = get_digest_rec(r, resp); - resp->client = get_client(resp->opaque_num, r); - if (res == OK && resp->client) - resp->client->nonce_count++; - - return DECLINED; -} - - -/* - * Nonce generation code - */ - -/* The hash part of the nonce is a SHA-1 hash of the time, realm, server host - * and port, opaque, and our secret. - */ -static void gen_nonce_hash(char *hash, const char *timestr, const char *opaque, - const server_rec *server, - const digest_config_rec *conf) -{ - const char *hex = "0123456789abcdef"; - unsigned char sha1[APR_SHA1_DIGESTSIZE]; - apr_sha1_ctx_t ctx; - int idx; - - memcpy(&ctx, &conf->nonce_ctx, sizeof(ctx)); - /* - apr_sha1_update_binary(&ctx, (const unsigned char *) server->server_hostname, - strlen(server->server_hostname)); - apr_sha1_update_binary(&ctx, (const unsigned char *) &server->port, - sizeof(server->port)); - */ - apr_sha1_update_binary(&ctx, (const unsigned char *) timestr, strlen(timestr)); - if (opaque) - apr_sha1_update_binary(&ctx, (const unsigned char *) opaque, - strlen(opaque)); - apr_sha1_final(sha1, &ctx); - - for (idx=0; idx<APR_SHA1_DIGESTSIZE; idx++) { - *hash++ = hex[sha1[idx] >> 4]; - *hash++ = hex[sha1[idx] & 0xF]; - } - - *hash++ = '\0'; -} - - -/* The nonce has the format b64(time)+hash . - */ -static const char *gen_nonce(apr_pool_t *p, apr_time_t now, const char *opaque, - const server_rec *server, - const digest_config_rec *conf) -{ - char *nonce = apr_palloc(p, NONCE_LEN+1); - int len; - time_rec t; - - if (conf->nonce_lifetime != 0) - t.time = now; - else if (otn_counter) - /* this counter is not synch'd, because it doesn't really matter - * if it counts exactly. - */ - t.time = (*otn_counter)++; - else - t.time = 42; - len = apr_base64_encode_binary(nonce, t.arr, sizeof(t.arr)); - gen_nonce_hash(nonce+NONCE_TIME_LEN, nonce, opaque, server, conf); - - return nonce; -} - - -/* - * Opaque and hash-table management - */ - -/* - * Generate a new client entry, add it to the list, and return the - * entry. Returns NULL if failed. - */ -static client_entry *gen_client(const request_rec *r) -{ - unsigned long op; - client_entry new_entry = { 0, NULL, 0, "", "" }, *entry; - - if (!opaque_cntr) return NULL; - - apr_lock_acquire(opaque_lock /*, MM_LOCK_RW */); - op = (*opaque_cntr)++; - apr_lock_release(opaque_lock); - - if (!(entry = add_client(op, &new_entry, r->server))) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "Digest: failed to allocate client entry - ignoring " - "client"); - return NULL; - } - - return entry; -} - - -/* - * MD5-sess code. - * - * If you want to use algorithm=MD5-sess you must write get_userpw_hash() - * yourself (see below). The dummy provided here just uses the hash from - * the auth-file, i.e. it is only useful for testing client implementations - * of MD5-sess . - */ - -/* - * get_userpw_hash() will be called each time a new session needs to be - * generated and is expected to return the equivalent of - * - * h_urp = ap_md5(r->pool, - * apr_pstrcat(r->pool, username, ":", ap_auth_name(r), ":", passwd)) - * ap_md5(r->pool, - * (unsigned char *) apr_pstrcat(r->pool, h_urp, ":", resp->nonce, ":", - * resp->cnonce, NULL)); - * - * or put differently, it must return - * - * MD5(MD5(username ":" realm ":" password) ":" nonce ":" cnonce) - * - * If something goes wrong, the failure must be logged and NULL returned. - * - * You must implement this yourself, which will probably consist of code - * contacting the password server with the necessary information (typically - * the username, realm, nonce, and cnonce) and receiving the hash from it. - * - * TBD: This function should probably be in a seperate source file so that - * people need not modify mod_auth_digest.c each time they install a new - * version of apache. - */ -static const char *get_userpw_hash(const request_rec *r, - const digest_header_rec *resp, - const digest_config_rec *conf) -{ - return ap_md5(r->pool, - (unsigned char *) apr_pstrcat(r->pool, conf->ha1, ":", resp->nonce, - ":", resp->cnonce, NULL)); -} - - -/* Retrieve current session H(A1). If there is none and "generate" is - * true then a new session for MD5-sess is generated and stored in the - * client struct; if generate is false, or a new session could not be - * generated then NULL is returned (in case of failure to generate the - * failure reason will have been logged already). - */ -static const char *get_session_HA1(const request_rec *r, - digest_header_rec *resp, - const digest_config_rec *conf, - int generate) -{ - const char *ha1 = NULL; - - /* return the current sessions if there is one */ - if (resp->opaque && resp->client && resp->client->ha1[0]) - return resp->client->ha1; - else if (!generate) - return NULL; - - /* generate a new session */ - if (!resp->client) - resp->client = gen_client(r); - if (resp->client) { - ha1 = get_userpw_hash(r, resp, conf); - if (ha1) - memcpy(resp->client->ha1, ha1, sizeof(resp->client->ha1)); - } - - return ha1; -} - - -static void clear_session(const digest_header_rec *resp) -{ - if (resp->client) - resp->client->ha1[0] = '\0'; -} - - -/* - * Authorization challenge generation code (for WWW-Authenticate) - */ - -static const char *guess_domain(apr_pool_t *p, const char *uri, - const char *filename, const char *dir) -{ - size_t u_len = strlen(uri), f_len = strlen(filename), d_len = strlen(dir); - const char *u, *f; - - - /* Because of things like mod_alias and mod_rewrite and the fact that - * protection is often on a directory basis (not a location basis) it - * is hard to determine the uri to put in the domain attribute. - * - * What we do is the following: first we see if the directory is - * a prefix for the uri - if this is the case we assume that therefore - * a <Location> directive was protecting this uri and we can use it - * for the domain. - */ - if (u_len >= d_len && !memcmp(uri, dir, d_len)) - return dir; - - /* Now we check for <Files ...>, and if we find one we send back a - * dummy uri - this is the only way to specify that the protection - * space only covers a single uri. - */ - if (dir[0] != '/') - /* This doesn't work for Amaya (ok, it's of arguable validity in - * the first place), so just return the file name instead - return "http://0.0.0.0/"; - */ - return dir; - - /* Next we find the largest common common suffix of the request-uri - * and the final file name, ignoring any extensions; this gives us a - * hint as to where any rewriting could've occured (assuming that some - * prefix of the uri is rewritten, not a suffix). - */ - u = uri + u_len - 1; /* strip any extension */ - while (u > uri && *u != '/') u--; - while (*u && *u != '.') u++; - if (*u == '.') u--; - if (*u == '/') u--; - - f = filename + f_len - 1; /* strip any extension */ - while (f > filename && *f != '/') f--; - while (*f && *f != '.') f++; - if (*f == '.') f--; - if (*f == '/') f--; - - while (*f == *u && f > filename && u > uri) u--, f--; - f++; u++; - - while (*f && *f != '/') f++, u++; /* suffix must start with / */ - - /* Now, if the directory reaches into this common suffix then we can - * take the uri with the same reach. - */ - if ((unsigned long) (f-filename) < d_len) { - char *tmp = apr_pstrdup(p, uri); - tmp[(u-uri)+(d_len-(f-filename))] = '\0'; - return tmp; - } - - return ""; /* give up */ -} - - -static const char *ltox(apr_pool_t *p, unsigned long num) -{ - if (num != 0) - return apr_psprintf(p, "%lx", num); - else - return ""; -} - -static void note_digest_auth_failure(request_rec *r, - const digest_config_rec *conf, - digest_header_rec *resp, int stale) -{ - const char *qop, *opaque, *opaque_param, *domain, *nonce; - int cnt; - - /* Setup qop */ - - if (conf->qop_list[0] == NULL) { - qop = ", qop=\"auth\""; - } else if (!strcasecmp(conf->qop_list[0], "none")) { - qop = ""; - } else { - qop = apr_pstrcat(r->pool, ", qop=\"", conf->qop_list[0], NULL); - for (cnt=1; conf->qop_list[cnt] != NULL; cnt++) - qop = apr_pstrcat(r->pool, qop, ",", conf->qop_list[cnt], NULL); - qop = apr_pstrcat(r->pool, qop, "\"", NULL); - } - - /* Setup opaque */ - - if (resp->opaque == NULL) { - /* new client */ - if ((conf->check_nc || conf->nonce_lifetime == 0 - || !strcasecmp(conf->algorithm, "MD5-sess")) - && (resp->client = gen_client(r)) != NULL) - opaque = ltox(r->pool, resp->client->key); - else - opaque = ""; /* opaque not needed */ - } - else if (resp->client == NULL) { - /* client info was gc'd */ - resp->client = gen_client(r); - if (resp->client != NULL) { - opaque = ltox(r->pool, resp->client->key); - stale = 1; - client_list->num_renewed++; - } - else - opaque = ""; /* ??? */ - } - else { - opaque = resp->opaque; - /* we're generating a new nonce, so reset the nonce-count */ - resp->client->nonce_count = 0; - } - - if (opaque[0]) - opaque_param = apr_pstrcat(r->pool, ", opaque=\"", opaque, "\"", NULL); - else - opaque_param = NULL; - - /* Setup nonce */ - - nonce = gen_nonce(r->pool, r->request_time, opaque, r->server, conf); - if (resp->client && conf->nonce_lifetime == 0) - memcpy(resp->client->last_nonce, nonce, NONCE_LEN+1); - - /* Setup MD5-sess stuff. Note that we just clear out the session - * info here, since we can't generate a new session until the request - * from the client comes in with the cnonce. - */ - - if (!strcasecmp(conf->algorithm, "MD5-sess")) - clear_session(resp); - - /* setup domain attribute. We want to send this attribute wherever - * possible so that the client won't send the Authorization header - * unneccessarily (it's usually > 200 bytes!). - */ - - if (r->proxyreq) - domain = NULL; /* don't send domain for proxy requests */ - else if (conf->uri_list) - domain = conf->uri_list; - else { - /* They didn't specify any domain, so let's guess at it */ - domain = guess_domain(r->pool, resp->psd_request_uri->path, r->filename, - conf->dir_name); - if (domain[0] == '/' && domain[1] == '\0') - domain = NULL; /* "/" is the default, so no need to send it */ - else - domain = apr_pstrcat(r->pool, ", domain=\"", domain, "\"", NULL); - } - - apr_table_mergen(r->err_headers_out, - (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authenticate" : "WWW-Authenticate", - apr_psprintf(r->pool, "Digest realm=\"%s\", nonce=\"%s\", " - "algorithm=%s%s%s%s%s", - ap_auth_name(r), nonce, conf->algorithm, - opaque_param ? opaque_param : "", - domain ? domain : "", - stale ? ", stale=true" : "", qop)); - -} - - -/* - * Authorization header verification code - */ - -static const char *get_hash(request_rec *r, const char *user, - const char *realm, const char *auth_pwfile) -{ - ap_configfile_t *f; - char l[MAX_STRING_LEN]; - const char *rpw; - char *w, *x; - apr_status_t sts; - - if ((sts = ap_pcfg_openfile(&f, r->pool, auth_pwfile)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, sts, r, - "Digest: Could not open password file: %s", auth_pwfile); - return NULL; - } - while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) { - if ((l[0] == '#') || (!l[0])) - continue; - rpw = l; - w = ap_getword(r->pool, &rpw, ':'); - x = ap_getword(r->pool, &rpw, ':'); - - if (x && w && !strcmp(user, w) && !strcmp(realm, x)) { - ap_cfg_closefile(f); - return apr_pstrdup(r->pool, rpw); - } - } - ap_cfg_closefile(f); - return NULL; -} - -static int check_nc(const request_rec *r, const digest_header_rec *resp, - const digest_config_rec *conf) -{ - unsigned long nc; - const char *snc = resp->nonce_count; - char *endptr; - - if (!conf->check_nc || !client_shm) - return OK; - - nc = strtol(snc, &endptr, 16); - if (endptr < (snc+strlen(snc)) && !apr_isspace(*endptr)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: invalid nc %s received - not a number", snc); - return !OK; - } - - if (!resp->client) - return !OK; - - if (nc != resp->client->nonce_count) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: Warning, possible replay attack: nonce-count " - "check failed: %lu != %lu", nc, - resp->client->nonce_count); - return !OK; - } - - return OK; -} - -static int check_nonce(request_rec *r, digest_header_rec *resp, - const digest_config_rec *conf) -{ - apr_time_t dt; - int len; - time_rec nonce_time; - char tmp, hash[NONCE_HASH_LEN+1]; - - if (strlen(resp->nonce) != NONCE_LEN) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: invalid nonce %s received - length is not %d", - resp->nonce, NONCE_LEN); - note_digest_auth_failure(r, conf, resp, 1); - return HTTP_UNAUTHORIZED; - } - - tmp = resp->nonce[NONCE_TIME_LEN]; - resp->nonce[NONCE_TIME_LEN] = '\0'; - len = apr_base64_decode_binary(nonce_time.arr, resp->nonce); - gen_nonce_hash(hash, resp->nonce, resp->opaque, r->server, conf); - resp->nonce[NONCE_TIME_LEN] = tmp; - resp->nonce_time = nonce_time.time; - - if (strcmp(hash, resp->nonce+NONCE_TIME_LEN)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: invalid nonce %s received - hash is not %s", - resp->nonce, hash); - note_digest_auth_failure(r, conf, resp, 1); - return HTTP_UNAUTHORIZED; - } - - dt = r->request_time - nonce_time.time; - if (conf->nonce_lifetime > 0 && dt < 0) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: invalid nonce %s received - user attempted " - "time travel", resp->nonce); - note_digest_auth_failure(r, conf, resp, 1); - return HTTP_UNAUTHORIZED; - } - - if (conf->nonce_lifetime > 0) { - if (dt > conf->nonce_lifetime) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0,r, - "Digest: user %s: nonce expired (%.2f seconds old - max lifetime %.2f) - sending new nonce", - r->user, ((double)dt)/APR_USEC_PER_SEC, - ((double)(conf->nonce_lifetime))/APR_USEC_PER_SEC); - note_digest_auth_failure(r, conf, resp, 1); - return HTTP_UNAUTHORIZED; - } - } - else if (conf->nonce_lifetime == 0 && resp->client) { - if (memcmp(resp->client->last_nonce, resp->nonce, NONCE_LEN)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r, - "Digest: user %s: one-time-nonce mismatch - sending " - "new nonce", r->user); - note_digest_auth_failure(r, conf, resp, 1); - return HTTP_UNAUTHORIZED; - } - } - /* else (lifetime < 0) => never expires */ - - return OK; -} - -/* The actual MD5 code... whee */ - -/* RFC-2069 */ -static const char *old_digest(const request_rec *r, - const digest_header_rec *resp, const char *ha1) -{ - const char *ha2; - - ha2 = ap_md5(r->pool, (unsigned char *)apr_pstrcat(r->pool, r->method, ":", - resp->uri, NULL)); - return ap_md5(r->pool, - (unsigned char *)apr_pstrcat(r->pool, ha1, ":", resp->nonce, - ":", ha2, NULL)); -} - -/* RFC-2617 */ -static const char *new_digest(const request_rec *r, - digest_header_rec *resp, - const digest_config_rec *conf) -{ - const char *ha1, *ha2, *a2; - - if (resp->algorithm && !strcasecmp(resp->algorithm, "MD5-sess")) { - ha1 = get_session_HA1(r, resp, conf, 1); - if (!ha1) - return NULL; - } - else - ha1 = conf->ha1; - - if (resp->message_qop && !strcasecmp(resp->message_qop, "auth-int")) - a2 = apr_pstrcat(r->pool, r->method, ":", resp->uri, ":", - ap_md5(r->pool, (const unsigned char*) ""), NULL); /* TBD */ - else - a2 = apr_pstrcat(r->pool, r->method, ":", resp->uri, NULL); - ha2 = ap_md5(r->pool, (const unsigned char *)a2); - - return ap_md5(r->pool, - (unsigned char *)apr_pstrcat(r->pool, ha1, ":", resp->nonce, - ":", resp->nonce_count, ":", - resp->cnonce, ":", - resp->message_qop, ":", ha2, - NULL)); -} - - -static void copy_uri_components(uri_components *dst, uri_components *src, - request_rec *r) { - if (src->scheme && src->scheme[0] != '\0') - dst->scheme = src->scheme; - else - dst->scheme = (char *) "http"; - - if (src->hostname && src->hostname[0] != '\0') { - dst->hostname = apr_pstrdup(r->pool, src->hostname); - ap_unescape_url(dst->hostname); - } - else - dst->hostname = (char *) ap_get_server_name(r); - - if (src->port_str && src->port_str[0] != '\0') - dst->port = src->port; - else - dst->port = ap_get_server_port(r); - - if (src->path && src->path[0] != '\0') { - dst->path = apr_pstrdup(r->pool, src->path); - ap_unescape_url(dst->path); - } - else - dst->path = src->path; - - if (src->query && src->query[0] != '\0') { - dst->query = apr_pstrdup(r->pool, src->query); - ap_unescape_url(dst->query); - } - else - dst->query = src->query; -} - -/* These functions return 0 if client is OK, and proper error status - * if not... either HTTP_UNAUTHORIZED, if we made a check, and it failed, or - * HTTP_INTERNAL_SERVER_ERROR, if things are so totally confused that we - * couldn't figure out how to tell if the client is authorized or not. - * - * If they return DECLINED, and all other modules also decline, that's - * treated by the server core as a configuration error, logged and - * reported as such. - */ - -/* Determine user ID, and check if the attributes are correct, if it - * really is that user, if the nonce is correct, etc. - */ - -static int authenticate_digest_user(request_rec *r) -{ - digest_config_rec *conf; - digest_header_rec *resp; - request_rec *mainreq; - const char *t; - int res; - - /* do we require Digest auth for this URI? */ - - if (!(t = ap_auth_type(r)) || strcasecmp(t, "Digest")) - return DECLINED; - - if (!ap_auth_name(r)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: need AuthName: %s", r->uri); - return HTTP_INTERNAL_SERVER_ERROR; - } - - - /* get the client response and mark */ - - mainreq = r; - while (mainreq->main != NULL) mainreq = mainreq->main; - while (mainreq->prev != NULL) mainreq = mainreq->prev; - resp = (digest_header_rec *) ap_get_module_config(mainreq->request_config, - &auth_digest_module); - resp->needed_auth = 1; - - - /* get our conf */ - - conf = (digest_config_rec *) ap_get_module_config(r->per_dir_config, - &auth_digest_module); - - - /* check for existence and syntax of Auth header */ - - if (resp->auth_hdr_sts != VALID) { - if (resp->auth_hdr_sts == NOT_DIGEST) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: client used wrong authentication scheme " - "`%s': %s", resp->scheme, r->uri); - else if (resp->auth_hdr_sts == INVALID) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: missing user, realm, nonce, uri, digest, " - "cnonce, or nonce_count in authorization header: %s", - r->uri); - /* else (resp->auth_hdr_sts == NO_HEADER) */ - note_digest_auth_failure(r, conf, resp, 0); - return HTTP_UNAUTHORIZED; - } - - r->user = (char *) resp->username; - r->ap_auth_type = (char *) "Digest"; - - /* check the auth attributes */ - - if (strcmp(resp->uri, resp->raw_request_uri)) { - /* Hmm, the simple match didn't work (probably a proxy modified the - * request-uri), so lets do a more sophisticated match - */ - uri_components r_uri, d_uri; - - copy_uri_components(&r_uri, resp->psd_request_uri, r); - if (ap_parse_uri_components(r->pool, resp->uri, &d_uri) != HTTP_OK) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: invalid uri <%s> in Authorization header", - resp->uri); - return HTTP_BAD_REQUEST; - } - - if (d_uri.hostname) - ap_unescape_url(d_uri.hostname); - if (d_uri.path) - ap_unescape_url(d_uri.path); - if (d_uri.query) - ap_unescape_url(d_uri.query); - - if (r->method_number == M_CONNECT) { - if (strcmp(resp->uri, r_uri.hostinfo)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: uri mismatch - <%s> does not match " - "request-uri <%s>", resp->uri, r_uri.hostinfo); - return HTTP_BAD_REQUEST; - } - } - else if ( - /* check hostname matches, if present */ - (d_uri.hostname && d_uri.hostname[0] != '\0' - && strcasecmp(d_uri.hostname, r_uri.hostname)) - /* check port matches, if present */ - || (d_uri.port_str && d_uri.port != r_uri.port) - /* check that server-port is default port if no port present */ - || (d_uri.hostname && d_uri.hostname[0] != '\0' - && !d_uri.port_str && r_uri.port != ap_default_port(r)) - /* check that path matches */ - || (d_uri.path != r_uri.path - /* either exact match */ - && (!d_uri.path || !r_uri.path - || strcmp(d_uri.path, r_uri.path)) - /* or '*' matches empty path in scheme://host */ - && !(d_uri.path && !r_uri.path && resp->psd_request_uri->hostname - && d_uri.path[0] == '*' && d_uri.path[1] == '\0')) - /* check that query matches */ - || (d_uri.query != r_uri.query - && (!d_uri.query || !r_uri.query - || strcmp(d_uri.query, r_uri.query))) - ) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: uri mismatch - <%s> does not match " - "request-uri <%s>", resp->uri, resp->raw_request_uri); - return HTTP_BAD_REQUEST; - } - } - - if (resp->opaque && resp->opaque_num == 0) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: received invalid opaque - got `%s'", - resp->opaque); - note_digest_auth_failure(r, conf, resp, 0); - return HTTP_UNAUTHORIZED; - } - - if (strcmp(resp->realm, conf->realm)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: realm mismatch - got `%s' but expected `%s'", - resp->realm, conf->realm); - note_digest_auth_failure(r, conf, resp, 0); - return HTTP_UNAUTHORIZED; - } - - if (resp->algorithm != NULL - && strcasecmp(resp->algorithm, "MD5") - && strcasecmp(resp->algorithm, "MD5-sess")) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: unknown algorithm `%s' received: %s", - resp->algorithm, r->uri); - note_digest_auth_failure(r, conf, resp, 0); - return HTTP_UNAUTHORIZED; - } - - if (!conf->pwfile) - return DECLINED; - - if (!(conf->ha1 = get_hash(r, r->user, conf->realm, conf->pwfile))) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: user `%s' in realm `%s' not found: %s", - r->user, conf->realm, r->uri); - note_digest_auth_failure(r, conf, resp, 0); - return HTTP_UNAUTHORIZED; - } - - - if (resp->message_qop == NULL) { - /* old (rfc-2069) style digest */ - if (strcmp(resp->digest, old_digest(r, resp, conf->ha1))) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: user %s: password mismatch: %s", r->user, - r->uri); - note_digest_auth_failure(r, conf, resp, 0); - return HTTP_UNAUTHORIZED; - } - } - else { - const char *exp_digest; - int match = 0, idx; - for (idx=0; conf->qop_list[idx] != NULL; idx++) { - if (!strcasecmp(conf->qop_list[idx], resp->message_qop)) { - match = 1; - break; - } - } - - if (!match - && !(conf->qop_list[0] == NULL - && !strcasecmp(resp->message_qop, "auth"))) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: invalid qop `%s' received: %s", - resp->message_qop, r->uri); - note_digest_auth_failure(r, conf, resp, 0); - return HTTP_UNAUTHORIZED; - } - - exp_digest = new_digest(r, resp, conf); - if (!exp_digest) { - /* we failed to allocate a client struct */ - return HTTP_INTERNAL_SERVER_ERROR; - } - if (strcmp(resp->digest, exp_digest)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: user %s: password mismatch: %s", r->user, - r->uri); - note_digest_auth_failure(r, conf, resp, 0); - return HTTP_UNAUTHORIZED; - } - } - - if (check_nc(r, resp, conf) != OK) { - note_digest_auth_failure(r, conf, resp, 0); - return HTTP_UNAUTHORIZED; - } - - /* Note: this check is done last so that a "stale=true" can be - generated if the nonce is old */ - if ((res = check_nonce(r, resp, conf))) - return res; - - return OK; -} - - -/* - * Checking ID - */ - -static apr_table_t *groups_for_user(request_rec *r, const char *user, - const char *grpfile) -{ - ap_configfile_t *f; - apr_table_t *grps = apr_table_make(r->pool, 15); - apr_pool_t *sp; - char l[MAX_STRING_LEN]; - const char *group_name, *ll, *w; - apr_status_t sts; - - if ((sts = ap_pcfg_openfile(&f, r->pool, grpfile)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, sts, r, - "Digest: Could not open group file: %s", grpfile); - return NULL; - } - - if (apr_pool_create(&sp, r->pool) != APR_SUCCESS) - return NULL; - - while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) { - if ((l[0] == '#') || (!l[0])) - continue; - ll = l; - apr_pool_clear(sp); - - group_name = ap_getword(sp, &ll, ':'); - - while (ll[0]) { - w = ap_getword_conf(sp, &ll); - if (!strcmp(w, user)) { - apr_table_setn(grps, apr_pstrdup(r->pool, group_name), "in"); - break; - } - } - } - - ap_cfg_closefile(f); - apr_pool_destroy(sp); - return grps; -} - - -static int digest_check_auth(request_rec *r) -{ - const digest_config_rec *conf = - (digest_config_rec *) ap_get_module_config(r->per_dir_config, - &auth_digest_module); - const char *user = r->user; - int m = r->method_number; - int method_restricted = 0; - register int x; - const char *t, *w; - apr_table_t *grpstatus; - const apr_array_header_t *reqs_arr; - require_line *reqs; - - if (!(t = ap_auth_type(r)) || strcasecmp(t, "Digest")) - return DECLINED; - - reqs_arr = ap_requires(r); - /* If there is no "requires" directive, then any user will do. - */ - if (!reqs_arr) - return OK; - reqs = (require_line *) reqs_arr->elts; - - if (conf->grpfile) - grpstatus = groups_for_user(r, user, conf->grpfile); - else - grpstatus = NULL; - - for (x = 0; x < reqs_arr->nelts; x++) { - - if (!(reqs[x].method_mask & (1 << m))) - continue; - - method_restricted = 1; - - t = reqs[x].requirement; - w = ap_getword_white(r->pool, &t); - if (!strcasecmp(w, "valid-user")) - return OK; - else if (!strcasecmp(w, "user")) { - while (t[0]) { - w = ap_getword_conf(r->pool, &t); - if (!strcmp(user, w)) - return OK; - } - } - else if (!strcasecmp(w, "group")) { - if (!grpstatus) - return DECLINED; - - while (t[0]) { - w = ap_getword_conf(r->pool, &t); - if (apr_table_get(grpstatus, w)) - return OK; - } - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: access to %s failed, reason: unknown require " - "directive \"%s\"", r->uri, reqs[x].requirement); - return DECLINED; - } - } - - if (!method_restricted) - return OK; - - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: access to %s failed, reason: user %s not allowed access", - r->uri, user); - - note_digest_auth_failure(r, conf, - (digest_header_rec *) ap_get_module_config(r->request_config, - &auth_digest_module), - 0); - return HTTP_UNAUTHORIZED; -} - - -/* - * Authorization-Info header code - */ - -#ifdef SEND_DIGEST -static const char *hdr(const apr_table_t *tbl, const char *name) -{ - const char *val = apr_table_get(tbl, name); - if (val) - return val; - else - return ""; -} -#endif - -static int add_auth_info(request_rec *r) -{ - const digest_config_rec *conf = - (digest_config_rec *) ap_get_module_config(r->per_dir_config, - &auth_digest_module); - digest_header_rec *resp = - (digest_header_rec *) ap_get_module_config(r->request_config, - &auth_digest_module); - const char *ai = NULL, *digest = NULL, *nextnonce = ""; - - if (resp == NULL || !resp->needed_auth || conf == NULL) - return OK; - - - /* rfc-2069 digest - */ - if (resp->message_qop == NULL) { - /* old client, so calc rfc-2069 digest */ - -#ifdef SEND_DIGEST - /* most of this totally bogus because the handlers don't set the - * headers until the final handler phase (I wonder why this phase - * is called fixup when there's almost nothing you can fix up...) - * - * Because it's basically impossible to get this right (e.g. the - * Content-length is never set yet when we get here, and we can't - * calc the entity hash) it's best to just leave this #def'd out. - */ - char date[APR_RFC822_DATE_LEN]; - apr_rfc822_date(date, r->request_time); - char *entity_info = - ap_md5(r->pool, - (unsigned char *) apr_pstrcat(r->pool, resp->raw_request_uri, - ":", - r->content_type ? r->content_type : ap_default_type(r), ":", - hdr(r->headers_out, "Content-Length"), ":", - r->content_encoding ? r->content_encoding : "", ":", - hdr(r->headers_out, "Last-Modified"), ":", - r->no_cache && !apr_table_get(r->headers_out, "Expires") ? - date : - hdr(r->headers_out, "Expires"), - NULL)); - digest = - ap_md5(r->pool, - (unsigned char *)apr_pstrcat(r->pool, conf->ha1, ":", - resp->nonce, ":", - r->method, ":", - date, ":", - entity_info, ":", - ap_md5(r->pool, (unsigned char *) ""), /* H(entity) - TBD */ - NULL)); -#endif - } - - - /* setup nextnonce - */ - if (conf->nonce_lifetime > 0) { - /* send nextnonce if current nonce will expire in less than 30 secs */ - if ((r->request_time - resp->nonce_time) > (conf->nonce_lifetime-NEXTNONCE_DELTA)) { - nextnonce = apr_pstrcat(r->pool, ", nextnonce=\"", - gen_nonce(r->pool, r->request_time, - resp->opaque, r->server, conf), - "\"", NULL); - if (resp->client) - resp->client->nonce_count = 0; - } - } - else if (conf->nonce_lifetime == 0 && resp->client) { - const char *nonce = gen_nonce(r->pool, 0, resp->opaque, r->server, - conf); - nextnonce = apr_pstrcat(r->pool, ", nextnonce=\"", nonce, "\"", NULL); - memcpy(resp->client->last_nonce, nonce, NONCE_LEN+1); - } - /* else nonce never expires, hence no nextnonce */ - - - /* do rfc-2069 digest - */ - if (conf->qop_list[0] && !strcasecmp(conf->qop_list[0], "none") - && resp->message_qop == NULL) { - /* use only RFC-2069 format */ - if (digest) - ai = apr_pstrcat(r->pool, "digest=\"", digest, "\"", nextnonce,NULL); - else - ai = nextnonce; - } - else { - const char *resp_dig, *ha1, *a2, *ha2; - - /* calculate rspauth attribute - */ - if (resp->algorithm && !strcasecmp(resp->algorithm, "MD5-sess")) { - ha1 = get_session_HA1(r, resp, conf, 0); - if (!ha1) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: internal error: couldn't find session " - "info for user %s", resp->username); - return !OK; - } - } - else - ha1 = conf->ha1; - - if (resp->message_qop && !strcasecmp(resp->message_qop, "auth-int")) - a2 = apr_pstrcat(r->pool, ":", resp->uri, ":", - ap_md5(r->pool, (const unsigned char *) ""), NULL); /* TBD */ - else - a2 = apr_pstrcat(r->pool, ":", resp->uri, NULL); - ha2 = ap_md5(r->pool, (const unsigned char *)a2); - - resp_dig = ap_md5(r->pool, - (unsigned char *)apr_pstrcat(r->pool, ha1, ":", - resp->nonce, ":", - resp->nonce_count, ":", - resp->cnonce, ":", - resp->message_qop ? - resp->message_qop : "", - ":", ha2, NULL)); - - /* assemble Authentication-Info header - */ - ai = apr_pstrcat(r->pool, - "rspauth=\"", resp_dig, "\"", - nextnonce, - resp->cnonce ? ", cnonce=\"" : "", - resp->cnonce ? ap_escape_quotes(r->pool, resp->cnonce) : - "", - resp->cnonce ? "\"" : "", - resp->nonce_count ? ", nc=" : "", - resp->nonce_count ? resp->nonce_count : "", - resp->message_qop ? ", qop=" : "", - resp->message_qop ? resp->message_qop : "", - digest ? "digest=\"" : "", - digest ? digest : "", - digest ? "\"" : "", - NULL); - } - - if (ai && ai[0]) - apr_table_mergen(r->headers_out, - (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authentication-Info" - : "Authentication-Info", - ai); - return OK; -} - - -static void register_hooks(apr_pool_t *p) -{ - static const char * const cfgPost[]={ "http_core.c", NULL }; - static const char * const parsePre[]={ "mod_proxy.c", NULL }; - - ap_hook_post_config(initialize_module, NULL, cfgPost, APR_HOOK_MIDDLE); - ap_hook_child_init(initialize_child, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_read_request(parse_hdr_and_update_nc, parsePre, NULL, APR_HOOK_MIDDLE); - ap_hook_check_user_id(authenticate_digest_user, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_auth_checker(digest_check_auth, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_fixups(add_auth_info, NULL, NULL, APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA auth_digest_module = -{ - STANDARD20_MODULE_STUFF, - create_digest_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - digest_cmds, /* command table */ - register_hooks /* register hooks */ -}; - diff --git a/modules/aaa/mod_auth_digest.dsp b/modules/aaa/mod_auth_digest.dsp deleted file mode 100644 index 84d6760577..0000000000 --- a/modules/aaa/mod_auth_digest.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_auth_digest" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_auth_digest - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_auth_digest.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_auth_digest.mak" CFG="mod_auth_digest - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_auth_digest - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_auth_digest - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_auth_digest - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_auth_digest" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_auth_digest.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_auth_digest -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_auth_digest.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_auth_digest - -!ELSEIF "$(CFG)" == "mod_auth_digest - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_auth_digest" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_auth_digest.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_auth_digest -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_auth_digest.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_auth_digest - -!ENDIF - -# Begin Target - -# Name "mod_auth_digest - Win32 Release" -# Name "mod_auth_digest - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_auth_digest.c -# End Source File -# End Target -# End Project diff --git a/modules/aaa/mod_auth_digest.mak b/modules/aaa/mod_auth_digest.mak deleted file mode 100644 index 871e162be7..0000000000 --- a/modules/aaa/mod_auth_digest.mak +++ /dev/null @@ -1,370 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_auth_digest.dsp -!IF "$(CFG)" == "" -CFG=mod_auth_digest - Win32 Debug -!MESSAGE No configuration specified. Defaulting to mod_auth_digest - Win32\ - Debug. -!ENDIF - -!IF "$(CFG)" != "mod_auth_digest - Win32 Release" && "$(CFG)" !=\ - "mod_auth_digest - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_auth_digest.mak" CFG="mod_auth_digest - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_auth_digest - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_auth_digest - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_auth_digest - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_auth_digest.so" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release"\ - "libapr - Win32 Release" "$(OUTDIR)\mod_auth_digest.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN"\ - "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_auth_digest.idb" - -@erase "$(INTDIR)\mod_auth_digest.obj" - -@erase "$(OUTDIR)\mod_auth_digest.exp" - -@erase "$(OUTDIR)\mod_auth_digest.lib" - -@erase "$(OUTDIR)\mod_auth_digest.map" - -@erase "$(OUTDIR)\mod_auth_digest.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_auth_digest" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_auth_digest.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_auth_digest.pdb" /map:"$(INTDIR)\mod_auth_digest.map"\ - /machine:I386 /out:"$(OUTDIR)\mod_auth_digest.so"\ - /implib:"$(OUTDIR)\mod_auth_digest.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_auth_digest -LINK32_OBJS= \ - "$(INTDIR)\mod_auth_digest.obj" \ - "..\..\Release\libhttpd.lib" \ - "..\..\srclib\apr-util\Release\libaprutil.lib" \ - "..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_auth_digest.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_auth_digest - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_auth_digest.so" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug"\ - "libapr - Win32 Debug" "$(OUTDIR)\mod_auth_digest.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN"\ - "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_auth_digest.idb" - -@erase "$(INTDIR)\mod_auth_digest.obj" - -@erase "$(OUTDIR)\mod_auth_digest.exp" - -@erase "$(OUTDIR)\mod_auth_digest.lib" - -@erase "$(OUTDIR)\mod_auth_digest.map" - -@erase "$(OUTDIR)\mod_auth_digest.pdb" - -@erase "$(OUTDIR)\mod_auth_digest.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_auth_digest" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_auth_digest.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_auth_digest.pdb" /map:"$(INTDIR)\mod_auth_digest.map"\ - /debug /machine:I386 /out:"$(OUTDIR)\mod_auth_digest.so"\ - /implib:"$(OUTDIR)\mod_auth_digest.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_auth_digest -LINK32_OBJS= \ - "$(INTDIR)\mod_auth_digest.obj" \ - "..\..\Debug\libhttpd.lib" \ - "..\..\srclib\apr-util\Debug\libaprutil.lib" \ - "..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_auth_digest.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_auth_digest - Win32 Release" || "$(CFG)" ==\ - "mod_auth_digest - Win32 Debug" - -!IF "$(CFG)" == "mod_auth_digest - Win32 Release" - -"libapr - Win32 Release" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Release" - cd "..\..\modules\aaa" - -"libapr - Win32 ReleaseCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\aaa" - -!ELSEIF "$(CFG)" == "mod_auth_digest - Win32 Debug" - -"libapr - Win32 Debug" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Debug" - cd "..\..\modules\aaa" - -"libapr - Win32 DebugCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\aaa" - -!ENDIF - -!IF "$(CFG)" == "mod_auth_digest - Win32 Release" - -"libaprutil - Win32 Release" : - cd "..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"\ - - cd "..\..\modules\aaa" - -"libaprutil - Win32 ReleaseCLEAN" : - cd "..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libaprutil.mak"\ - CFG="libaprutil - Win32 Release" RECURSE=1 - cd "..\..\modules\aaa" - -!ELSEIF "$(CFG)" == "mod_auth_digest - Win32 Debug" - -"libaprutil - Win32 Debug" : - cd "..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" - cd "..\..\modules\aaa" - -"libaprutil - Win32 DebugCLEAN" : - cd "..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libaprutil.mak"\ - CFG="libaprutil - Win32 Debug" RECURSE=1 - cd "..\..\modules\aaa" - -!ENDIF - -!IF "$(CFG)" == "mod_auth_digest - Win32 Release" - -"libhttpd - Win32 Release" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Release" - cd ".\modules\aaa" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Release"\ - RECURSE=1 - cd ".\modules\aaa" - -!ELSEIF "$(CFG)" == "mod_auth_digest - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Debug" - cd ".\modules\aaa" - -"libhttpd - Win32 DebugCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\aaa" - -!ENDIF - -SOURCE=.\mod_auth_digest.c -DEP_CPP_MOD_A=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\http_request.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_md5.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\apr_base64.h"\ - "..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\srclib\apr-util\include\apr_sha1.h"\ - "..\..\srclib\apr-util\include\apu.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_dso.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_lock.h"\ - "..\..\srclib\apr\include\apr_md5.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_shmem.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\include\apr_user.h"\ - "..\..\srclib\apr\include\apr_want.h"\ - "..\..\srclib\apr\include\apr_xlate.h"\ - -NODEP_CPP_MOD_A=\ - "..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\mod_auth_digest.obj" : $(SOURCE) $(DEP_CPP_MOD_A) "$(INTDIR)" - - - -!ENDIF - diff --git a/modules/arch/win32/mod_isapi.c b/modules/arch/win32/mod_isapi.c deleted file mode 100644 index 5753afbeaf..0000000000 --- a/modules/arch/win32/mod_isapi.c +++ /dev/null @@ -1,1299 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_isapi.c - Internet Server Application (ISA) module for Apache - * by Alexei Kosut <akosut@apache.org> - * - * This module implements Microsoft's ISAPI, allowing Apache (when running - * under Windows) to load Internet Server Applications (ISAPI extensions). - * It implements all of the ISAPI 2.0 specification, except for the - * "Microsoft-only" extensions dealing with asynchronous I/O. All ISAPI - * extensions that use only synchronous I/O and are compatible with the - * ISAPI 2.0 specification should work (most ISAPI 1.0 extensions should - * function as well). - * - * To load, simply place the ISA in a location in the document tree. - * Then add an "AddHandler isapi-isa dll" into your config file. - * You should now be able to load ISAPI DLLs just be reffering to their - * URLs. Make sure the ExecCGI option is active in the directory - * the ISA is in. - */ - -#include "apr_strings.h" -#include "apr_portable.h" -#include "apr_buckets.h" -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_request.h" -#include "http_log.h" -#include "util_script.h" -#include "mod_core.h" - -/* We use the exact same header file as the original */ -#include <HttpExt.h> - -#if !defined(HSE_REQ_MAP_URL_TO_PATH_EX) \ - || !defined(HSE_REQ_SEND_RESPONSE_HEADER_EX) -#pragma message("WARNING: This build of Apache is missing the recent changes") -#pragma message("in the Microsoft Win32 Platform SDK; some mod_isapi features") -#pragma message("will be disabled. To obtain the latest Platform SDK files,") -#pragma message("please refer to:") -#pragma message("http://msdn.microsoft.com/downloads/sdks/platform/platform.asp") -#endif - -/* TODO: Unknown errors that must be researched for correct codes */ - -#define TODO_ERROR 1 - -/* Seems IIS does not enforce the requirement for \r\n termination on HSE_REQ_SEND_RESPONSE_HEADER, - define this to conform */ -#define RELAX_HEADER_RULE - -module isapi_module; - -/* Declare the ISAPI functions */ - -BOOL WINAPI GetServerVariable (HCONN hConn, LPSTR lpszVariableName, - LPVOID lpvBuffer, LPDWORD lpdwSizeofBuffer); -BOOL WINAPI WriteClient (HCONN ConnID, LPVOID Buffer, LPDWORD lpwdwBytes, - DWORD dwReserved); -BOOL WINAPI ReadClient (HCONN ConnID, LPVOID lpvBuffer, LPDWORD lpdwSize); -BOOL WINAPI ServerSupportFunction (HCONN hConn, DWORD dwHSERequest, - LPVOID lpvBuffer, LPDWORD lpdwSize, - LPDWORD lpdwDataType); - -/* - The optimiser blows it totally here. What happens is that autos are addressed relative to the - stack pointer, which, of course, moves around. The optimiser seems to lose track of it somewhere - between setting HttpExtensionProc's address and calling through it. We work around the problem by - forcing it to use frame pointers. - - The revisions below may eliminate this artifact. -*/ -#pragma optimize("y",off) - -/* Our isapi server config structure */ - -typedef struct { - HANDLE lock; - apr_array_header_t *loaded; - DWORD ReadAheadBuffer; - int LogNotSupported; - int AppendLogToErrors; - int AppendLogToQuery; -} isapi_server_conf; - -/* Our loaded isapi module description structure */ - -typedef struct { - const char *filename; - apr_dso_handle_t *handle; - HSE_VERSION_INFO *pVer; - PFN_GETEXTENSIONVERSION GetExtensionVersion; - PFN_HTTPEXTENSIONPROC HttpExtensionProc; - PFN_TERMINATEEXTENSION TerminateExtension; - int refcount; - DWORD timeout; - BOOL fakeasync; - DWORD reportversion; -} isapi_loaded; - -/* Our "Connection ID" structure */ - -typedef struct { - LPEXTENSION_CONTROL_BLOCK ecb; - isapi_server_conf *sconf; - isapi_loaded *isa; - request_rec *r; - PFN_HSE_IO_COMPLETION completion; - PVOID completion_arg; - HANDLE complete; -} isapi_cid; - -static BOOL isapi_unload(isapi_loaded* isa, int force); - -static apr_status_t cleanup_isapi_server_config(void *sconfv) -{ - isapi_server_conf *sconf = sconfv; - size_t n; - isapi_loaded **isa; - - n = sconf->loaded->nelts; - isa = (isapi_loaded **)sconf->loaded->elts; - while(n--) { - if ((*isa)->handle) - isapi_unload(*isa, TRUE); - ++isa; - } - CloseHandle(sconf->lock); - return APR_SUCCESS; -} - -static void *create_isapi_server_config(apr_pool_t *p, server_rec *s) -{ - isapi_server_conf *sconf = apr_palloc(p, sizeof(isapi_server_conf)); - sconf->loaded = apr_array_make(p, 20, sizeof(isapi_loaded*)); - sconf->lock = CreateMutex(NULL, FALSE, NULL); - - sconf->ReadAheadBuffer = 49152; - sconf->LogNotSupported = -1; - sconf->AppendLogToErrors = 0; - sconf->AppendLogToQuery = 0; - - apr_pool_cleanup_register(p, sconf, cleanup_isapi_server_config, - apr_pool_cleanup_null); - - return sconf; -} - -static int compare_loaded(const void *av, const void *bv) -{ - const isapi_loaded **a = av; - const isapi_loaded **b = bv; - - return strcmp((*a)->filename, (*b)->filename); -} - -static void isapi_post_config(apr_pool_t *p, apr_pool_t *plog, - apr_pool_t *ptemp, server_rec *s) -{ - isapi_server_conf *sconf = ap_get_module_config(s->module_config, - &isapi_module); - isapi_loaded **elts = (isapi_loaded **)sconf->loaded->elts; - int nelts = sconf->loaded->nelts; - - /* sort the elements of the main_server, by filename */ - qsort(elts, nelts, sizeof(isapi_loaded*), compare_loaded); - - /* and make the virtualhosts share the same thing */ - for (s = s->next; s; s = s->next) { - ap_set_module_config(s->module_config, &isapi_module, sconf); - } -} - -static apr_status_t isapi_load(apr_pool_t *p, isapi_server_conf *sconf, - request_rec *r, const char *fpath, - isapi_loaded** isa) -{ - isapi_loaded **found = (isapi_loaded **)sconf->loaded->elts; - apr_status_t rv; - int n; - - for (n = 0; n < sconf->loaded->nelts; ++n) { - if (strcasecmp(fpath, (*found)->filename) == 0) { - break; - } - ++found; - } - - if (n < sconf->loaded->nelts) - { - *isa = *found; - if ((*isa)->handle) - { - ++(*isa)->refcount; - return APR_SUCCESS; - } - /* Otherwise we fall through and have to reload the resource - * into this existing mod_isapi cache bucket. - */ - } - else - { - *isa = apr_pcalloc(p, sizeof(isapi_module)); - (*isa)->filename = fpath; - (*isa)->pVer = apr_pcalloc(p, sizeof(HSE_VERSION_INFO)); - - /* TODO: These need to become overrideable, so that we - * assure a given isapi can be fooled into behaving well. - */ - (*isa)->timeout = INFINITE; /* microsecs */ - (*isa)->fakeasync = TRUE; - (*isa)->reportversion = MAKELONG(0, 5); /* Revision 5.0 */ - } - - rv = apr_dso_load(&(*isa)->handle, fpath, p); - if (rv) - { - ap_log_rerror(APLOG_MARK, APLOG_ALERT, rv, r, - "ISAPI %s failed to load", fpath); - (*isa)->handle = NULL; - return rv; - } - - rv = apr_dso_sym((void**)&(*isa)->GetExtensionVersion, (*isa)->handle, - "GetExtensionVersion"); - if (rv) - { - ap_log_rerror(APLOG_MARK, APLOG_ALERT, rv, r, - "ISAPI %s is missing GetExtensionVersion()", - fpath); - apr_dso_unload((*isa)->handle); - (*isa)->handle = NULL; - return rv; - } - - rv = apr_dso_sym((void**)&(*isa)->HttpExtensionProc, (*isa)->handle, - "HttpExtensionProc"); - if (rv) - { - ap_log_rerror(APLOG_MARK, APLOG_ALERT, rv, r, - "ISAPI %s is missing HttpExtensionProc()", - fpath); - apr_dso_unload((*isa)->handle); - (*isa)->handle = NULL; - return rv; - } - - /* TerminateExtension() is an optional interface */ - rv = apr_dso_sym((void**)&(*isa)->TerminateExtension, (*isa)->handle, - "TerminateExtension"); - SetLastError(0); - - /* Run GetExtensionVersion() */ - if (!((*isa)->GetExtensionVersion)((*isa)->pVer)) { - apr_status_t rv = apr_get_os_error(); - ap_log_rerror(APLOG_MARK, APLOG_ALERT, rv, r, - "ISAPI %s call GetExtensionVersion() failed", - fpath); - apr_dso_unload((*isa)->handle); - (*isa)->handle = NULL; - return rv; - } - - ++(*isa)->refcount; - - return APR_SUCCESS; -} - -static int isapi_unload(isapi_loaded* isa, int force) -{ - /* All done with the DLL... get rid of it... - * - * If optionally cached, pass HSE_TERM_ADVISORY_UNLOAD, - * and if it returns TRUE, unload, otherwise, cache it. - */ - if ((--isa->refcount > 0) && !force) - return FALSE; - if (isa->TerminateExtension) { - if (force) - (*isa->TerminateExtension)(HSE_TERM_MUST_UNLOAD); - else if (!(*isa->TerminateExtension)(HSE_TERM_ADVISORY_UNLOAD)) - return FALSE; - } - apr_dso_unload(isa->handle); - isa->handle = NULL; - return TRUE; -} - -apr_status_t isapi_handler (request_rec *r) -{ - isapi_server_conf * sconf; - apr_table_t *e; - apr_status_t rv; - isapi_loaded *isa; - isapi_cid *cid; - DWORD read; - int res; - - if(strcmp(r->handler, "isapi-isa")) - return DECLINED; - - sconf = ap_get_module_config(r->server->module_config, &isapi_module); - e = r->subprocess_env; - - /* Use similar restrictions as CGIs - * - * If this fails, it's pointless to load the isapi dll. - */ - if (!(ap_allow_options(r) & OPT_EXECCGI)) - return HTTP_FORBIDDEN; - - if (r->finfo.filetype == APR_NOFILE) - return HTTP_NOT_FOUND; - - if (r->finfo.filetype != APR_REG) - return HTTP_FORBIDDEN; - - /* Load the isapi extention without caching (sconf == NULL) - * but note that we will recover an existing cached module. - */ - if (isapi_load(r->pool, sconf, r, r->filename, &isa) != APR_SUCCESS) - return HTTP_INTERNAL_SERVER_ERROR; - - /* Set up variables */ - ap_add_common_vars(r); - ap_add_cgi_vars(r); - apr_table_setn(r->subprocess_env, "UNMAPPED_REMOTE_USER", "REMOTE_USER"); - apr_table_setn(r->subprocess_env, "SERVER_PORT_SECURE", "0"); - apr_table_setn(r->subprocess_env, "URL", r->uri); - - /* Set up connection structure and ecb */ - cid = apr_pcalloc(r->pool, sizeof(isapi_cid)); - cid->sconf = ap_get_module_config(r->server->module_config, &isapi_module); - - cid->ecb = apr_pcalloc(r->pool, sizeof(struct _EXTENSION_CONTROL_BLOCK)); - cid->ecb->ConnID = (HCONN)cid; - cid->isa = isa; - cid->r = r; - cid->r->status = 0; - cid->complete = NULL; - cid->completion = NULL; - - cid->ecb->cbSize = sizeof(EXTENSION_CONTROL_BLOCK); - cid->ecb->dwVersion = isa->reportversion; - cid->ecb->dwHttpStatusCode = 0; - strcpy(cid->ecb->lpszLogData, ""); - // TODO: are copies really needed here? - cid->ecb->lpszMethod = apr_pstrdup(r->pool, (char*) r->method); - cid->ecb->lpszQueryString = apr_pstrdup(r->pool, - (char*) apr_table_get(e, "QUERY_STRING")); - cid->ecb->lpszPathInfo = apr_pstrdup(r->pool, - (char*) apr_table_get(e, "PATH_INFO")); - cid->ecb->lpszPathTranslated = apr_pstrdup(r->pool, - (char*) apr_table_get(e, "PATH_TRANSLATED")); - cid->ecb->lpszContentType = apr_pstrdup(r->pool, - (char*) apr_table_get(e, "CONTENT_TYPE")); - /* Set up the callbacks */ - cid->ecb->GetServerVariable = GetServerVariable; - cid->ecb->WriteClient = WriteClient; - cid->ecb->ReadClient = ReadClient; - cid->ecb->ServerSupportFunction = ServerSupportFunction; - - - /* Set up client input */ - rv = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR); - if (rv) { - isapi_unload(isa, FALSE); - return HTTP_INTERNAL_SERVER_ERROR; /* XXX: The wrong error */ - } - - if (ap_should_client_block(r)) { - /* Time to start reading the appropriate amount of data, - * and allow the administrator to tweak the number - * TODO: add the httpd.conf option for ReadAheadBuffer. - */ - if (r->remaining) { - cid->ecb->cbTotalBytes = r->remaining; - if (cid->ecb->cbTotalBytes > cid->sconf->ReadAheadBuffer) - cid->ecb->cbAvailable = cid->sconf->ReadAheadBuffer; - else - cid->ecb->cbAvailable = cid->ecb->cbTotalBytes; - } - else - { - cid->ecb->cbTotalBytes = 0xffffffff; - cid->ecb->cbAvailable = cid->sconf->ReadAheadBuffer; - } - - cid->ecb->lpbData = apr_pcalloc(r->pool, cid->ecb->cbAvailable + 1); - - read = 0; - while (read < cid->ecb->cbAvailable && - ((res = ap_get_client_block(r, cid->ecb->lpbData + read, - cid->ecb->cbAvailable - read)) > 0)) { - read += res; - } - - if (res < 0) { - isapi_unload(isa, FALSE); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* Although its not to spec, IIS seems to null-terminate - * its lpdData string. So we will too. - */ - if (res == 0) - cid->ecb->cbAvailable = cid->ecb->cbTotalBytes = read; - else - cid->ecb->cbAvailable = read; - cid->ecb->lpbData[read] = '\0'; - } - else { - cid->ecb->cbTotalBytes = 0; - cid->ecb->cbAvailable = 0; - cid->ecb->lpbData = NULL; - } - - /* All right... try and run the sucker */ - rv = (*isa->HttpExtensionProc)(cid->ecb); - - /* Check for a log message - and log it */ - if (cid->ecb->lpszLogData && *cid->ecb->lpszLogData) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r, - "ISAPI %s: %s", r->filename, cid->ecb->lpszLogData); - - switch(rv) { - case HSE_STATUS_SUCCESS: - case HSE_STATUS_SUCCESS_AND_KEEP_CONN: - /* Ignore the keepalive stuff; Apache handles it just fine without - * the ISA's "advice". - * Per Microsoft: "In IIS versions 4.0 and later, the return - * values HSE_STATUS_SUCCESS and HSE_STATUS_SUCCESS_AND_KEEP_CONN - * are functionally identical: Keep-Alive connections are - * maintained, if supported by the client." - * ... so we were pat all this time - */ - break; - - case HSE_STATUS_PENDING: - /* emulating async behavior... - * - * Create a cid->completed event and wait on it for some timeout - * so that the app thinks is it running async. - * - * All async ServerSupportFunction calls will be handled through - * the registered IO_COMPLETION hook. - */ - - if (!isa->fakeasync) { - if (cid->sconf->LogNotSupported) - { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r, - "ISAPI %s asynch I/O request refused", - r->filename); - cid->r->status = HTTP_INTERNAL_SERVER_ERROR; - } - } - else { - cid->complete = CreateEvent(NULL, FALSE, FALSE, NULL); - if (WaitForSingleObject(cid->complete, isa->timeout) - == WAIT_TIMEOUT) { - /* TODO: Now what... if this hung, then do we kill our own - * thread to force it's death? For now leave timeout = -1 - */ - } - } - break; - - case HSE_STATUS_ERROR: - /* end response if we have yet to do so. - */ - cid->r->status = HTTP_INTERNAL_SERVER_ERROR; - break; - - default: - /* TODO: log unrecognized retval for debugging - */ - cid->r->status = HTTP_INTERNAL_SERVER_ERROR; - break; - } - - /* Set the status (for logging) */ - if (cid->ecb->dwHttpStatusCode) { - cid->r->status = cid->ecb->dwHttpStatusCode; - } - - /* All done with the DLL... get rid of it... */ - isapi_unload(isa, FALSE); - - return OK; /* NOT r->status, even if it has changed. */ -} -#pragma optimize("",on) - -BOOL WINAPI GetServerVariable (HCONN hConn, LPSTR lpszVariableName, - LPVOID lpvBuffer, LPDWORD lpdwSizeofBuffer) -{ - request_rec *r = ((isapi_cid *)hConn)->r; - const char *result; - DWORD len; - - if (!strcmp(lpszVariableName, "ALL_HTTP")) - { - /* lf delimited, colon split, comma seperated and - * null terminated list of HTTP_ vars - */ - char **env = (char**) apr_table_elts(r->subprocess_env)->elts; - int nelts = 2 * apr_table_elts(r->subprocess_env)->nelts; - int i; - - for (len = 0, i = 0; i < nelts; i += 2) - if (!strncmp(env[i], "HTTP_", 5)) - len += strlen(env[i]) + strlen(env[i + 1]) + 2; - - if (*lpdwSizeofBuffer < len + 1) { - *lpdwSizeofBuffer = len + 1; - SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; - } - - for (i = 0; i < nelts; i += 2) - if (!strncmp(env[i], "HTTP_", 5)) { - strcpy(lpvBuffer, env[i]); - ((char*)lpvBuffer) += strlen(env[i]); - *(((char*)lpvBuffer)++) = ':'; - strcpy(lpvBuffer, env[i + 1]); - ((char*)lpvBuffer) += strlen(env[i + 1]); - *(((char*)lpvBuffer)++) = '\n'; - } - - *(((char*)lpvBuffer)++) = '\0'; - *lpdwSizeofBuffer = len; - return TRUE; - } - - if (!strcmp(lpszVariableName, "ALL_RAW")) - { - /* lf delimited, colon split, comma seperated and - * null terminated list of the raw request header - */ - char **raw = (char**) apr_table_elts(r->headers_in)->elts; - int nelts = 2 * apr_table_elts(r->headers_in)->nelts; - int i; - - for (len = 0, i = 0; i < nelts; i += 2) - len += strlen(raw[i]) + strlen(raw[i + 1]) + 2; - - if (*lpdwSizeofBuffer < len + 1) { - *lpdwSizeofBuffer = len + 1; - SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; - } - - for (i = 0; i < nelts; i += 2) { - strcpy(lpvBuffer, raw[i]); - ((char*)lpvBuffer) += strlen(raw[i]); - *(((char*)lpvBuffer)++) = ':'; - *(((char*)lpvBuffer)++) = ' '; - strcpy(lpvBuffer, raw[i + 1]); - ((char*)lpvBuffer) += strlen(raw[i + 1]); - *(((char*)lpvBuffer)++) = '\n'; - i += 2; - } - *(((char*)lpvBuffer)++) = '\0'; - *lpdwSizeofBuffer = len; - return TRUE; - } - - /* Not a special case */ - result = apr_table_get(r->subprocess_env, lpszVariableName); - - if (result) { - len = strlen(result); - if (*lpdwSizeofBuffer < len + 1) { - *lpdwSizeofBuffer = len + 1; - SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; - } - strcpy(lpvBuffer, result); - *lpdwSizeofBuffer = len; - return TRUE; - } - - /* Not Found */ - SetLastError(ERROR_INVALID_INDEX); - return FALSE; -} - -BOOL WINAPI WriteClient (HCONN ConnID, LPVOID Buffer, LPDWORD lpwdwBytes, - DWORD dwReserved) -{ - request_rec *r = ((isapi_cid *)ConnID)->r; - apr_bucket_brigade *bb; - apr_bucket *b; - - if (dwReserved == HSE_IO_SYNC) - ; /* XXX: Fake it */ - - bb = apr_brigade_create(r->pool); - b = apr_bucket_transient_create(Buffer, *lpwdwBytes); - APR_BRIGADE_INSERT_TAIL(bb, b); - b = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - ap_pass_brigade(r->output_filters, bb); - - return TRUE; -} - -BOOL WINAPI ReadClient (HCONN ConnID, LPVOID lpvBuffer, LPDWORD lpdwSize) -{ - request_rec *r = ((isapi_cid *)ConnID)->r; - DWORD read = 0; - int res; - - if (r->remaining < (long) *lpdwSize) - *lpdwSize = r->remaining; - - while (read < *lpdwSize && - ((res = ap_get_client_block(r, (char*)lpvBuffer + read, - *lpdwSize - read)) > 0)) { - if (res < 0) { - *lpdwSize = 0; - if (!apr_get_os_error()) - SetLastError(TODO_ERROR); /* XXX: Find the right error code */ - return FALSE; - } - - read += res; - } - - *lpdwSize = read; - return TRUE; -} - -static apr_off_t SendResponseHeaderEx(isapi_cid *cid, const char *stat, - const char *head, apr_size_t statlen, - apr_size_t headlen) -{ - int termarg; - char *termch; - - if (!stat || statlen == 0 || !*stat) { - stat = "Status: 200 OK"; - } - else { - char *newstat; - newstat = apr_palloc(cid->r->pool, statlen + 9); - strcpy(newstat, "Status: "); - apr_cpystrn(newstat + 8, stat, statlen + 1); - stat = newstat; - } - - if (!head || headlen == 0 || !*head) { - head = "\r\n"; - } - else - { - if (head[headlen]) { - /* Whoops... not NULL terminated */ - head = apr_pstrndup(cid->r->pool, head, headlen); - } - } - - /* Parse them out, or die trying */ - cid->r->status= ap_scan_script_header_err_strs(cid->r, NULL, &termch, - &termarg, stat, head, NULL); - cid->ecb->dwHttpStatusCode = cid->r->status; - if (cid->r->status == HTTP_INTERNAL_SERVER_ERROR) - return -1; - - /* Headers will actually go when they are good and ready */ - - /* If all went well, tell the caller we consumed the headers complete */ - if (!termch) - return(headlen); - - /* Any data left is sent directly by the caller, all we - * give back is the size of the headers we consumed - */ - if (termch && (termarg == 1) && headlen > (termch - head)) { - return termch - head; - } - return 0; -} - -/* XXX: Is there is still an O(n^2) attack possible here? Please detail. */ -BOOL WINAPI ServerSupportFunction(HCONN hConn, DWORD dwHSERequest, - LPVOID lpvBuffer, LPDWORD lpdwSize, - LPDWORD lpdwDataType) -{ - isapi_cid *cid = (isapi_cid *)hConn; - request_rec *r = cid->r; - request_rec *subreq; - - switch (dwHSERequest) { - case 1: /* HSE_REQ_SEND_URL_REDIRECT_RESP */ - /* Set the status to be returned when the HttpExtensionProc() - * is done. - * WARNING: Microsoft now advertises HSE_REQ_SEND_URL_REDIRECT_RESP - * and HSE_REQ_SEND_URL as equivalant per the Jan 2000 SDK. - * They most definately are not, even in their own samples. - */ - apr_table_set (r->headers_out, "Location", lpvBuffer); - cid->r->status = cid->ecb->dwHttpStatusCode - = HTTP_MOVED_TEMPORARILY; - return TRUE; - - case 2: /* HSE_REQ_SEND_URL */ - /* Soak up remaining input */ - if (r->remaining > 0) { - char argsbuffer[HUGE_STRING_LEN]; - while (ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN)); - } - - /* Reset the method to GET */ - r->method = apr_pstrdup(r->pool, "GET"); - r->method_number = M_GET; - - /* Don't let anyone think there's still data */ - apr_table_unset(r->headers_in, "Content-Length"); - - /* AV fault per PR3598 - redirected path is lost! */ - (char*)lpvBuffer = apr_pstrdup(r->pool, (char*)lpvBuffer); - ap_internal_redirect((char*)lpvBuffer, r); - return TRUE; - - case 3: /* HSE_REQ_SEND_RESPONSE_HEADER */ - { - /* Parse them out, or die trying */ - apr_size_t statlen = 0, headlen = 0; - int ate; - if (lpvBuffer) - statlen = strlen((char*) lpvBuffer); - if (lpdwDataType) - headlen = strlen((char*) lpdwDataType); - ate = SendResponseHeaderEx(cid, (char*) lpvBuffer, - (char*) lpdwDataType, - statlen, headlen); - if (ate < 0) { - SetLastError(TODO_ERROR); - return FALSE; - } - else if (ate < headlen) { - apr_bucket_brigade *bb; - apr_bucket *b; - bb = apr_brigade_create(cid->r->pool); - b = apr_bucket_transient_create((char*) lpdwDataType + ate, - headlen - ate); - APR_BRIGADE_INSERT_TAIL(bb, b); - b = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - ap_pass_brigade(cid->r->output_filters, bb); - } - return TRUE; - } - - case 4: /* HSE_REQ_DONE_WITH_SESSION */ - /* Signal to resume the thread completing this request - */ - if (cid->complete) - SetEvent(cid->complete); - return TRUE; - - case 1001: /* HSE_REQ_MAP_URL_TO_PATH */ - { - /* Map a URL to a filename */ - char *file = (char *)lpvBuffer; - DWORD len; - subreq = ap_sub_req_lookup_uri(apr_pstrndup(r->pool, file, *lpdwSize), - r, NULL); - - len = apr_cpystrn(file, subreq->filename, *lpdwSize) - file; - - - /* IIS puts a trailing slash on directories, Apache doesn't */ - if (subreq->finfo.filetype == APR_DIR) { - if (len < *lpdwSize - 1) { - file[len++] = '\\'; - file[len] = '\0'; - } - } - *lpdwSize = len; - return TRUE; - } - - case 1002: /* HSE_REQ_GET_SSPI_INFO */ - if (cid->sconf->LogNotSupported) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r, - "ISAPI ServerSupportFunction HSE_REQ_GET_SSPI_INFO " - "is not supported: %s", r->filename); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - - case 1003: /* HSE_APPEND_LOG_PARAMETER */ - /* Log lpvBuffer, of lpdwSize bytes, in the URI Query (cs-uri-query) field - */ - apr_table_set(r->notes, "isapi-parameter", (char*) lpvBuffer); - if (cid->sconf->AppendLogToQuery) { - if (r->args) - r->args = apr_pstrcat(r->pool, r->args, (char*) lpvBuffer, NULL); - else - r->args = apr_pstrdup(r->pool, (char*) lpvBuffer); - } - if (cid->sconf->AppendLogToErrors) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r, - "ISAPI %s: %s", cid->r->filename, - (char*) lpvBuffer); - return TRUE; - - case 1005: /* HSE_REQ_IO_COMPLETION */ - /* Emulates a completion port... Record callback address and - * user defined arg, we will call this after any async request - * (e.g. transmitfile) as if the request executed async. - * Per MS docs... HSE_REQ_IO_COMPLETION replaces any prior call - * to HSE_REQ_IO_COMPLETION, and lpvBuffer may be set to NULL. - */ - if (!cid->isa->fakeasync) { - if (cid->sconf->LogNotSupported) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r, - "ISAPI ServerSupportFunction HSE_REQ_IO_COMPLETION " - "is not supported: %s", r->filename); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - cid->completion = (PFN_HSE_IO_COMPLETION) lpvBuffer; - cid->completion_arg = (PVOID) lpdwDataType; - return TRUE; - - case 1006: /* HSE_REQ_TRANSMIT_FILE */ - { - HSE_TF_INFO *tf = (HSE_TF_INFO*)lpvBuffer; - apr_status_t rv; - apr_bucket_brigade *bb; - apr_bucket *b; - apr_file_t *fd; - - if (!cid->isa->fakeasync && (tf->dwFlags & HSE_IO_ASYNC)) { - if (cid->sconf->LogNotSupported) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r, - "ISAPI ServerSupportFunction HSE_REQ_TRANSMIT_FILE " - "as HSE_IO_ASYNC is not supported: %s", r->filename); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - if ((rv = apr_os_file_put(&fd, tf->hFile, r->pool)) != APR_SUCCESS) { - return FALSE; - } - - /* apr_dupfile_oshandle (&fd, tf->hFile, r->pool); */ - bb = apr_brigade_create(r->pool); - - if (tf->dwFlags & HSE_IO_SEND_HEADERS) - { - /* According to MS: if calling HSE_REQ_TRANSMIT_FILE with the - * HSE_IO_SEND_HEADERS flag, then you can't otherwise call any - * HSE_SEND_RESPONSE_HEADERS* fn, but if you don't use the flag, - * you must have done so. They document that the pHead headers - * option is valid only for HSE_IO_SEND_HEADERS - we are a bit - * more flexible and assume with the flag, pHead are the - * response headers, and without, pHead simply contains text - * (handled after this case). - */ - apr_off_t ate = SendResponseHeaderEx(cid, tf->pszStatusCode, - (char*)tf->pHead, - strlen(tf->pszStatusCode), - (apr_size_t)tf->HeadLength); - if (ate < 0) - { - apr_brigade_destroy(bb); - SetLastError(TODO_ERROR); - return FALSE; - } - if (ate < (apr_size_t)tf->HeadLength) - { - b = apr_bucket_transient_create((char*)tf->pHead + ate, - (apr_size_t)tf->HeadLength - ate); - APR_BRIGADE_INSERT_TAIL(bb, b); - } - } - else if (tf->pHead && tf->HeadLength) { - b = apr_bucket_transient_create((char*)tf->pHead, - (apr_size_t)tf->HeadLength); - APR_BRIGADE_INSERT_TAIL(bb, b); - } - - b = apr_bucket_file_create(fd, (apr_off_t)tf->Offset, - (apr_size_t)tf->BytesToWrite); - APR_BRIGADE_INSERT_TAIL(bb, b); - - if (tf->pTail && (apr_size_t)tf->TailLength) { - b = apr_bucket_transient_create((char*)tf->pTail, - (apr_size_t)tf->TailLength); - APR_BRIGADE_INSERT_TAIL(bb, b); - } - - b = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - ap_pass_brigade(r->output_filters, bb); - - /* we do nothing with (tf->dwFlags & HSE_DISCONNECT_AFTER_SEND) - */ - - if (tf->dwFlags & HSE_IO_ASYNC) { - /* XXX: Fake async response, - * use tf->pfnHseIO, or if NULL, then use cid->fnIOComplete - * pass pContect to the HseIO callback. - */ - } - return TRUE; - } - - case 1007: /* HSE_REQ_REFRESH_ISAPI_ACL */ - if (cid->sconf->LogNotSupported) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r, - "ISAPI ServerSupportFunction " - "HSE_REQ_REFRESH_ISAPI_ACL " - "is not supported: %s", r->filename); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - - case 1008: /* HSE_REQ_IS_KEEP_CONN */ - *((LPBOOL) lpvBuffer) = (r->connection->keepalive == 1); - return TRUE; - - case 1010: /* XXX: Fake it : HSE_REQ_ASYNC_READ_CLIENT */ - if (cid->sconf->LogNotSupported) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r, - "ISAPI asynchronous I/O not supported: %s", - r->filename); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - - case 1011: /* HSE_REQ_GET_IMPERSONATION_TOKEN Added in ISAPI 4.0 */ - if (cid->sconf->LogNotSupported) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r, - "ISAPI ServerSupportFunction " - "HSE_REQ_GET_IMPERSONATION_TOKEN " - "is not supported: %s", r->filename); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - -#ifdef HSE_REQ_MAP_URL_TO_PATH_EX - case 1012: /* HSE_REQ_MAP_URL_TO_PATH_EX */ - { - /* Map a URL to a filename */ - LPHSE_URL_MAPEX_INFO info = (LPHSE_URL_MAPEX_INFO) lpdwDataType; - char* test_uri = apr_pstrndup(r->pool, (char *)lpvBuffer, *lpdwSize); - - subreq = ap_sub_req_lookup_uri(test_uri, r, NULL); - info->cchMatchingURL = strlen(test_uri); - info->cchMatchingPath = apr_cpystrn(info->lpszPath, subreq->filename, - MAX_PATH) - info->lpszPath; - - /* Mapping started with assuming both strings matched. - * Now roll on the path_info as a mismatch and handle - * terminating slashes for directory matches. - */ - if (subreq->path_info && *subreq->path_info) { - apr_cpystrn(info->lpszPath + info->cchMatchingPath, - subreq->path_info, MAX_PATH - info->cchMatchingPath); - info->cchMatchingURL -= strlen(subreq->path_info); - if (subreq->finfo.filetype == APR_DIR - && info->cchMatchingPath < MAX_PATH - 1) { - /* roll forward over path_info's first slash */ - ++info->cchMatchingPath; - ++info->cchMatchingURL; - } - } - else if (subreq->finfo.filetype == APR_DIR - && info->cchMatchingPath < MAX_PATH - 1) { - /* Add a trailing slash for directory */ - info->lpszPath[info->cchMatchingPath++] = '/'; - info->lpszPath[info->cchMatchingPath] = '\0'; - } - - /* If the matched isn't a file, roll match back to the prior slash */ - if (subreq->finfo.filetype == APR_NOFILE) { - while (info->cchMatchingPath && info->cchMatchingURL) { - if (info->lpszPath[info->cchMatchingPath - 1] == '/') - break; - --info->cchMatchingPath; - --info->cchMatchingURL; - } - } - - /* Paths returned with back slashes */ - for (test_uri = info->lpszPath; *test_uri; ++test_uri) - if (*test_uri == '/') - *test_uri = '\\'; - - /* is a combination of: - * HSE_URL_FLAGS_READ 0x001 Allow read - * HSE_URL_FLAGS_WRITE 0x002 Allow write - * HSE_URL_FLAGS_EXECUTE 0x004 Allow execute - * HSE_URL_FLAGS_SSL 0x008 Require SSL - * HSE_URL_FLAGS_DONT_CACHE 0x010 Don't cache (VRoot only) - * HSE_URL_FLAGS_NEGO_CERT 0x020 Allow client SSL cert - * HSE_URL_FLAGS_REQUIRE_CERT 0x040 Require client SSL cert - * HSE_URL_FLAGS_MAP_CERT 0x080 Map client SSL cert to account - * HSE_URL_FLAGS_SSL128 0x100 Require 128-bit SSL cert - * HSE_URL_FLAGS_SCRIPT 0x200 Allow script execution - * - * XxX: As everywhere, EXEC flags could use some work... - * and this could go further with more flags, as desired. - */ - info->dwFlags = (subreq->finfo.protection & APR_UREAD ? 0x001 : 0) - | (subreq->finfo.protection & APR_UWRITE ? 0x002 : 0) - | (subreq->finfo.protection & APR_UEXECUTE ? 0x204 : 0); - return TRUE; - } -#endif - - case 1014: /* HSE_REQ_ABORTIVE_CLOSE */ - if (cid->sconf->LogNotSupported) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r, - "ISAPI ServerSupportFunction HSE_REQ_ABORTIVE_CLOSE" - " is not supported: %s", r->filename); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - - case 1015: /* HSE_REQ_GET_CERT_INFO_EX Added in ISAPI 4.0 */ - if (cid->sconf->LogNotSupported) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r, - "ISAPI ServerSupportFunction " - "HSE_REQ_GET_CERT_INFO_EX " - "is not supported: %s", r->filename); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - -#ifdef HSE_REQ_SEND_RESPONSE_HEADER_EX - case 1016: /* HSE_REQ_SEND_RESPONSE_HEADER_EX Added in ISAPI 4.0 */ - { - LPHSE_SEND_HEADER_EX_INFO shi - = (LPHSE_SEND_HEADER_EX_INFO) lpvBuffer; - /* XXX: ignore shi->fKeepConn? We shouldn't need the advise */ - /* r->connection->keepalive = shi->fKeepConn; */ - apr_off_t ate = SendResponseHeaderEx(cid, shi->pszStatus, - shi->pszHeader, - shi->cchStatus, - shi->cchHeader); - if (ate < 0) { - SetLastError(TODO_ERROR); - return FALSE; - } - else if (ate < (apr_off_t)shi->cchHeader) { - apr_bucket_brigade *bb; - apr_bucket *b; - bb = apr_brigade_create(cid->r->pool); - b = apr_bucket_transient_create(shi->pszHeader + ate, - (apr_size_t)shi->cchHeader - ate); - APR_BRIGADE_INSERT_TAIL(bb, b); - b = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - ap_pass_brigade(cid->r->output_filters, bb); - } - return TRUE; - - } -#endif - - case 1017: /* HSE_REQ_CLOSE_CONNECTION Added after ISAPI 4.0 */ - if (cid->sconf->LogNotSupported) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r, - "ISAPI ServerSupportFunction " - "HSE_REQ_CLOSE_CONNECTION " - "is not supported: %s", r->filename); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - - case 1018: /* HSE_REQ_IS_CONNECTED Added after ISAPI 4.0 */ - /* Returns True if client is connected c.f. MSKB Q188346 - * assuming the identical return mechanism as HSE_REQ_IS_KEEP_CONN - */ - *((LPBOOL) lpvBuffer) = (r->connection->aborted == 0); - return TRUE; - - case 1020: /* HSE_REQ_EXTENSION_TRIGGER Added after ISAPI 4.0 */ - /* Undocumented - defined by the Microsoft Jan '00 Platform SDK - */ - if (cid->sconf->LogNotSupported) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r, - "ISAPI ServerSupportFunction " - "HSE_REQ_EXTENSION_TRIGGER " - "is not supported: %s", r->filename); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - - default: - if (cid->sconf->LogNotSupported) - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r, - "ISAPI ServerSupportFunction (%d) not supported: " - "%s", dwHSERequest, r->filename); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } -} - -/* - * Command handler for the ISAPIReadAheadBuffer directive, which is TAKE1 - */ -static const char *isapi_cmd_readaheadbuffer(cmd_parms *cmd, void *config, - char *arg) -{ - isapi_server_conf *sconf = ap_get_module_config(cmd->server->module_config, - &isapi_module); - char *scan; - long val; - - if (((val = strtol(arg, (char **) &scan, 10)) <= 0) || *scan) - return "ISAPIReadAheadBuffer must be a legitimate value."; - - sconf->ReadAheadBuffer = val; - return NULL; -} - -/* - * Command handler for the ISAPIReadAheadBuffer directive, which is TAKE1 - */ -static const char *isapi_cmd_lognotsupported(cmd_parms *cmd, void *config, - char *arg) -{ - isapi_server_conf *sconf = ap_get_module_config(cmd->server->module_config, - &isapi_module); - - if (strcasecmp(arg, "on") == 0) { - sconf->LogNotSupported = -1; - } - else if (strcasecmp(arg, "off") == 0) { - sconf->LogNotSupported = 0; - } - else { - return "ISAPILogNotSupported must be on or off"; - } - return NULL; -} - -static const char *isapi_cmd_appendlogtoerrors(cmd_parms *cmd, void *config, - char *arg) -{ - isapi_server_conf *sconf = ap_get_module_config(cmd->server->module_config, - &isapi_module); - - if (strcasecmp(arg, "on") == 0) { - sconf->AppendLogToErrors = -1; - } - else if (strcasecmp(arg, "off") == 0) { - sconf->AppendLogToErrors = 0; - } - else { - return "ISAPIAppendLogToErrors must be on or off"; - } - return NULL; -} - -static const char *isapi_cmd_appendlogtoquery(cmd_parms *cmd, void *config, - char *arg) -{ - isapi_server_conf *sconf = ap_get_module_config(cmd->server->module_config, - &isapi_module); - - if (strcasecmp(arg, "on") == 0) { - sconf->AppendLogToQuery = -1; - } - else if (strcasecmp(arg, "off") == 0) { - sconf->AppendLogToQuery = 0; - } - else { - return "ISAPIAppendLogToQuery must be on or off"; - } - return NULL; -} - -static const char *isapi_cmd_cachefile(cmd_parms *cmd, void *dummy, - const char *filename) - -{ - isapi_server_conf *sconf = ap_get_module_config(cmd->server->module_config, - &isapi_module); - isapi_loaded *isa, **newisa; - apr_finfo_t tmp; - apr_status_t rv; - char *fspec; - - fspec = ap_os_case_canonical_filename(cmd->pool, filename); - if (apr_stat(&tmp, fspec, - APR_FINFO_TYPE, cmd->temp_pool) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, cmd->server, - "ISAPI: unable to stat(%s), skipping", filename); - return NULL; - } - if (tmp.filetype != APR_REG) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, cmd->server, - "ISAPI: %s isn't a regular file, skipping", filename); - return NULL; - } - - /* Load the extention as cached (passing sconf) */ - rv = isapi_load(cmd->pool, sconf, NULL, fspec, &isa); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, cmd->server, - "ISAPI: unable to cache %s, skipping", filename); - return NULL; - } - - /* Add to cached list of loaded modules */ - newisa = apr_array_push(sconf->loaded); - *newisa = isa; - - return NULL; -} - -static void isapi_hooks(apr_pool_t *cont) -{ - ap_hook_post_config(isapi_post_config, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_handler(isapi_handler, NULL, NULL, APR_HOOK_MIDDLE); -} - -static const command_rec isapi_cmds[] = { -AP_INIT_TAKE1("ISAPIReadAheadBuffer", isapi_cmd_readaheadbuffer, NULL, RSRC_CONF, - "Maximum bytes to initially pass to the ISAPI handler"), -AP_INIT_TAKE1("ISAPILogNotSupported", isapi_cmd_lognotsupported, NULL, RSRC_CONF, - "Log requests not supported by the ISAPI server"), -AP_INIT_TAKE1("ISAPIAppendLogToErrors", isapi_cmd_appendlogtoerrors, NULL, RSRC_CONF, - "Send all Append Log requests to the error log"), -AP_INIT_TAKE1("ISAPIAppendLogToQuery", isapi_cmd_appendlogtoquery, NULL, RSRC_CONF, - "Append Log requests are concatinated to the query args"), -AP_INIT_ITERATE("ISAPICacheFile", isapi_cmd_cachefile, NULL, RSRC_CONF, - "Cache the specified ISAPI extension in-process"), -{ NULL } -}; - -module isapi_module = { - STANDARD20_MODULE_STUFF, - NULL, /* create per-dir config */ - NULL, /* merge per-dir config */ - create_isapi_server_config, /* server config */ - NULL, /* merge server config */ - isapi_cmds, /* command apr_table_t */ - isapi_hooks /* register hooks */ -}; diff --git a/modules/cache/.cvsignore b/modules/cache/.cvsignore deleted file mode 100644 index 65f0cc30cf..0000000000 --- a/modules/cache/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -.deps -.libs -*.la -modules.mk -Makefile -*.lo -*.slo -*.so -Debug -Release diff --git a/modules/cache/.indent.pro b/modules/cache/.indent.pro deleted file mode 100644 index a9fbe9f9a1..0000000000 --- a/modules/cache/.indent.pro +++ /dev/null @@ -1,54 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 --TBUFF --TFILE --TTRANS --TUINT4 --T_trans --Tallow_options_t --Tapache_sfio --Tarray_header --Tbool_int --Tbuf_area --Tbuff_struct --Tbuffy --Tcmd_how --Tcmd_parms --Tcommand_rec --Tcommand_struct --Tconn_rec --Tcore_dir_config --Tcore_server_config --Tdir_maker_func --Tevent --Tglobals_s --Thandler_func --Thandler_rec --Tjoblist_s --Tlisten_rec --Tmerger_func --Tmode_t --Tmodule --Tmodule_struct --Tmutex --Tn_long --Tother_child_rec --Toverrides_t --Tparent_score --Tpid_t --Tpiped_log --Tpool --Trequest_rec --Trequire_line --Trlim_t --Tscoreboard --Tsemaphore --Tserver_addr_rec --Tserver_rec --Tserver_rec_chain --Tshort_score --Ttable --Ttable_entry --Tthread --Tu_wide_int --Tvtime_t --Twide_int diff --git a/modules/cache/Makefile.in b/modules/cache/Makefile.in deleted file mode 100644 index 167b343d0d..0000000000 --- a/modules/cache/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ - -include $(top_srcdir)/build/special.mk - diff --git a/modules/cache/config.m4 b/modules/cache/config.m4 deleted file mode 100644 index c4ad083075..0000000000 --- a/modules/cache/config.m4 +++ /dev/null @@ -1,11 +0,0 @@ -dnl modules enabled in this directory by default - -dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]]) - -APACHE_MODPATH_INIT(cache) - -APACHE_MODULE(file_cache, File cache, , , no) - -APR_ADDTO(LTFLAGS,-export-dynamic) - -APACHE_MODPATH_FINISH diff --git a/modules/cache/mod_file_cache.c b/modules/cache/mod_file_cache.c deleted file mode 100644 index 345a8e108b..0000000000 --- a/modules/cache/mod_file_cache.c +++ /dev/null @@ -1,468 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* - * Author: mod_file_cache by Bill Stoddard <stoddard@apache.org> - * Based on mod_mmap_static by Dean Gaudet <dgaudet@arctic.org> - * - * v0.01: initial implementation - */ - -/* - Documentation: - - Some sites have a set of static files that are really busy, and - change infrequently (or even on a regular schedule). Save time - by caching open handles to these files. This module, unlike - mod_mmap_static, caches open file handles, not file content. - On systems (like Windows) with heavy system call overhead and - that have an efficient sendfile implementation, caching file handles - offers several advantages over caching content. First, the file system - can manage the memory, allowing infrequently hit cached files to - be paged out. Second, since caching open handles does not consume - significant resources, it will be possible to enable an AutoLoadCache - feature where static files are dynamically loaded in the cache - as the server runs. On systems that have file change notification, - this module can be enhanced to automatically garbage collect - cached files that change on disk. - - This module should work on Unix systems that have sendfile. Place - cachefile directives into your configuration to direct files to - be cached. - - cachefile /path/to/file1 - cachefile /path/to/file2 - ... - - These files are only cached when the server is restarted, so if you - change the list, or if the files are changed, then you'll need to - restart the server. - - To reiterate that point: if the files are modified *in place* - without restarting the server you may end up serving requests that - are completely bogus. You should update files by unlinking the old - copy and putting a new copy in place. - - There's no such thing as inheriting these files across vhosts or - whatever... place the directives in the main server only. - - Known problems: - - Don't use Alias or RewriteRule to move these files around... unless - you feel like paying for an extra stat() on each request. This is - a deficiency in the Apache API that will hopefully be solved some day. - The file will be served out of the file handle cache, but there will be - an extra stat() that's a waste. -*/ - -#include "apr.h" - -#if !(APR_HAS_SENDFILE || APR_HAS_MMAP) -#error mod_file_cache only works on systems with APR_HAS_SENDFILE or APR_HAS_MMAP -#endif - -#include "apr_mmap.h" -#include "apr_strings.h" -#include "apr_hash.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#define CORE_PRIVATE - -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "http_protocol.h" -#include "http_request.h" -#include "http_core.h" - -module AP_MODULE_DECLARE_DATA file_cache_module; - -typedef struct { -#if APR_HAS_SENDFILE - apr_file_t *file; -#endif - const char *filename; - apr_finfo_t finfo; - int is_mmapped; -#if APR_HAS_MMAP - apr_mmap_t *mm; -#endif - char mtimestr[APR_RFC822_DATE_LEN]; - char sizestr[21]; /* big enough to hold any 64-bit file size + null */ -} a_file; - -typedef struct { - apr_hash_t *fileht; -} a_server_config; - - -static void *create_server_config(apr_pool_t *p, server_rec *s) -{ - a_server_config *sconf = apr_palloc(p, sizeof(*sconf)); - - sconf->fileht = apr_hash_make(p); - return sconf; -} - -static apr_status_t cleanup_file_cache(void *sconfv) -{ - a_server_config *sconf = sconfv; - a_file *file; - apr_hash_index_t *hi; - - /* Iterate over the file hash table and clean up each entry */ - for (hi = apr_hash_first(sconf->fileht); hi; hi=apr_hash_next(hi)) { - apr_hash_this(hi, NULL, NULL, (void **)&file); -#if APR_HAS_MMAP - if (file->is_mmapped) { - apr_mmap_delete(file->mm); - } -#endif -#if APR_HAS_SENDFILE - if (!file->is_mmapped) { - apr_file_close(file->file); - } -#endif - } - return APR_SUCCESS; -} - -static void cache_the_file(cmd_parms *cmd, const char *filename, int mmap) -{ - a_server_config *sconf; - a_file *new_file; - a_file tmp; - apr_file_t *fd = NULL; - apr_status_t rc; - const char *fspec; - - fspec = ap_os_case_canonical_filename(cmd->pool, filename); - if ((rc = apr_stat(&tmp.finfo, fspec, APR_FINFO_MIN, - cmd->temp_pool)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server, - "mod_file_cache: unable to stat(%s), skipping", fspec); - return; - } - if (tmp.finfo.filetype != APR_REG) { - ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, cmd->server, - "mod_file_cache: %s isn't a regular file, skipping", fspec); - return; - } - - rc = apr_file_open(&fd, fspec, APR_READ | APR_XTHREAD, APR_OS_DEFAULT, cmd->pool); - if (rc != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server, - "mod_file_cache: unable to open(%s, O_RDONLY), skipping", fspec); - return; - } - - /* WooHoo, we have a file to put in the cache */ - new_file = apr_pcalloc(cmd->pool, sizeof(a_file)); - new_file->finfo = tmp.finfo; - -#if APR_HAS_MMAP - if (mmap) { - /* MMAPFile directive. MMAP'ing the file */ - if ((rc = apr_mmap_create(&new_file->mm, fd, 0, new_file->finfo.size, - APR_MMAP_READ, cmd->pool)) != APR_SUCCESS) { - apr_file_close(fd); - ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server, - "mod_file_cache: unable to mmap %s, skipping", filename); - return; - } - apr_file_close(fd); - new_file->is_mmapped = TRUE; - } -#endif -#if APR_HAS_SENDFILE - if (!mmap) { - /* CacheFile directive. Caching the file handle */ - new_file->is_mmapped = FALSE; - new_file->file = fd; - } -#endif - - new_file->filename = fspec; - apr_rfc822_date(new_file->mtimestr, new_file->finfo.mtime); - apr_snprintf(new_file->sizestr, sizeof new_file->sizestr, "%" APR_OFF_T_FMT, new_file->finfo.size); - - sconf = ap_get_module_config(cmd->server->module_config, &file_cache_module); - apr_hash_set(sconf->fileht, new_file->filename, strlen(new_file->filename), new_file); - - if (apr_hash_count(sconf->fileht) == 1) { - /* first one, register the cleanup */ - apr_pool_cleanup_register(cmd->pool, sconf, cleanup_file_cache, apr_pool_cleanup_null); - } -} - -static const char *cachefilehandle(cmd_parms *cmd, void *dummy, const char *filename) -{ -#if APR_HAS_SENDFILE - cache_the_file(cmd, filename, 0); -#else - /* Sendfile not supported by this OS */ - ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, cmd->server, - "mod_file_cache: unable to cache file: %s. Sendfile is not supported on this OS", filename); -#endif - return NULL; -} -static const char *cachefilemmap(cmd_parms *cmd, void *dummy, const char *filename) -{ -#if APR_HAS_MMAP - cache_the_file(cmd, filename, 1); -#else - /* MMAP not supported by this OS */ - ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, cmd->server, - "mod_file_cache: unable to cache file: %s. MMAP is not supported by this OS", filename); -#endif - return NULL; -} - -static void file_cache_post_config(apr_pool_t *p, apr_pool_t *plog, - apr_pool_t *ptemp, server_rec *s) -{ - /* Hummm, anything to do here? */ -} - -/* If it's one of ours, fill in r->finfo now to avoid extra stat()... this is a - * bit of a kludge, because we really want to run after core_translate runs. - */ -static int file_cache_xlat(request_rec *r) -{ - a_server_config *sconf; - a_file *match; - int res; - - sconf = ap_get_module_config(r->server->module_config, &file_cache_module); - - /* we only operate when at least one cachefile directive was used */ - if (!apr_hash_count(sconf->fileht)) { - return DECLINED; - } - - res = ap_core_translate(r); - if (res != OK || !r->filename) { - return res; - } - - /* search the cache */ - match = (a_file *) apr_hash_get(sconf->fileht, r->filename, APR_HASH_KEY_STRING); - if (match == NULL) - return DECLINED; - - /* pass search results to handler */ - ap_set_module_config(r->request_config, &file_cache_module, match); - - /* shortcircuit the get_path_info() stat() calls and stuff */ - r->finfo = match->finfo; - return OK; -} - -static int mmap_handler(request_rec *r, a_file *file) -{ -#if APR_HAS_MMAP - ap_send_mmap (file->mm, r, 0, file->finfo.size); -#endif - return OK; -} - -static int sendfile_handler(request_rec *r, a_file *file) -{ -#if APR_HAS_SENDFILE - apr_size_t nbytes; - apr_status_t rv = APR_EINIT; - - /* A cached file handle (more importantly, its file pointer) is - * shared by all threads in the process. The file pointer will - * be corrupted if multiple threads attempt to read from the - * cached file handle. The sendfile API does not rely on the position - * of the file pointer instead taking explicit file offset and - * length arguments. - * - * We should call ap_send_fd with a cached file handle IFF - * we are CERTAIN the file will be served with apr_sendfile(). - * The presense of an AP_FTYPE_FILTER in the filter chain nearly - * guarantees that apr_sendfile will NOT be used to send the file. - * Furthermore, AP_FTYPE_CONTENT filters will be at the beginning - * of the chain, so it should suffice to just check the first - * filter in the chain. If the first filter is not a content filter, - * assume apr_sendfile() will be used to send the content. - */ - if (r->output_filters && r->output_filters->frec) { - if (r->output_filters->frec->ftype == AP_FTYPE_CONTENT) - return DECLINED; - } - - - rv = ap_send_fd(file->file, r, 0, file->finfo.size, &nbytes); - if (rv != APR_SUCCESS) { - /* ap_send_fd will log the error */ - return HTTP_INTERNAL_SERVER_ERROR; - } -#endif - return OK; -} - -static int file_cache_handler(request_rec *r) -{ - a_file *match; - int errstatus; - int rc = OK; - - /* XXX: not sure if this is right yet - * see comment in http_core.c:default_handler - */ - if (ap_strcmp_match(r->handler, "*/*")) { - return DECLINED; - } - - /* we don't handle anything but GET */ - if (r->method_number != M_GET) return DECLINED; - - /* did xlat phase find the file? */ - match = ap_get_module_config(r->request_config, &file_cache_module); - - if (match == NULL) { - return DECLINED; - } - - /* note that we would handle GET on this resource */ - r->allowed |= (1 << M_GET); - - /* This handler has no use for a request body (yet), but we still - * need to read and discard it if the client sent one. - */ - if ((errstatus = ap_discard_request_body(r)) != OK) - return errstatus; - - ap_update_mtime(r, match->finfo.mtime); - - /* ap_set_last_modified() always converts the file mtime to a string - * which is slow. Accelerate the common case. - * ap_set_last_modified(r); - */ - { - apr_time_t mod_time; - char *datestr; - - mod_time = ap_rationalize_mtime(r, r->mtime); - if (mod_time == match->finfo.mtime) - datestr = match->mtimestr; - else { - datestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN); - apr_rfc822_date(datestr, mod_time); - } - apr_table_setn(r->headers_out, "Last-Modified", datestr); - } - - ap_set_etag(r); - if ((errstatus = ap_meets_conditions(r)) != OK) { - return errstatus; - } - - /* ap_set_content_length() always converts the same number and never - * returns an error. Accelerate it. - */ - r->clength = match->finfo.size; - apr_table_setn(r->headers_out, "Content-Length", match->sizestr); - - /* Call appropriate handler */ - if (!r->header_only) { - if (match->is_mmapped == TRUE) - rc = mmap_handler(r, match); - else - rc = sendfile_handler(r, match); - } - - return rc; -} - -static command_rec file_cache_cmds[] = -{ -AP_INIT_ITERATE("cachefile", cachefilehandle, NULL, RSRC_CONF, - "A space separated list of files to add to the file handle cache at config time"), -AP_INIT_ITERATE("mmapfile", cachefilemmap, NULL, RSRC_CONF, - "A space separated list of files to mmap at config time"), - {NULL} -}; - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_handler(file_cache_handler, NULL, NULL, APR_HOOK_LAST); - ap_hook_post_config(file_cache_post_config, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_translate_name(file_cache_xlat, NULL, NULL, APR_HOOK_MIDDLE); - /* This trick doesn't work apparently because the translate hooks - are single shot. If the core_hook returns OK, then our hook is - not called. - ap_hook_translate_name(file_cache_xlat, aszPre, NULL, APR_HOOK_MIDDLE); - */ - -} - -module AP_MODULE_DECLARE_DATA file_cache_module = -{ - STANDARD20_MODULE_STUFF, - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - create_server_config, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - file_cache_cmds, /* command handlers */ - register_hooks /* register hooks */ -}; diff --git a/modules/cache/mod_file_cache.dsp b/modules/cache/mod_file_cache.dsp deleted file mode 100644 index 58786f2e40..0000000000 --- a/modules/cache/mod_file_cache.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_file_cache" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_file_cache - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_file_cache.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_file_cache.mak" CFG="mod_file_cache - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_file_cache - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_file_cache - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_file_cache - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_file_cache" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 /nologo /subsystem:windows /dll /map /machine:I386 /out:"Release/mod_file_cache.so" /base:@..\..\os\win32\BaseAddr.ref,mod_file_cache -# ADD LINK32 /nologo /subsystem:windows /dll /map /machine:I386 /out:"Release/mod_file_cache.so" /base:@..\..\os\win32\BaseAddr.ref,mod_file_cache - -!ELSEIF "$(CFG)" == "mod_file_cache - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_file_cache" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:"Debug/mod_file_cache.so" /base:@..\..\os\win32\BaseAddr.ref,mod_file_cache -# ADD LINK32 /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:"Debug/mod_file_cache.so" /base:@..\..\os\win32\BaseAddr.ref,mod_file_cache - -!ENDIF - -# Begin Target - -# Name "mod_file_cache - Win32 Release" -# Name "mod_file_cache - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_file_cache.c -# End Source File -# End Target -# End Project diff --git a/modules/cache/mod_file_cache.mak b/modules/cache/mod_file_cache.mak deleted file mode 100644 index 3a4c5da41d..0000000000 --- a/modules/cache/mod_file_cache.mak +++ /dev/null @@ -1,331 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_file_cache.dsp -!IF "$(CFG)" == "" -CFG=mod_file_cache - Win32 Debug -!MESSAGE No configuration specified. Defaulting to mod_file_cache - Win32\ - Debug. -!ENDIF - -!IF "$(CFG)" != "mod_file_cache - Win32 Release" && "$(CFG)" !=\ - "mod_file_cache - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_file_cache.mak" CFG="mod_file_cache - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_file_cache - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_file_cache - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_file_cache - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_file_cache.so" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libapr - Win32 Release"\ - "$(OUTDIR)\mod_file_cache.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_file_cache.idb" - -@erase "$(INTDIR)\mod_file_cache.obj" - -@erase "$(OUTDIR)\mod_file_cache.exp" - -@erase "$(OUTDIR)\mod_file_cache.lib" - -@erase "$(OUTDIR)\mod_file_cache.map" - -@erase "$(OUTDIR)\mod_file_cache.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_file_cache" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_file_cache.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=/nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_file_cache.pdb" /map:"$(INTDIR)\mod_file_cache.map"\ - /machine:I386 /out:"$(OUTDIR)\mod_file_cache.so"\ - /implib:"$(OUTDIR)\mod_file_cache.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_file_cache -LINK32_OBJS= \ - "$(INTDIR)\mod_file_cache.obj" \ - "..\..\Release\libhttpd.lib" \ - "..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_file_cache.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_file_cache - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_file_cache.so" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libapr - Win32 Debug"\ - "$(OUTDIR)\mod_file_cache.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_file_cache.idb" - -@erase "$(INTDIR)\mod_file_cache.obj" - -@erase "$(OUTDIR)\mod_file_cache.exp" - -@erase "$(OUTDIR)\mod_file_cache.lib" - -@erase "$(OUTDIR)\mod_file_cache.map" - -@erase "$(OUTDIR)\mod_file_cache.pdb" - -@erase "$(OUTDIR)\mod_file_cache.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_file_cache" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_file_cache.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=/nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_file_cache.pdb" /map:"$(INTDIR)\mod_file_cache.map" /debug\ - /machine:I386 /out:"$(OUTDIR)\mod_file_cache.so"\ - /implib:"$(OUTDIR)\mod_file_cache.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_file_cache -LINK32_OBJS= \ - "$(INTDIR)\mod_file_cache.obj" \ - "..\..\Debug\libhttpd.lib" \ - "..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_file_cache.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_file_cache - Win32 Release" || "$(CFG)" ==\ - "mod_file_cache - Win32 Debug" - -!IF "$(CFG)" == "mod_file_cache - Win32 Release" - -"libapr - Win32 Release" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Release" - cd "..\..\modules\cache" - -"libapr - Win32 ReleaseCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\cache" - -!ELSEIF "$(CFG)" == "mod_file_cache - Win32 Debug" - -"libapr - Win32 Debug" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Debug" - cd "..\..\modules\cache" - -"libapr - Win32 DebugCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\cache" - -!ENDIF - -!IF "$(CFG)" == "mod_file_cache - Win32 Release" - -"libhttpd - Win32 Release" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Release" - cd ".\modules\cache" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Release"\ - RECURSE=1 - cd ".\modules\cache" - -!ELSEIF "$(CFG)" == "mod_file_cache - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Debug" - cd ".\modules\cache" - -"libhttpd - Win32 DebugCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\cache" - -!ENDIF - -SOURCE=.\mod_file_cache.c -DEP_CPP_MOD_F=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\http_request.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\srclib\apr-util\include\apu.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_dso.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_hash.h"\ - "..\..\srclib\apr\include\apr_lock.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\include\apr_user.h"\ - "..\..\srclib\apr\include\apr_want.h"\ - -NODEP_CPP_MOD_F=\ - "..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\mod_file_cache.obj" : $(SOURCE) $(DEP_CPP_MOD_F) "$(INTDIR)" - - - -!ENDIF - diff --git a/modules/config5.m4 b/modules/config5.m4 deleted file mode 100644 index caa40eaf70..0000000000 --- a/modules/config5.m4 +++ /dev/null @@ -1,43 +0,0 @@ -AC_MSG_CHECKING(for extra modules) -AC_ARG_WITH(module, - [ --with-module=location Include the specified module. location is the - path to the new module.], - [ - modtype=`echo $withval | sed -e's/\(.*\):.*/\1/'` - pkg=`echo $withval | sed -e's/.*:\(.*\)/\1/'` - modfilec=`echo $pkg | sed -e 's;^.*/;;'` - modfileo=`echo $pkg | sed -e 's;^.*/;;' -e 's;\.c$;.o;'` - - if test "x$withval" != "xmodules/$modtype/$modfilec"; then - cp $pkg modules/$modtype/$modfilec - fi - module=`echo $pkg | sed -e 's;.*/mod_\(.*\).c;\1;'` - objects="mod_$module.lo" - libname="mod_$module.la" - modpath_current="modules/$modtype" - BUILTIN_LIBS="$BUILTIN_LIBS $modpath_current/$libname" - if test ! -s "$modpath_current/modules.mk"; then - cat >>$modpath_current/modules.mk<<EOF -$libname: $objects - \$(MOD_LINK) $objects -DISTCLEAN_TARGETS = modules.mk -static = $libname -shared = -EOF - else - cat >>$modpath_current/modules.mk.tmp<<EOF -$libname: $objects - \$(MOD_LINK) $objects -EOF - cat $modpath_current/modules.mk >> $modpath_current/modules.mk.tmp - rm $modpath_current/modules.mk - mv $modpath_current/modules.mk.tmp $modpath_current/modules.mk - sed -e "s/\(static =.*\)/\1 $libname/" $modpath_current/modules.mk > $modpath_current/modules.mk.tmp - rm $modpath_current/modules.mk - mv $modpath_current/modules.mk.tmp $modpath_current/modules.mk - fi - MODLIST="$MODLIST $module" - AC_MSG_RESULT(added $withval) - ], - [ AC_MSG_RESULT(no extra modules) - ]) diff --git a/modules/dav/fs/.cvsignore b/modules/dav/fs/.cvsignore deleted file mode 100644 index 65f0cc30cf..0000000000 --- a/modules/dav/fs/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -.deps -.libs -*.la -modules.mk -Makefile -*.lo -*.slo -*.so -Debug -Release diff --git a/modules/dav/fs/Makefile.in b/modules/dav/fs/Makefile.in deleted file mode 100644 index 7c5c149d85..0000000000 --- a/modules/dav/fs/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ -# a modules Makefile has no explicit targets -- they will be defined by -# whatever modules are enabled. just grab special.mk to deal with this. -include $(top_srcdir)/build/special.mk diff --git a/modules/dav/fs/config6.m4 b/modules/dav/fs/config6.m4 deleted file mode 100644 index ca1153aed3..0000000000 --- a/modules/dav/fs/config6.m4 +++ /dev/null @@ -1,15 +0,0 @@ -dnl modules enabled in this directory by default - -APACHE_MODPATH_INIT(dav/fs) - -dav_fs_objects="mod_dav_fs.lo dbm.lo lock.lo repos.lo" - -if test "$enable_dav" = "no"; then - dav_fs_enable=no -else - dav_fs_enable=yes -fi - -APACHE_MODULE(dav_fs, DAV provider for the filesystem, $dav_fs_objects, , $dav_fs_enable) - -APACHE_MODPATH_FINISH diff --git a/modules/dav/fs/dbm.c b/modules/dav/fs/dbm.c deleted file mode 100644 index fd1b7714de..0000000000 --- a/modules/dav/fs/dbm.c +++ /dev/null @@ -1,259 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* -** DAV extension module for Apache 2.0.* -** - Database support using DBM-style databases, -** part of the filesystem repository implementation -*/ - -/* -** This implementation uses a SDBM database per file and directory to -** record the properties. These databases are kept in a subdirectory (of -** the directory in question or the directory that holds the file in -** question) named by the macro DAV_FS_STATE_DIR (.DAV). The filename of the -** database is equivalent to the target filename, and is -** DAV_FS_STATE_FILE_FOR_DIR (.state_for_dir) for the directory itself. -*/ - -#include "apr_strings.h" -#include "apr_file_io.h" - -#include "apr_dbm.h" - -#include "mod_dav.h" -#include "repos.h" - -struct dav_db { - apr_pool_t *pool; - apr_dbm_t *file; -}; - - -void dav_dbm_get_statefiles(apr_pool_t *p, const char *fname, - const char **state1, const char **state2) -{ - if (fname == NULL) - fname = DAV_FS_STATE_FILE_FOR_DIR; - - apr_dbm_get_usednames(p, fname, state1, state2); -} - -static dav_error * dav_fs_dbm_error(dav_db *db, apr_pool_t *p, - apr_status_t status) -{ - int save_errno = errno; - int errcode; - const char *errstr; - dav_error *err; - char errbuf[200]; - - if (status == APR_SUCCESS) - return NULL; - - p = db ? db->pool : p; - - /* There might not be a <db> if we had problems creating it. */ - if (db == NULL) { - errcode = 1; - errstr = "Could not open property database."; - } - else { - (void) apr_dbm_geterror(db->file, &errcode, errbuf, sizeof(errbuf)); - errstr = apr_pstrdup(p, errbuf); - } - - err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, errcode, errstr); - err->save_errno = save_errno; - return err; -} - -/* ensure that our state subdirectory is present */ -/* ### does this belong here or in dav_fs_repos.c ?? */ -void dav_fs_ensure_state_dir(apr_pool_t * p, const char *dirname) -{ - const char *pathname = apr_pstrcat(p, dirname, "/" DAV_FS_STATE_DIR, NULL); - - /* ### do we need to deal with the umask? */ - - /* just try to make it, ignoring any resulting errors */ - (void) apr_dir_make(pathname, APR_OS_DEFAULT, p); -} - -/* dav_dbm_open_direct: Opens a *dbm database specified by path. - * ro = boolean read-only flag. - */ -dav_error * dav_dbm_open_direct(apr_pool_t *p, const char *pathname, int ro, - dav_db **pdb) -{ - apr_status_t status; - apr_dbm_t *file; - - *pdb = NULL; - - if ((status = apr_dbm_open(&file, pathname, - ro ? APR_DBM_READONLY : APR_DBM_RWCREATE, - APR_OS_DEFAULT, p)) - != APR_SUCCESS - && !ro) { - /* ### do something with 'status' */ - - /* we can't continue if we couldn't open the file - and we need to write */ - return dav_fs_dbm_error(NULL, p, status); - } - - /* may be NULL if we tried to open a non-existent db as read-only */ - if (file != NULL) { - /* we have an open database... return it */ - *pdb = apr_pcalloc(p, sizeof(**pdb)); - (*pdb)->pool = p; - (*pdb)->file = file; - } - - return NULL; -} - -static dav_error * dav_dbm_open(apr_pool_t * p, const dav_resource *resource, - int ro, dav_db **pdb) -{ - const char *dirpath; - const char *fname; - const char *pathname; - - /* Get directory and filename for resource */ - dav_fs_dir_file_name(resource, &dirpath, &fname); - - /* If not opening read-only, ensure the state dir exists */ - if (!ro) { - /* ### what are the perf implications of always checking this? */ - dav_fs_ensure_state_dir(p, dirpath); - } - - pathname = apr_pstrcat(p, - dirpath, - "/" DAV_FS_STATE_DIR "/", - fname ? fname : DAV_FS_STATE_FILE_FOR_DIR, - NULL); - - /* ### readers cannot open while a writer has this open; we should - ### perform a few retries with random pauses. */ - - /* ### do we need to deal with the umask? */ - - return dav_dbm_open_direct(p, pathname, ro, pdb); -} - -static void dav_dbm_close(dav_db *db) -{ - apr_dbm_close(db->file); -} - -static dav_error * dav_dbm_fetch(dav_db *db, dav_datum key, dav_datum *pvalue) -{ - apr_status_t status = apr_dbm_fetch(db->file, key, pvalue); - - return dav_fs_dbm_error(db, NULL, status); -} - -static dav_error * dav_dbm_store(dav_db *db, dav_datum key, dav_datum value) -{ - apr_status_t status = apr_dbm_store(db->file, key, value); - - return dav_fs_dbm_error(db, NULL, status); -} - -static dav_error * dav_dbm_delete(dav_db *db, dav_datum key) -{ - apr_status_t status = apr_dbm_delete(db->file, key); - - return dav_fs_dbm_error(db, NULL, status); -} - -static int dav_dbm_exists(dav_db *db, dav_datum key) -{ - return apr_dbm_exists(db->file, key); -} - -static dav_error * dav_dbm_firstkey(dav_db *db, dav_datum *pkey) -{ - apr_status_t status = apr_dbm_firstkey(db->file, pkey); - - return dav_fs_dbm_error(db, NULL, status); -} - -static dav_error * dav_dbm_nextkey(dav_db *db, dav_datum *pkey) -{ - apr_status_t status = apr_dbm_nextkey(db->file, pkey); - - return dav_fs_dbm_error(db, NULL, status); -} - -static void dav_dbm_freedatum(dav_db *db, dav_datum data) -{ - apr_dbm_freedatum(db->file, data); -} - -const dav_hooks_db dav_hooks_db_dbm = -{ - dav_dbm_open, - dav_dbm_close, - dav_dbm_fetch, - dav_dbm_store, - dav_dbm_delete, - dav_dbm_exists, - dav_dbm_firstkey, - dav_dbm_nextkey, - dav_dbm_freedatum, -}; diff --git a/modules/dav/fs/lock.c b/modules/dav/fs/lock.c deleted file mode 100644 index cd7c43188d..0000000000 --- a/modules/dav/fs/lock.c +++ /dev/null @@ -1,1537 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* -** DAV filesystem lock implementation -*/ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_file_io.h" -#include "apr_uuid.h" - -#define APR_WANT_MEMFUNC -#include "apr_want.h" - -#include "httpd.h" -#include "http_log.h" - -#include "mod_dav.h" -#include "repos.h" - - -/* --------------------------------------------------------------- -** -** Lock database primitives -** -*/ - -/* -** LOCK DATABASES -** -** Lockdiscovery information is stored in the single lock database specified -** by the DAVLockDB directive. Information about this db is stored in the -** global server configuration. -** -** KEY -** -** The database is keyed by a key_type unsigned char (DAV_TYPE_INODE or -** DAV_TYPE_FNAME) followed by inode and device number if possible, -** otherwise full path (in the case of Win32 or lock-null resources). -** -** VALUE -** -** The value consists of a list of elements. -** DIRECT LOCK: [char (DAV_LOCK_DIRECT), -** char (dav_lock_scope), -** char (dav_lock_type), -** int depth, -** time_t expires, -** apr_uuid_t locktoken, -** char[] owner, -** char[] auth_user] -** -** INDIRECT LOCK: [char (DAV_LOCK_INDIRECT), -** apr_uuid_t locktoken, -** time_t expires, -** int key_size, -** char[] key] -** The key is to the collection lock that resulted in this indirect lock -*/ - -#define DAV_TRUE 1 -#define DAV_FALSE 0 - -#define DAV_CREATE_LIST 23 -#define DAV_APPEND_LIST 24 - -/* Stored lock_discovery prefix */ -#define DAV_LOCK_DIRECT 1 -#define DAV_LOCK_INDIRECT 2 - -#define DAV_TYPE_INODE 10 -#define DAV_TYPE_FNAME 11 - - -/* ack. forward declare. */ -static dav_error * dav_fs_remove_locknull_member(apr_pool_t *p, - const char *filename, - dav_buffer *pbuf); - -/* -** Use the opaquelock scheme for locktokens -*/ -struct dav_locktoken { - apr_uuid_t uuid; -}; -#define dav_compare_locktoken(plt1, plt2) \ - memcmp(&(plt1)->uuid, &(plt2)->uuid, sizeof((plt1)->uuid)) - - -/* ################################################################# -** ### keep these structures (internal) or move fully to dav_lock? -*/ - -/* -** We need to reliably size the fixed-length portion of -** dav_lock_discovery; best to separate it into another -** struct for a convenient sizeof, unless we pack lock_discovery. -*/ -typedef struct dav_lock_discovery_fixed -{ - char scope; - char type; - int depth; - time_t timeout; -} dav_lock_discovery_fixed; - -typedef struct dav_lock_discovery -{ - struct dav_lock_discovery_fixed f; - - dav_locktoken *locktoken; - const char *owner; /* owner field from activelock */ - const char *auth_user; /* authenticated user who created the lock */ - struct dav_lock_discovery *next; -} dav_lock_discovery; - -/* Indirect locks represent locks inherited from containing collections. - * They reference the lock token for the collection the lock is - * inherited from. A lock provider may also define a key to the - * inherited lock, for fast datbase lookup. The key is opaque outside - * the lock provider. - */ -typedef struct dav_lock_indirect -{ - dav_locktoken *locktoken; - dav_datum key; - struct dav_lock_indirect *next; - time_t timeout; -} dav_lock_indirect; - -/* ################################################################# */ - - -/* -** Stored direct lock info - full lock_discovery length: -** prefix + Fixed length + lock token + 2 strings + 2 nulls (one for each string) -*/ -#define dav_size_direct(a) (1 + sizeof(dav_lock_discovery_fixed) \ - + sizeof(apr_uuid_t) \ - + ((a)->owner ? strlen((a)->owner) : 0) \ - + ((a)->auth_user ? strlen((a)->auth_user) : 0) \ - + 2) - -/* Stored indirect lock info - lock token and dav_datum */ -#define dav_size_indirect(a) (1 + sizeof(apr_uuid_t) \ - + sizeof(time_t) \ - + sizeof(int) + (a)->key.dsize) - -/* -** The lockdb structure. -** -** The <db> field may be NULL, meaning one of two things: -** 1) That we have not actually opened the underlying database (yet). The -** <opened> field should be false. -** 2) We opened it readonly and it wasn't present. -** -** The delayed opening (determined by <opened>) makes creating a lockdb -** quick, while deferring the underlying I/O until it is actually required. -** -** We export the notion of a lockdb, but hide the details of it. Most -** implementations will use a database of some kind, but it is certainly -** possible that alternatives could be used. -*/ -struct dav_lockdb_private -{ - request_rec *r; /* for accessing the uuid state */ - apr_pool_t *pool; /* a pool to use */ - const char *lockdb_path; /* where is the lock database? */ - - int opened; /* we opened the database */ - dav_db *db; /* if non-NULL, the lock database */ -}; -typedef struct -{ - dav_lockdb pub; - dav_lockdb_private priv; -} dav_lockdb_combined; - -/* -** The private part of the lock structure. -*/ -struct dav_lock_private -{ - dav_datum key; /* key into the lock database */ -}; -typedef struct -{ - dav_lock pub; - dav_lock_private priv; - dav_locktoken token; -} dav_lock_combined; - -/* -** This must be forward-declared so the open_lockdb function can use it. -*/ -extern const dav_hooks_locks dav_hooks_locks_fs; - - -/* internal function for creating locks */ -static dav_lock *dav_fs_alloc_lock(dav_lockdb *lockdb, dav_datum key, - const dav_locktoken *locktoken) -{ - dav_lock_combined *comb; - - comb = apr_pcalloc(lockdb->info->pool, sizeof(*comb)); - comb->pub.rectype = DAV_LOCKREC_DIRECT; - comb->pub.info = &comb->priv; - comb->priv.key = key; - - if (locktoken == NULL) { - comb->pub.locktoken = &comb->token; - apr_uuid_get(&comb->token.uuid); - } - else { - comb->pub.locktoken = locktoken; - } - - return &comb->pub; -} - -/* -** dav_fs_parse_locktoken -** -** Parse an opaquelocktoken URI into a locktoken. -*/ -static dav_error * dav_fs_parse_locktoken( - apr_pool_t *p, - const char *char_token, - dav_locktoken **locktoken_p) -{ - dav_locktoken *locktoken; - - if (ap_strstr_c(char_token, "opaquelocktoken:") != char_token) { - return dav_new_error(p, - HTTP_BAD_REQUEST, DAV_ERR_LOCK_UNK_STATE_TOKEN, - "The lock token uses an unknown State-token " - "format and could not be parsed."); - } - char_token += 16; - - locktoken = apr_pcalloc(p, sizeof(*locktoken)); - if (apr_uuid_parse(&locktoken->uuid, char_token)) { - return dav_new_error(p, HTTP_BAD_REQUEST, DAV_ERR_LOCK_PARSE_TOKEN, - "The opaquelocktoken has an incorrect format " - "and could not be parsed."); - } - - *locktoken_p = locktoken; - return NULL; -} - -/* -** dav_fs_format_locktoken -** -** Generate the URI for a locktoken -*/ -static const char *dav_fs_format_locktoken( - apr_pool_t *p, - const dav_locktoken *locktoken) -{ - char buf[APR_UUID_FORMATTED_LENGTH + 1]; - - apr_uuid_format(buf, &locktoken->uuid); - return apr_pstrcat(p, "opaquelocktoken:", buf, NULL); -} - -/* -** dav_fs_compare_locktoken -** -** Determine whether two locktokens are the same -*/ -static int dav_fs_compare_locktoken( - const dav_locktoken *lt1, - const dav_locktoken *lt2) -{ - return dav_compare_locktoken(lt1, lt2); -} - -/* -** dav_fs_really_open_lockdb: -** -** If the database hasn't been opened yet, then open the thing. -*/ -static dav_error * dav_fs_really_open_lockdb(dav_lockdb *lockdb) -{ - dav_error *err; - - if (lockdb->info->opened) - return NULL; - - err = dav_dbm_open_direct(lockdb->info->pool, - lockdb->info->lockdb_path, - lockdb->ro, - &lockdb->info->db); - if (err != NULL) { - return dav_push_error(lockdb->info->pool, - HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_LOCK_OPENDB, - "Could not open the lock database.", - err); - } - - /* all right. it is opened now. */ - lockdb->info->opened = 1; - - return NULL; -} - -/* -** dav_fs_open_lockdb: -** -** "open" the lock database, as specified in the global server configuration. -** If force is TRUE, then the database is opened now, rather than lazily. -** -** Note that only one can be open read/write. -*/ -static dav_error * dav_fs_open_lockdb(request_rec *r, int ro, int force, - dav_lockdb **lockdb) -{ - dav_lockdb_combined *comb; - - comb = apr_pcalloc(r->pool, sizeof(*comb)); - comb->pub.hooks = &dav_hooks_locks_fs; - comb->pub.ro = ro; - comb->pub.info = &comb->priv; - comb->priv.r = r; - comb->priv.pool = r->pool; - - comb->priv.lockdb_path = dav_get_lockdb_path(r); - if (comb->priv.lockdb_path == NULL) { - return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_LOCK_NO_DB, - "A lock database was not specified with the " - "DAVLockDB directive. One must be specified " - "to use the locking functionality."); - } - - /* done initializing. return it. */ - *lockdb = &comb->pub; - - if (force) { - /* ### add a higher-level comment? */ - return dav_fs_really_open_lockdb(*lockdb); - } - - return NULL; -} - -/* -** dav_fs_close_lockdb: -** -** Close it. Duh. -*/ -static void dav_fs_close_lockdb(dav_lockdb *lockdb) -{ - if (lockdb->info->db != NULL) - (*dav_hooks_db_dbm.close)(lockdb->info->db); -} - -/* -** dav_fs_build_fname_key -** -** Given a pathname, build a DAV_TYPE_FNAME lock database key. -*/ -static dav_datum dav_fs_build_fname_key(apr_pool_t *p, const char *pathname) -{ - dav_datum key; - - /* ### does this allocation have a proper lifetime? need to check */ - /* ### can we use a buffer for this? */ - - /* size is TYPE + pathname + null */ - key.dsize = strlen(pathname) + 2; - key.dptr = apr_palloc(p, key.dsize); - *key.dptr = DAV_TYPE_FNAME; - memcpy(key.dptr + 1, pathname, key.dsize - 1); - if (key.dptr[key.dsize - 2] == '/') - key.dptr[--key.dsize - 1] = '\0'; - return key; -} - -/* -** dav_fs_build_key: Given a resource, return a dav_datum key -** to look up lock information for this file. -** -** (Win32 or file is lock-null): -** dav_datum->dvalue = full path -** -** (non-Win32 and file exists ): -** dav_datum->dvalue = inode, dev_major, dev_minor -*/ -static dav_datum dav_fs_build_key(apr_pool_t *p, const dav_resource *resource) -{ - const char *file = dav_fs_pathname(resource); -#ifndef WIN32 - dav_datum key; - apr_finfo_t finfo; - - /* ### use lstat() ?? */ - if (apr_stat(&finfo, file, APR_FINFO_NORM, p) == APR_SUCCESS) { - - /* ### can we use a buffer for this? */ - key.dsize = 1 + sizeof(finfo.inode) + sizeof(finfo.device); - key.dptr = apr_palloc(p, key.dsize); - *key.dptr = DAV_TYPE_INODE; - memcpy(key.dptr + 1, &finfo.inode, sizeof(finfo.inode)); - memcpy(key.dptr + 1 + sizeof(finfo.inode), &finfo.device, - sizeof(finfo.device)); - - return key; - } -#endif - - return dav_fs_build_fname_key(p, file); -} - -/* -** dav_fs_lock_expired: return 1 (true) if the given timeout is in the past -** or present (the lock has expired), or 0 (false) if in the future -** (the lock has not yet expired). -*/ -static int dav_fs_lock_expired(time_t expires) -{ - return expires != DAV_TIMEOUT_INFINITE && time(NULL) >= expires; -} - -/* -** dav_fs_save_lock_record: Saves the lock information specified in the -** direct and indirect lock lists about path into the lock database. -** If direct and indirect == NULL, the key is removed. -*/ -static dav_error * dav_fs_save_lock_record(dav_lockdb *lockdb, dav_datum key, - dav_lock_discovery *direct, - dav_lock_indirect *indirect) -{ - dav_error *err; - dav_datum val = { 0 }; - char *ptr; - dav_lock_discovery *dp = direct; - dav_lock_indirect *ip = indirect; - -#if DAV_DEBUG - if (lockdb->ro) { - return dav_new_error(lockdb->info->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "INTERNAL DESIGN ERROR: the lockdb was opened " - "readonly, but an attempt to save locks was " - "performed."); - } -#endif - - if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) { - /* ### add a higher-level error? */ - return err; - } - - /* If nothing to save, delete key */ - if (dp == NULL && ip == NULL) { - /* don't fail if the key is not present */ - /* ### but what about other errors? */ - (void) (*dav_hooks_db_dbm.remove)(lockdb->info->db, key); - return NULL; - } - - while(dp) { - val.dsize += dav_size_direct(dp); - dp = dp->next; - } - while(ip) { - val.dsize += dav_size_indirect(ip); - ip = ip->next; - } - - /* ### can this be apr_palloc() ? */ - /* ### hmmm.... investigate the use of a buffer here */ - ptr = val.dptr = apr_pcalloc(lockdb->info->pool, val.dsize); - dp = direct; - ip = indirect; - - while(dp) { - *ptr++ = DAV_LOCK_DIRECT; /* Direct lock - lock_discovery struct follows */ - memcpy(ptr, dp, sizeof(dp->f)); /* Fixed portion of struct */ - ptr += sizeof(dp->f); - memcpy(ptr, dp->locktoken, sizeof(*dp->locktoken)); - ptr += sizeof(*dp->locktoken); - if (dp->owner == NULL) { - *ptr++ = '\0'; - } - else { - memcpy(ptr, dp->owner, strlen(dp->owner) + 1); - ptr += strlen(dp->owner) + 1; - } - if (dp->auth_user == NULL) { - *ptr++ = '\0'; - } - else { - memcpy(ptr, dp->auth_user, strlen(dp->auth_user) + 1); - ptr += strlen(dp->auth_user) + 1; - } - - dp = dp->next; - } - - while(ip) { - *ptr++ = DAV_LOCK_INDIRECT; /* Indirect lock prefix */ - memcpy(ptr, ip->locktoken, sizeof(*ip->locktoken)); /* Locktoken */ - ptr += sizeof(*ip->locktoken); - memcpy(ptr, &ip->timeout, sizeof(ip->timeout)); /* Expire time */ - ptr += sizeof(ip->timeout); - memcpy(ptr, &ip->key.dsize, sizeof(ip->key.dsize)); /* Size of key */ - ptr += sizeof(ip->key.dsize); - memcpy(ptr, ip->key.dptr, ip->key.dsize); /* Key data */ - ptr += ip->key.dsize; - ip = ip->next; - } - - if ((err = (*dav_hooks_db_dbm.store)(lockdb->info->db, - key, val)) != NULL) { - /* ### more details? add an error_id? */ - return dav_push_error(lockdb->info->pool, - HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_LOCK_SAVE_LOCK, - "Could not save lock information.", - err); - } - - return NULL; -} - -/* -** dav_load_lock_record: Reads lock information about key from lock db; -** creates linked lists of the direct and indirect locks. -** -** If add_method = DAV_APPEND_LIST, the result will be appended to the -** head of the direct and indirect lists supplied. -** -** Passive lock removal: If lock has timed out, it will not be returned. -** ### How much "logging" does RFC 2518 require? -*/ -static dav_error * dav_fs_load_lock_record(dav_lockdb *lockdb, dav_datum key, - int add_method, - dav_lock_discovery **direct, - dav_lock_indirect **indirect) -{ - apr_pool_t *p = lockdb->info->pool; - dav_error *err; - apr_size_t offset = 0; - int need_save = DAV_FALSE; - dav_datum val = { 0 }; - dav_lock_discovery *dp; - dav_lock_indirect *ip; - dav_buffer buf = { 0 }; - - if (add_method != DAV_APPEND_LIST) { - *direct = NULL; - *indirect = NULL; - } - - if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) { - /* ### add a higher-level error? */ - return err; - } - - /* - ** If we opened readonly and the db wasn't there, then there are no - ** locks for this resource. Just exit. - */ - if (lockdb->info->db == NULL) - return NULL; - - if ((err = (*dav_hooks_db_dbm.fetch)(lockdb->info->db, key, &val)) != NULL) - return err; - - if (!val.dsize) - return NULL; - - while (offset < val.dsize) { - switch (*(val.dptr + offset++)) { - case DAV_LOCK_DIRECT: - /* Create and fill a dav_lock_discovery structure */ - - dp = apr_pcalloc(p, sizeof(*dp)); - memcpy(dp, val.dptr + offset, sizeof(dp->f)); - offset += sizeof(dp->f); - dp->locktoken = apr_palloc(p, sizeof(*dp->locktoken)); - memcpy(dp->locktoken, val.dptr + offset, sizeof(*dp->locktoken)); - offset += sizeof(*dp->locktoken); - if (*(val.dptr + offset) == '\0') { - ++offset; - } - else { - dp->owner = apr_pstrdup(p, val.dptr + offset); - offset += strlen(dp->owner) + 1; - } - - if (*(val.dptr + offset) == '\0') { - ++offset; - } - else { - dp->auth_user = apr_pstrdup(p, val.dptr + offset); - offset += strlen(dp->auth_user) + 1; - } - - if (!dav_fs_lock_expired(dp->f.timeout)) { - dp->next = *direct; - *direct = dp; - } - else { - need_save = DAV_TRUE; - - /* Remove timed-out locknull fm .locknull list */ - if (*key.dptr == DAV_TYPE_FNAME) { - const char *fname = key.dptr + 1; - apr_finfo_t finfo; - - /* if we don't see the file, then it's a locknull */ - if (apr_lstat(&finfo, fname, APR_FINFO_NORM, p) != APR_SUCCESS) { - if ((err = dav_fs_remove_locknull_member(p, fname, &buf)) != NULL) { - /* ### push a higher-level description? */ - return err; - } - } - } - } - break; - - case DAV_LOCK_INDIRECT: - /* Create and fill a dav_lock_indirect structure */ - - ip = apr_pcalloc(p, sizeof(*ip)); - ip->locktoken = apr_palloc(p, sizeof(*ip->locktoken)); - memcpy(ip->locktoken, val.dptr + offset, sizeof(*ip->locktoken)); - offset += sizeof(*ip->locktoken); - memcpy(&ip->timeout, val.dptr + offset, sizeof(ip->timeout)); - offset += sizeof(ip->timeout); - ip->key.dsize = *((int *) (val.dptr + offset)); /* length of datum */ - offset += sizeof(ip->key.dsize); - ip->key.dptr = apr_palloc(p, ip->key.dsize); - memcpy(ip->key.dptr, val.dptr + offset, ip->key.dsize); - offset += ip->key.dsize; - - if (!dav_fs_lock_expired(ip->timeout)) { - ip->next = *indirect; - *indirect = ip; - } - else { - need_save = DAV_TRUE; - /* A locknull resource will never be locked indirectly */ - } - - break; - - default: - (*dav_hooks_db_dbm.freedatum)(lockdb->info->db, val); - - /* ### should use a computed_desc and insert corrupt token data */ - --offset; - return dav_new_error(p, - HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_LOCK_CORRUPT_DB, - apr_psprintf(p, - "The lock database was found to " - "be corrupt. offset %" - APR_SIZE_T_FMT ", c=%02x", - offset, val.dptr[offset])); - } - } - - (*dav_hooks_db_dbm.freedatum)(lockdb->info->db, val); - - /* Clean up this record if we found expired locks */ - /* - ** ### shouldn't do this if we've been opened READONLY. elide the - ** ### timed-out locks from the response, but don't save that info back - */ - if (need_save == DAV_TRUE) { - return dav_fs_save_lock_record(lockdb, key, *direct, *indirect); - } - - return NULL; -} - -/* resolve <indirect>, returning <*direct> */ -static dav_error * dav_fs_resolve(dav_lockdb *lockdb, - dav_lock_indirect *indirect, - dav_lock_discovery **direct, - dav_lock_discovery **ref_dp, - dav_lock_indirect **ref_ip) -{ - dav_error *err; - dav_lock_discovery *dir; - dav_lock_indirect *ind; - - if ((err = dav_fs_load_lock_record(lockdb, indirect->key, - DAV_CREATE_LIST, - &dir, &ind)) != NULL) { - /* ### insert a higher-level description? */ - return err; - } - if (ref_dp != NULL) { - *ref_dp = dir; - *ref_ip = ind; - } - - for (; dir != NULL; dir = dir->next) { - if (!dav_compare_locktoken(indirect->locktoken, dir->locktoken)) { - *direct = dir; - return NULL; - } - } - - /* No match found (but we should have found one!) */ - - /* ### use a different description and/or error ID? */ - return dav_new_error(lockdb->info->pool, - HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_LOCK_CORRUPT_DB, - "The lock database was found to be corrupt. " - "An indirect lock's direct lock could not " - "be found."); -} - -/* --------------------------------------------------------------- -** -** Property-related lock functions -** -*/ - -/* -** dav_fs_get_supportedlock: Returns a static string for all supportedlock -** properties. I think we save more returning a static string than -** constructing it every time, though it might look cleaner. -*/ -static const char *dav_fs_get_supportedlock(const dav_resource *resource) -{ - static const char supported[] = DEBUG_CR - "<D:lockentry>" DEBUG_CR - "<D:lockscope><D:exclusive/></D:lockscope>" DEBUG_CR - "<D:locktype><D:write/></D:locktype>" DEBUG_CR - "</D:lockentry>" DEBUG_CR - "<D:lockentry>" DEBUG_CR - "<D:lockscope><D:shared/></D:lockscope>" DEBUG_CR - "<D:locktype><D:write/></D:locktype>" DEBUG_CR - "</D:lockentry>" DEBUG_CR; - - return supported; -} - -/* --------------------------------------------------------------- -** -** General lock functions -** -*/ - -/* --------------------------------------------------------------- -** -** Functions dealing with lock-null resources -** -*/ - -/* -** dav_fs_load_locknull_list: Returns a dav_buffer dump of the locknull file -** for the given directory. -*/ -static dav_error * dav_fs_load_locknull_list(apr_pool_t *p, const char *dirpath, - dav_buffer *pbuf) -{ - apr_finfo_t finfo; - apr_file_t *file = NULL; - dav_error *err = NULL; - apr_size_t amt; - - dav_buffer_init(p, pbuf, dirpath); - - if (pbuf->buf[pbuf->cur_len - 1] == '/') - pbuf->buf[--pbuf->cur_len] = '\0'; - - dav_buffer_place(p, pbuf, "/" DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE); - - /* reset this in case we leave w/o reading into the buffer */ - pbuf->cur_len = 0; - - if (apr_file_open(&file, pbuf->buf, APR_READ | APR_BINARY, APR_OS_DEFAULT, - p) != APR_SUCCESS) { - return NULL; - } - - if (apr_file_info_get(&finfo, APR_FINFO_NORM, file) != APR_SUCCESS) { - err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(p, - "Opened but could not stat file %s", - pbuf->buf)); - goto loaderror; - } - - dav_set_bufsize(p, pbuf, finfo.size); - amt = finfo.size; - if (apr_file_read(file, pbuf->buf, &amt) != APR_SUCCESS - || amt != finfo.size) { - err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(p, - "Failure reading locknull file " - "for %s", dirpath)); - - /* just in case the caller disregards the returned error */ - pbuf->cur_len = 0; - goto loaderror; - } - - loaderror: - apr_file_close(file); - return err; -} - -/* -** dav_fs_save_locknull_list: Saves contents of pbuf into the -** locknull file for dirpath. -*/ -static dav_error * dav_fs_save_locknull_list(apr_pool_t *p, const char *dirpath, - dav_buffer *pbuf) -{ - const char *pathname; - apr_file_t *file = NULL; - dav_error *err = NULL; - apr_size_t amt; - - if (pbuf->buf == NULL) - return NULL; - - dav_fs_ensure_state_dir(p, dirpath); - pathname = apr_pstrcat(p, - dirpath, - dirpath[strlen(dirpath) - 1] == '/' ? "" : "/", - DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE, - NULL); - - if (pbuf->cur_len == 0) { - /* delete the file if cur_len == 0 */ - if (apr_file_remove(pathname, p) != 0) { - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(p, - "Error removing %s", pathname)); - } - return NULL; - } - - if (apr_file_open(&file, pathname, - APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY, - APR_OS_DEFAULT, p) != APR_SUCCESS) { - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(p, - "Error opening %s for writing", - pathname)); - } - - amt = pbuf->cur_len; - if (apr_file_write(file, pbuf->buf, &amt) != APR_SUCCESS - || amt != pbuf->cur_len) { - err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(p, - "Error writing %" APR_SIZE_T_FMT - " bytes to %s", - pbuf->cur_len, pathname)); - } - - apr_file_close(file); - return err; -} - -/* -** dav_fs_remove_locknull_member: Removes filename from the locknull list -** for directory path. -*/ -static dav_error * dav_fs_remove_locknull_member(apr_pool_t *p, - const char *filename, - dav_buffer *pbuf) -{ - dav_error *err; - apr_size_t len; - apr_size_t scanlen; - char *scan; - const char *scanend; - char *dirpath = apr_pstrdup(p, filename); - char *fname = strrchr(dirpath, '/'); - int dirty = 0; - - if (fname != NULL) - *fname++ = '\0'; - else - fname = dirpath; - len = strlen(fname) + 1; - - if ((err = dav_fs_load_locknull_list(p, dirpath, pbuf)) != NULL) { - /* ### add a higher level description? */ - return err; - } - - for (scan = pbuf->buf, scanend = scan + pbuf->cur_len; - scan < scanend; - scan += scanlen) { - scanlen = strlen(scan) + 1; - if (len == scanlen && memcmp(fname, scan, scanlen) == 0) { - pbuf->cur_len -= scanlen; - memmove(scan, scan + scanlen, scanend - (scan + scanlen)); - dirty = 1; - break; - } - } - - if (dirty) { - if ((err = dav_fs_save_locknull_list(p, dirpath, pbuf)) != NULL) { - /* ### add a higher level description? */ - return err; - } - } - - return NULL; -} - -/* Note: used by dav_fs_repos.c */ -dav_error * dav_fs_get_locknull_members( - const dav_resource *resource, - dav_buffer *pbuf) -{ - const char *dirpath; - - dav_fs_dir_file_name(resource, &dirpath, NULL); - return dav_fs_load_locknull_list(dav_fs_pool(resource), dirpath, pbuf); -} - -/* ### fold into append_lock? */ -/* ### take an optional buf parameter? */ -static dav_error * dav_fs_add_locknull_state( - dav_lockdb *lockdb, - const dav_resource *resource) -{ - dav_buffer buf = { 0 }; - apr_pool_t *p = lockdb->info->pool; - const char *dirpath; - const char *fname; - dav_error *err; - - dav_fs_dir_file_name(resource, &dirpath, &fname); - - if ((err = dav_fs_load_locknull_list(p, dirpath, &buf)) != NULL) { - return dav_push_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not load .locknull file.", err); - } - - dav_buffer_append(p, &buf, fname); - buf.cur_len++; /* we want the null-term here */ - - if ((err = dav_fs_save_locknull_list(p, dirpath, &buf)) != NULL) { - return dav_push_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not save .locknull file.", err); - } - - return NULL; -} - -/* -** dav_fs_remove_locknull_state: Given a request, check to see if r->filename -** is/was a lock-null resource. If so, return it to an existant state. -** -** ### this function is broken... it doesn't check! -** -** In this implementation, this involves two things: -** (a) remove it from the list in the appropriate .DAV/locknull file -** (b) on *nix, convert the key from a filename to an inode. -*/ -static dav_error * dav_fs_remove_locknull_state( - dav_lockdb *lockdb, - const dav_resource *resource) -{ - dav_buffer buf = { 0 }; - dav_error *err; - apr_pool_t *p = lockdb->info->pool; - const char *pathname = dav_fs_pathname(resource); - - if ((err = dav_fs_remove_locknull_member(p, pathname, &buf)) != NULL) { - /* ### add a higher-level description? */ - return err; - } - -#ifndef WIN32 - { - dav_lock_discovery *ld; - dav_lock_indirect *id; - dav_datum key; - - /* - ** Fetch the lock(s) that made the resource lock-null. Remove - ** them under the filename key. Obtain the new inode key, and - ** save the same lock information under it. - */ - key = dav_fs_build_fname_key(p, pathname); - if ((err = dav_fs_load_lock_record(lockdb, key, DAV_CREATE_LIST, - &ld, &id)) != NULL) { - /* ### insert a higher-level error description */ - return err; - } - - if ((err = dav_fs_save_lock_record(lockdb, key, NULL, NULL)) != NULL) { - /* ### insert a higher-level error description */ - return err; - } - - key = dav_fs_build_key(p, resource); - if ((err = dav_fs_save_lock_record(lockdb, key, ld, id)) != NULL) { - /* ### insert a higher-level error description */ - return err; - } - } -#endif - - return NULL; -} - -static dav_error * dav_fs_create_lock(dav_lockdb *lockdb, - const dav_resource *resource, - dav_lock **lock) -{ - dav_datum key; - - key = dav_fs_build_key(lockdb->info->pool, resource); - - *lock = dav_fs_alloc_lock(lockdb, - key, - NULL); - - (*lock)->is_locknull = !resource->exists; - - return NULL; -} - -static dav_error * dav_fs_get_locks(dav_lockdb *lockdb, - const dav_resource *resource, - int calltype, - dav_lock **locks) -{ - apr_pool_t *p = lockdb->info->pool; - dav_datum key; - dav_error *err; - dav_lock *lock = NULL; - dav_lock *newlock; - dav_lock_discovery *dp; - dav_lock_indirect *ip; - -#if DAV_DEBUG - if (calltype == DAV_GETLOCKS_COMPLETE) { - return dav_new_error(lockdb->info->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "INTERNAL DESIGN ERROR: DAV_GETLOCKS_COMPLETE " - "is not yet supported"); - } -#endif - - key = dav_fs_build_key(p, resource); - if ((err = dav_fs_load_lock_record(lockdb, key, DAV_CREATE_LIST, - &dp, &ip)) != NULL) { - /* ### push a higher-level desc? */ - return err; - } - - /* copy all direct locks to the result list */ - for (; dp != NULL; dp = dp->next) { - newlock = dav_fs_alloc_lock(lockdb, key, dp->locktoken); - newlock->is_locknull = !resource->exists; - newlock->scope = dp->f.scope; - newlock->type = dp->f.type; - newlock->depth = dp->f.depth; - newlock->timeout = dp->f.timeout; - newlock->owner = dp->owner; - newlock->auth_user = dp->auth_user; - - /* hook into the result list */ - newlock->next = lock; - lock = newlock; - } - - /* copy all the indirect locks to the result list. resolve as needed. */ - for (; ip != NULL; ip = ip->next) { - newlock = dav_fs_alloc_lock(lockdb, ip->key, ip->locktoken); - newlock->is_locknull = !resource->exists; - - if (calltype == DAV_GETLOCKS_RESOLVED) { - if ((err = dav_fs_resolve(lockdb, ip, &dp, NULL, NULL)) != NULL) { - /* ### push a higher-level desc? */ - return err; - } - - newlock->scope = dp->f.scope; - newlock->type = dp->f.type; - newlock->depth = dp->f.depth; - newlock->timeout = dp->f.timeout; - newlock->owner = dp->owner; - newlock->auth_user = dp->auth_user; - } - else { - /* DAV_GETLOCKS_PARTIAL */ - newlock->rectype = DAV_LOCKREC_INDIRECT_PARTIAL; - } - - /* hook into the result list */ - newlock->next = lock; - lock = newlock; - } - - *locks = lock; - return NULL; -} - -static dav_error * dav_fs_find_lock(dav_lockdb *lockdb, - const dav_resource *resource, - const dav_locktoken *locktoken, - int partial_ok, - dav_lock **lock) -{ - dav_error *err; - dav_datum key; - dav_lock_discovery *dp; - dav_lock_indirect *ip; - - *lock = NULL; - - key = dav_fs_build_key(lockdb->info->pool, resource); - if ((err = dav_fs_load_lock_record(lockdb, key, DAV_CREATE_LIST, - &dp, &ip)) != NULL) { - /* ### push a higher-level desc? */ - return err; - } - - for (; dp != NULL; dp = dp->next) { - if (!dav_compare_locktoken(locktoken, dp->locktoken)) { - *lock = dav_fs_alloc_lock(lockdb, key, locktoken); - (*lock)->is_locknull = !resource->exists; - (*lock)->scope = dp->f.scope; - (*lock)->type = dp->f.type; - (*lock)->depth = dp->f.depth; - (*lock)->timeout = dp->f.timeout; - (*lock)->owner = dp->owner; - (*lock)->auth_user = dp->auth_user; - return NULL; - } - } - - for (; ip != NULL; ip = ip->next) { - if (!dav_compare_locktoken(locktoken, ip->locktoken)) { - *lock = dav_fs_alloc_lock(lockdb, ip->key, locktoken); - (*lock)->is_locknull = !resource->exists; - - /* ### nobody uses the resolving right now! */ - if (partial_ok) { - (*lock)->rectype = DAV_LOCKREC_INDIRECT_PARTIAL; - } - else { - (*lock)->rectype = DAV_LOCKREC_INDIRECT; - if ((err = dav_fs_resolve(lockdb, ip, &dp, - NULL, NULL)) != NULL) { - /* ### push a higher-level desc? */ - return err; - } - (*lock)->scope = dp->f.scope; - (*lock)->type = dp->f.type; - (*lock)->depth = dp->f.depth; - (*lock)->timeout = dp->f.timeout; - (*lock)->owner = dp->owner; - (*lock)->auth_user = dp->auth_user; - } - return NULL; - } - } - - return NULL; -} - -static dav_error * dav_fs_has_locks(dav_lockdb *lockdb, - const dav_resource *resource, - int *locks_present) -{ - dav_error *err; - dav_datum key; - - *locks_present = 0; - - if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) { - /* ### insert a higher-level error description */ - return err; - } - - /* - ** If we opened readonly and the db wasn't there, then there are no - ** locks for this resource. Just exit. - */ - if (lockdb->info->db == NULL) - return NULL; - - key = dav_fs_build_key(lockdb->info->pool, resource); - - *locks_present = (*dav_hooks_db_dbm.exists)(lockdb->info->db, key); - - return NULL; -} - -static dav_error * dav_fs_append_locks(dav_lockdb *lockdb, - const dav_resource *resource, - int make_indirect, - const dav_lock *lock) -{ - apr_pool_t *p = lockdb->info->pool; - dav_error *err; - dav_lock_indirect *ip; - dav_lock_discovery *dp; - dav_datum key; - - key = dav_fs_build_key(lockdb->info->pool, resource); - if ((err = dav_fs_load_lock_record(lockdb, key, 0, &dp, &ip)) != NULL) { - /* ### maybe add in a higher-level description */ - return err; - } - - /* - ** ### when we store the lock more directly, we need to update - ** ### lock->rectype and lock->is_locknull - */ - - if (make_indirect) { - for (; lock != NULL; lock = lock->next) { - - /* ### this works for any <lock> rectype */ - dav_lock_indirect *newi = apr_pcalloc(p, sizeof(*newi)); - - /* ### shut off the const warning for now */ - newi->locktoken = (dav_locktoken *)lock->locktoken; - newi->timeout = lock->timeout; - newi->key = lock->info->key; - newi->next = ip; - ip = newi; - } - } - else { - for (; lock != NULL; lock = lock->next) { - /* create and link in the right kind of lock */ - - if (lock->rectype == DAV_LOCKREC_DIRECT) { - dav_lock_discovery *newd = apr_pcalloc(p, sizeof(*newd)); - - newd->f.scope = lock->scope; - newd->f.type = lock->type; - newd->f.depth = lock->depth; - newd->f.timeout = lock->timeout; - /* ### shut off the const warning for now */ - newd->locktoken = (dav_locktoken *)lock->locktoken; - newd->owner = lock->owner; - newd->auth_user = lock->auth_user; - newd->next = dp; - dp = newd; - } - else { - /* DAV_LOCKREC_INDIRECT(_PARTIAL) */ - - dav_lock_indirect *newi = apr_pcalloc(p, sizeof(*newi)); - - /* ### shut off the const warning for now */ - newi->locktoken = (dav_locktoken *)lock->locktoken; - newi->key = lock->info->key; - newi->next = ip; - ip = newi; - } - } - } - - if ((err = dav_fs_save_lock_record(lockdb, key, dp, ip)) != NULL) { - /* ### maybe add a higher-level description */ - return err; - } - - /* we have a special list for recording locknull resources */ - /* ### ack! this can add two copies to the locknull list */ - if (!resource->exists - && (err = dav_fs_add_locknull_state(lockdb, resource)) != NULL) { - /* ### maybe add a higher-level description */ - return err; - } - - return NULL; -} - -static dav_error * dav_fs_remove_lock(dav_lockdb *lockdb, - const dav_resource *resource, - const dav_locktoken *locktoken) -{ - dav_error *err; - dav_buffer buf = { 0 }; - dav_lock_discovery *dh = NULL; - dav_lock_indirect *ih = NULL; - dav_datum key; - - key = dav_fs_build_key(lockdb->info->pool, resource); - - if (locktoken != NULL) { - dav_lock_discovery *dp; - dav_lock_discovery *dprev = NULL; - dav_lock_indirect *ip; - dav_lock_indirect *iprev = NULL; - - if ((err = dav_fs_load_lock_record(lockdb, key, DAV_CREATE_LIST, - &dh, &ih)) != NULL) { - /* ### maybe add a higher-level description */ - return err; - } - - for (dp = dh; dp != NULL; dp = dp->next) { - if (dav_compare_locktoken(locktoken, dp->locktoken) == 0) { - if (dprev) - dprev->next = dp->next; - else - dh = dh->next; - } - dprev = dp; - } - - for (ip = ih; ip != NULL; ip = ip->next) { - if (dav_compare_locktoken(locktoken, ip->locktoken) == 0) { - if (iprev) - iprev->next = ip->next; - else - ih = ih->next; - } - iprev = ip; - } - - } - - /* save the modified locks, or remove all locks (dh=ih=NULL). */ - if ((err = dav_fs_save_lock_record(lockdb, key, dh, ih)) != NULL) { - /* ### maybe add a higher-level description */ - return err; - } - - /* - ** If this resource is a locknull resource AND no more locks exist, - ** then remove the locknull member. - ** - ** Note: remove_locknull_state() attempts to convert a locknull member - ** to a real member. In this case, all locks are gone, so the - ** locknull resource returns to the null state (ie. doesn't exist), - ** so there is no need to update the lockdb (and it won't find - ** any because a precondition is that none exist). - */ - if (!resource->exists && dh == NULL && ih == NULL - && (err = dav_fs_remove_locknull_member(lockdb->info->pool, - dav_fs_pathname(resource), - &buf)) != NULL) { - /* ### maybe add a higher-level description */ - return err; - } - - return NULL; -} - -static int dav_fs_do_refresh(dav_lock_discovery *dp, - const dav_locktoken_list *ltl, - time_t new_time) -{ - int dirty = 0; - - for (; ltl != NULL; ltl = ltl->next) { - if (dav_compare_locktoken(dp->locktoken, ltl->locktoken) == 0) - { - dp->f.timeout = new_time; - dirty = 1; - } - } - - return dirty; -} - -static dav_error * dav_fs_refresh_locks(dav_lockdb *lockdb, - const dav_resource *resource, - const dav_locktoken_list *ltl, - time_t new_time, - dav_lock **locks) -{ - dav_error *err; - dav_datum key; - dav_lock_discovery *dp; - dav_lock_discovery *dp_scan; - dav_lock_indirect *ip; - int dirty = 0; - dav_lock *newlock; - - *locks = NULL; - - key = dav_fs_build_key(lockdb->info->pool, resource); - if ((err = dav_fs_load_lock_record(lockdb, key, DAV_CREATE_LIST, - &dp, &ip)) != NULL) { - /* ### maybe add in a higher-level description */ - return err; - } - - /* ### we should be refreshing direct AND (resolved) indirect locks! */ - - /* refresh all of the direct locks on this resource */ - for (dp_scan = dp; dp_scan != NULL; dp_scan = dp_scan->next) { - if (dav_fs_do_refresh(dp_scan, ltl, new_time)) { - /* the lock was refreshed. return the lock. */ - newlock = dav_fs_alloc_lock(lockdb, key, dp_scan->locktoken); - newlock->is_locknull = !resource->exists; - newlock->scope = dp_scan->f.scope; - newlock->type = dp_scan->f.type; - newlock->depth = dp_scan->f.depth; - newlock->timeout = dp_scan->f.timeout; - newlock->owner = dp_scan->owner; - newlock->auth_user = dp_scan->auth_user; - - newlock->next = *locks; - *locks = newlock; - - dirty = 1; - } - } - - /* if we refreshed any locks, then save them back. */ - if (dirty - && (err = dav_fs_save_lock_record(lockdb, key, dp, ip)) != NULL) { - /* ### maybe add in a higher-level description */ - return err; - } - - /* for each indirect lock, find its direct lock and refresh it. */ - for (; ip != NULL; ip = ip->next) { - dav_lock_discovery *ref_dp; - dav_lock_indirect *ref_ip; - - if ((err = dav_fs_resolve(lockdb, ip, &dp_scan, - &ref_dp, &ref_ip)) != NULL) { - /* ### push a higher-level desc? */ - return err; - } - if (dav_fs_do_refresh(dp_scan, ltl, new_time)) { - /* the lock was refreshed. return the lock. */ - newlock = dav_fs_alloc_lock(lockdb, ip->key, dp->locktoken); - newlock->is_locknull = !resource->exists; - newlock->scope = dp->f.scope; - newlock->type = dp->f.type; - newlock->depth = dp->f.depth; - newlock->timeout = dp->f.timeout; - newlock->owner = dp->owner; - newlock->auth_user = dp_scan->auth_user; - - newlock->next = *locks; - *locks = newlock; - - /* save the (resolved) direct lock back */ - if ((err = dav_fs_save_lock_record(lockdb, ip->key, ref_dp, - ref_ip)) != NULL) { - /* ### push a higher-level desc? */ - return err; - } - } - } - - return NULL; -} - - -const dav_hooks_locks dav_hooks_locks_fs = -{ - dav_fs_get_supportedlock, - dav_fs_parse_locktoken, - dav_fs_format_locktoken, - dav_fs_compare_locktoken, - dav_fs_open_lockdb, - dav_fs_close_lockdb, - dav_fs_remove_locknull_state, - dav_fs_create_lock, - dav_fs_get_locks, - dav_fs_find_lock, - dav_fs_has_locks, - dav_fs_append_locks, - dav_fs_remove_lock, - dav_fs_refresh_locks, - NULL, /* get_resource */ -}; diff --git a/modules/dav/fs/mod_dav_fs.c b/modules/dav/fs/mod_dav_fs.c deleted file mode 100644 index 98493d7145..0000000000 --- a/modules/dav/fs/mod_dav_fs.c +++ /dev/null @@ -1,142 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "httpd.h" -#include "http_config.h" - -#include "mod_dav.h" -#include "repos.h" - -/* per-server configuration */ -typedef struct { - const char *lockdb_path; - -} dav_fs_server_conf; - -extern module AP_MODULE_DECLARE_DATA dav_fs_module; - -const char *dav_get_lockdb_path(const request_rec *r) -{ - dav_fs_server_conf *conf; - - conf = ap_get_module_config(r->server->module_config, &dav_fs_module); - return conf->lockdb_path; -} - -static void *dav_fs_create_server_config(apr_pool_t *p, server_rec *s) -{ - return apr_pcalloc(p, sizeof(dav_fs_server_conf)); -} - -static void *dav_fs_merge_server_config(apr_pool_t *p, - void *base, void *overrides) -{ - dav_fs_server_conf *parent = base; - dav_fs_server_conf *child = overrides; - dav_fs_server_conf *newconf; - - newconf = apr_pcalloc(p, sizeof(*newconf)); - - newconf->lockdb_path = - child->lockdb_path ? child->lockdb_path : parent->lockdb_path; - - return newconf; -} - -/* - * Command handler for the DAVLockDB directive, which is TAKE1 - */ -static const char *dav_fs_cmd_davlockdb(cmd_parms *cmd, void *config, - const char *arg1) -{ - dav_fs_server_conf *conf; - - conf = ap_get_module_config(cmd->server->module_config, - &dav_fs_module); - arg1 = ap_os_canonical_filename(cmd->pool, arg1); - conf->lockdb_path = ap_server_root_relative(cmd->pool, arg1); - - return NULL; -} - -static const command_rec dav_fs_cmds[] = -{ - /* per server */ - AP_INIT_TAKE1("DAVLockDB", dav_fs_cmd_davlockdb, NULL, RSRC_CONF, - "specify a lock database"), - - { NULL } -}; - -static void register_hooks(apr_pool_t *p) -{ - dav_hook_gather_propsets(dav_fs_gather_propsets, NULL, NULL, - APR_HOOK_MIDDLE); - dav_hook_find_liveprop(dav_fs_find_liveprop, NULL, NULL, APR_HOOK_MIDDLE); - dav_hook_insert_all_liveprops(dav_fs_insert_all_liveprops, NULL, NULL, - APR_HOOK_MIDDLE); - - dav_fs_register(p); -} - -module AP_MODULE_DECLARE_DATA dav_fs_module = -{ - STANDARD20_MODULE_STUFF, - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - dav_fs_create_server_config, /* server config */ - dav_fs_merge_server_config, /* merge server config */ - dav_fs_cmds, /* command table */ - register_hooks, /* register hooks */ -}; diff --git a/modules/dav/fs/mod_dav_fs.dsp b/modules/dav/fs/mod_dav_fs.dsp deleted file mode 100644 index d81178fd8b..0000000000 --- a/modules/dav/fs/mod_dav_fs.dsp +++ /dev/null @@ -1,119 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_dav_fs" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_dav_fs - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_dav_fs.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_dav_fs.mak" CFG="mod_dav_fs - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_dav_fs - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_dav_fs - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_dav_fs - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\main" /I "..\..\..\srclib\aputil" /I "..\..\..\srclib\sdbm" /I "..\..\..\srclib\expat-lite" /I "..\..\..\srclib\apr\include" /I "../../../srclib/apr-util/include" /I "..\..\..\include" /I "..\..\..\os\win32" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_dav_fs" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_dav_fs.so" /machine:I386 /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav_fs -# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_dav_fs.so" /machine:I386 /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav_fs - -!ELSEIF "$(CFG)" == "mod_dav_fs - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\main" /I "..\..\..\srclib\aputil" /I "..\..\..\srclib\sdbm" /I "..\..\..\srclib\expat-lite" /I "..\..\..\srclib\apr\include" /I "../../../srclib/apr-util/include" /I "..\..\..\include" /I "..\..\..\os\win32" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_dav_fs" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_dav_fs.so" /machine:I386 /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav_fs -# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_dav_fs.so" /machine:I386 /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav_fs - -!ENDIF - -# Begin Target - -# Name "mod_dav_fs - Win32 Release" -# Name "mod_dav_fs - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" -# Begin Source File - -SOURCE=.\dbm.c -# End Source File -# Begin Source File - -SOURCE=.\lock.c -# End Source File -# Begin Source File - -SOURCE=.\mod_dav_fs.c -# End Source File -# Begin Source File - -SOURCE=.\repos.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" -# Begin Source File - -SOURCE=.\repos.h -# End Source File -# End Group -# End Target -# End Project diff --git a/modules/dav/fs/mod_dav_fs.mak b/modules/dav/fs/mod_dav_fs.mak deleted file mode 100644 index bd7b6238ae..0000000000 --- a/modules/dav/fs/mod_dav_fs.mak +++ /dev/null @@ -1,533 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_dav_fs.dsp -!IF "$(CFG)" == "" -CFG=mod_dav_fs - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_dav_fs - Win32 Release. -!ENDIF - -!IF "$(CFG)" != "mod_dav_fs - Win32 Release" && "$(CFG)" !=\ - "mod_dav_fs - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_dav_fs.mak" CFG="mod_dav_fs - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_dav_fs - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_dav_fs - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_dav_fs - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_dav_fs.so" - -!ELSE - -ALL : "mod_dav - Win32 Release" "libhttpd - Win32 Release"\ - "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_dav_fs.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN"\ - "libhttpd - Win32 ReleaseCLEAN" "mod_dav - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\dbm.obj" - -@erase "$(INTDIR)\lock.obj" - -@erase "$(INTDIR)\mod_dav_fs.idb" - -@erase "$(INTDIR)\mod_dav_fs.obj" - -@erase "$(INTDIR)\repos.obj" - -@erase "$(OUTDIR)\mod_dav_fs.exp" - -@erase "$(OUTDIR)\mod_dav_fs.lib" - -@erase "$(OUTDIR)\mod_dav_fs.map" - -@erase "$(OUTDIR)\mod_dav_fs.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\main" /I "..\..\..\srclib\aputil" /I\ - "..\..\..\srclib\sdbm" /I "..\..\..\srclib\expat-lite" /I\ - "..\..\..\srclib\apr\include" /I "../../../srclib/apr-util/include" /I\ - "..\..\..\include" /I "..\..\..\os\win32" /D "NDEBUG" /D "WIN32" /D "_WINDOWS"\ - /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_dav_fs" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_dav_fs.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows\ - /dll /incremental:no /pdb:"$(OUTDIR)\mod_dav_fs.pdb"\ - /map:"$(INTDIR)\mod_dav_fs.map" /machine:I386 /out:"$(OUTDIR)\mod_dav_fs.so"\ - /implib:"$(OUTDIR)\mod_dav_fs.lib"\ - /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav_fs -LINK32_OBJS= \ - "$(INTDIR)\dbm.obj" \ - "$(INTDIR)\lock.obj" \ - "$(INTDIR)\mod_dav_fs.obj" \ - "$(INTDIR)\repos.obj" \ - "..\..\..\Release\libhttpd.lib" \ - "..\..\..\srclib\apr-util\Release\libaprutil.lib" \ - "..\..\..\srclib\apr\Release\libapr.lib" \ - "..\main\Release\mod_dav.lib" - -"$(OUTDIR)\mod_dav_fs.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_dav_fs - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_dav_fs.so" - -!ELSE - -ALL : "mod_dav - Win32 Debug" "libhttpd - Win32 Debug"\ - "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_dav_fs.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN"\ - "libhttpd - Win32 DebugCLEAN" "mod_dav - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\dbm.obj" - -@erase "$(INTDIR)\lock.obj" - -@erase "$(INTDIR)\mod_dav_fs.idb" - -@erase "$(INTDIR)\mod_dav_fs.obj" - -@erase "$(INTDIR)\repos.obj" - -@erase "$(OUTDIR)\mod_dav_fs.exp" - -@erase "$(OUTDIR)\mod_dav_fs.lib" - -@erase "$(OUTDIR)\mod_dav_fs.map" - -@erase "$(OUTDIR)\mod_dav_fs.pdb" - -@erase "$(OUTDIR)\mod_dav_fs.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\main" /I "..\..\..\srclib\aputil"\ - /I "..\..\..\srclib\sdbm" /I "..\..\..\srclib\expat-lite" /I\ - "..\..\..\srclib\apr\include" /I "../../../srclib/apr-util/include" /I\ - "..\..\..\include" /I "..\..\..\os\win32" /D "_DEBUG" /D "WIN32" /D "_WINDOWS"\ - /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_dav_fs" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_dav_fs.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows\ - /dll /incremental:no /pdb:"$(OUTDIR)\mod_dav_fs.pdb"\ - /map:"$(INTDIR)\mod_dav_fs.map" /debug /machine:I386\ - /out:"$(OUTDIR)\mod_dav_fs.so" /implib:"$(OUTDIR)\mod_dav_fs.lib"\ - /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav_fs -LINK32_OBJS= \ - "$(INTDIR)\dbm.obj" \ - "$(INTDIR)\lock.obj" \ - "$(INTDIR)\mod_dav_fs.obj" \ - "$(INTDIR)\repos.obj" \ - "..\..\..\Debug\libhttpd.lib" \ - "..\..\..\srclib\apr-util\Debug\libaprutil.lib" \ - "..\..\..\srclib\apr\Debug\libapr.lib" \ - "..\main\Debug\mod_dav.lib" - -"$(OUTDIR)\mod_dav_fs.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_dav_fs - Win32 Release" || "$(CFG)" ==\ - "mod_dav_fs - Win32 Debug" -SOURCE=.\dbm.c -DEP_CPP_DBM_C=\ - "..\..\..\include\ap_config.h"\ - "..\..\..\include\ap_mmn.h"\ - "..\..\..\include\ap_release.h"\ - "..\..\..\include\httpd.h"\ - "..\..\..\include\pcreposix.h"\ - "..\..\..\include\util_uri.h"\ - "..\..\..\include\util_xml.h"\ - "..\..\..\os\win32\os.h"\ - "..\..\..\srclib\apr-util\include\apr_dbm.h"\ - "..\..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\..\srclib\apr-util\include\apr_xml.h"\ - "..\..\..\srclib\apr-util\include\apu.h"\ - "..\..\..\srclib\apr-util\include\apu_compat.h"\ - "..\..\..\srclib\apr\include\apr.h"\ - "..\..\..\srclib\apr\include\apr_compat.h"\ - "..\..\..\srclib\apr\include\apr_errno.h"\ - "..\..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\..\srclib\apr\include\apr_general.h"\ - "..\..\..\srclib\apr\include\apr_hash.h"\ - "..\..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\..\srclib\apr\include\apr_pools.h"\ - "..\..\..\srclib\apr\include\apr_strings.h"\ - "..\..\..\srclib\apr\include\apr_tables.h"\ - "..\..\..\srclib\apr\include\apr_time.h"\ - "..\..\..\srclib\apr\include\apr_user.h"\ - "..\..\..\srclib\apr\include\apr_want.h"\ - "..\main\mod_dav.h"\ - ".\repos.h"\ - -NODEP_CPP_DBM_C=\ - "..\..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\dbm.obj" : $(SOURCE) $(DEP_CPP_DBM_C) "$(INTDIR)" - - -SOURCE=.\lock.c -DEP_CPP_LOCK_=\ - "..\..\..\include\ap_config.h"\ - "..\..\..\include\ap_mmn.h"\ - "..\..\..\include\ap_release.h"\ - "..\..\..\include\http_log.h"\ - "..\..\..\include\httpd.h"\ - "..\..\..\include\pcreposix.h"\ - "..\..\..\include\util_uri.h"\ - "..\..\..\include\util_xml.h"\ - "..\..\..\os\win32\os.h"\ - "..\..\..\srclib\apr-util\include\apr_dbm.h"\ - "..\..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\..\srclib\apr-util\include\apr_xml.h"\ - "..\..\..\srclib\apr-util\include\apu.h"\ - "..\..\..\srclib\apr-util\include\apu_compat.h"\ - "..\..\..\srclib\apr\include\apr.h"\ - "..\..\..\srclib\apr\include\apr_compat.h"\ - "..\..\..\srclib\apr\include\apr_errno.h"\ - "..\..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\..\srclib\apr\include\apr_general.h"\ - "..\..\..\srclib\apr\include\apr_hash.h"\ - "..\..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\..\srclib\apr\include\apr_pools.h"\ - "..\..\..\srclib\apr\include\apr_strings.h"\ - "..\..\..\srclib\apr\include\apr_tables.h"\ - "..\..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\..\srclib\apr\include\apr_time.h"\ - "..\..\..\srclib\apr\include\apr_user.h"\ - "..\..\..\srclib\apr\include\apr_uuid.h"\ - "..\..\..\srclib\apr\include\apr_want.h"\ - "..\main\mod_dav.h"\ - ".\repos.h"\ - -NODEP_CPP_LOCK_=\ - "..\..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\lock.obj" : $(SOURCE) $(DEP_CPP_LOCK_) "$(INTDIR)" - - -SOURCE=.\mod_dav_fs.c -DEP_CPP_MOD_D=\ - "..\..\..\include\ap_config.h"\ - "..\..\..\include\ap_mmn.h"\ - "..\..\..\include\ap_release.h"\ - "..\..\..\include\http_config.h"\ - "..\..\..\include\httpd.h"\ - "..\..\..\include\pcreposix.h"\ - "..\..\..\include\util_cfgtree.h"\ - "..\..\..\include\util_uri.h"\ - "..\..\..\include\util_xml.h"\ - "..\..\..\os\win32\os.h"\ - "..\..\..\srclib\apr-util\include\apr_dbm.h"\ - "..\..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\..\srclib\apr-util\include\apr_xml.h"\ - "..\..\..\srclib\apr-util\include\apu.h"\ - "..\..\..\srclib\apr-util\include\apu_compat.h"\ - "..\..\..\srclib\apr\include\apr.h"\ - "..\..\..\srclib\apr\include\apr_compat.h"\ - "..\..\..\srclib\apr\include\apr_errno.h"\ - "..\..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\..\srclib\apr\include\apr_general.h"\ - "..\..\..\srclib\apr\include\apr_hash.h"\ - "..\..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\..\srclib\apr\include\apr_pools.h"\ - "..\..\..\srclib\apr\include\apr_tables.h"\ - "..\..\..\srclib\apr\include\apr_time.h"\ - "..\..\..\srclib\apr\include\apr_user.h"\ - "..\..\..\srclib\apr\include\apr_want.h"\ - "..\main\mod_dav.h"\ - ".\repos.h"\ - -NODEP_CPP_MOD_D=\ - "..\..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\mod_dav_fs.obj" : $(SOURCE) $(DEP_CPP_MOD_D) "$(INTDIR)" - - -SOURCE=.\repos.c -DEP_CPP_REPOS=\ - "..\..\..\include\ap_config.h"\ - "..\..\..\include\ap_mmn.h"\ - "..\..\..\include\ap_release.h"\ - "..\..\..\include\http_log.h"\ - "..\..\..\include\http_protocol.h"\ - "..\..\..\include\http_request.h"\ - "..\..\..\include\httpd.h"\ - "..\..\..\include\pcreposix.h"\ - "..\..\..\include\util_filter.h"\ - "..\..\..\include\util_uri.h"\ - "..\..\..\include\util_xml.h"\ - "..\..\..\os\win32\os.h"\ - "..\..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\..\srclib\apr-util\include\apr_dbm.h"\ - "..\..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\..\srclib\apr-util\include\apr_xml.h"\ - "..\..\..\srclib\apr-util\include\apu.h"\ - "..\..\..\srclib\apr-util\include\apu_compat.h"\ - "..\..\..\srclib\apr\include\apr.h"\ - "..\..\..\srclib\apr\include\apr_compat.h"\ - "..\..\..\srclib\apr\include\apr_dso.h"\ - "..\..\..\srclib\apr\include\apr_errno.h"\ - "..\..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\..\srclib\apr\include\apr_general.h"\ - "..\..\..\srclib\apr\include\apr_hash.h"\ - "..\..\..\srclib\apr\include\apr_lock.h"\ - "..\..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\..\srclib\apr\include\apr_pools.h"\ - "..\..\..\srclib\apr\include\apr_portable.h"\ - "..\..\..\srclib\apr\include\apr_strings.h"\ - "..\..\..\srclib\apr\include\apr_tables.h"\ - "..\..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\..\srclib\apr\include\apr_time.h"\ - "..\..\..\srclib\apr\include\apr_user.h"\ - "..\..\..\srclib\apr\include\apr_want.h"\ - "..\main\mod_dav.h"\ - ".\repos.h"\ - -NODEP_CPP_REPOS=\ - "..\..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\repos.obj" : $(SOURCE) $(DEP_CPP_REPOS) "$(INTDIR)" - - -!IF "$(CFG)" == "mod_dav_fs - Win32 Release" - -"libapr - Win32 Release" : - cd "..\../..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Release" - cd "..\..\modules\dav\fs" - -"libapr - Win32 ReleaseCLEAN" : - cd "..\../..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\dav\fs" - -!ELSEIF "$(CFG)" == "mod_dav_fs - Win32 Debug" - -"libapr - Win32 Debug" : - cd "..\../..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Debug" - cd "..\..\modules\dav\fs" - -"libapr - Win32 DebugCLEAN" : - cd "..\../..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\dav\fs" - -!ENDIF - -!IF "$(CFG)" == "mod_dav_fs - Win32 Release" - -"libaprutil - Win32 Release" : - cd "..\../..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"\ - - cd "..\..\modules\dav\fs" - -"libaprutil - Win32 ReleaseCLEAN" : - cd "..\../..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libaprutil.mak"\ - CFG="libaprutil - Win32 Release" RECURSE=1 - cd "..\..\modules\dav\fs" - -!ELSEIF "$(CFG)" == "mod_dav_fs - Win32 Debug" - -"libaprutil - Win32 Debug" : - cd "..\../..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" - cd "..\..\modules\dav\fs" - -"libaprutil - Win32 DebugCLEAN" : - cd "..\../..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libaprutil.mak"\ - CFG="libaprutil - Win32 Debug" RECURSE=1 - cd "..\..\modules\dav\fs" - -!ENDIF - -!IF "$(CFG)" == "mod_dav_fs - Win32 Release" - -"libhttpd - Win32 Release" : - cd "..\../.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Release" - cd ".\modules\dav\fs" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "..\../.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Release"\ - RECURSE=1 - cd ".\modules\dav\fs" - -!ELSEIF "$(CFG)" == "mod_dav_fs - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "..\../.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Debug" - cd ".\modules\dav\fs" - -"libhttpd - Win32 DebugCLEAN" : - cd "..\../.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\dav\fs" - -!ENDIF - -!IF "$(CFG)" == "mod_dav_fs - Win32 Release" - -"mod_dav - Win32 Release" : - cd "..\../..\modules\dav\main" - $(MAKE) /$(MAKEFLAGS) /F .\mod_dav.mak CFG="mod_dav - Win32 Release" - cd "..\fs" - -"mod_dav - Win32 ReleaseCLEAN" : - cd "..\../..\modules\dav\main" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\mod_dav.mak CFG="mod_dav - Win32 Release"\ - RECURSE=1 - cd "..\fs" - -!ELSEIF "$(CFG)" == "mod_dav_fs - Win32 Debug" - -"mod_dav - Win32 Debug" : - cd "..\../..\modules\dav\main" - $(MAKE) /$(MAKEFLAGS) /F .\mod_dav.mak CFG="mod_dav - Win32 Debug" - cd "..\fs" - -"mod_dav - Win32 DebugCLEAN" : - cd "..\../..\modules\dav\main" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\mod_dav.mak CFG="mod_dav - Win32 Debug"\ - RECURSE=1 - cd "..\fs" - -!ENDIF - - -!ENDIF - diff --git a/modules/dav/fs/repos.c b/modules/dav/fs/repos.c deleted file mode 100644 index e8064d1cc7..0000000000 --- a/modules/dav/fs/repos.c +++ /dev/null @@ -1,2077 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* -** DAV filesystem-based repository provider -*/ - -#include "apr.h" -#include "apr_file_io.h" -#include "apr_strings.h" - -#if APR_HAVE_STDIO_H -#include <stdio.h> /* for sprintf() */ -#endif - -#include "httpd.h" -#include "http_log.h" -#include "http_protocol.h" /* for ap_set_* (in dav_fs_set_headers) */ -#include "http_request.h" /* for ap_update_mtime() */ - -#include "mod_dav.h" -#include "repos.h" - - -/* to assist in debugging mod_dav's GET handling */ -#define DEBUG_GET_HANDLER 0 -#define DEBUG_PATHNAME_STYLE 0 - -#define DAV_FS_COPY_BLOCKSIZE 16384 /* copy 16k at a time */ - -/* context needed to identify a resource */ -struct dav_resource_private { - apr_pool_t *pool; /* memory storage pool associated with request */ - const char *pathname; /* full pathname to resource */ - apr_finfo_t finfo; /* filesystem info */ -}; - -/* private context for doing a filesystem walk */ -typedef struct { - /* the input walk parameters */ - const dav_walk_params *params; - - /* reused as we walk */ - dav_walk_resource wres; - - dav_resource res1; - dav_resource_private info1; - dav_buffer path1; - dav_buffer uri_buf; - - /* MOVE/COPY need a secondary path */ - dav_resource res2; - dav_resource_private info2; - dav_buffer path2; - - dav_buffer locknull_buf; - -} dav_fs_walker_context; - -typedef struct { - int is_move; /* is this a MOVE? */ - dav_buffer work_buf; /* handy buffer for copymove_file() */ - - /* CALLBACK: this is a secondary resource managed specially for us */ - const dav_resource *res_dst; - - /* copied from dav_walk_params (they are invariant across the walk) */ - const dav_resource *root; - apr_pool_t *pool; - -} dav_fs_copymove_walk_ctx; - -/* an internal WALKTYPE to walk hidden files (the .DAV directory) */ -#define DAV_WALKTYPE_HIDDEN 0x4000 - -/* an internal WALKTYPE to call collections (again) after their contents */ -#define DAV_WALKTYPE_POSTFIX 0x8000 - -#define DAV_CALLTYPE_POSTFIX 1000 /* a private call type */ - - -/* pull this in from the other source file */ -extern const dav_hooks_locks dav_hooks_locks_fs; - -/* forward-declare the hook structures */ -static const dav_hooks_repository dav_hooks_repository_fs; -static const dav_hooks_liveprop dav_hooks_liveprop_fs; - -/* -** The namespace URIs that we use. This list and the enumeration must -** stay in sync. -*/ -static const char * const dav_fs_namespace_uris[] = -{ - "DAV:", - "http://apache.org/dav/props/", - - NULL /* sentinel */ -}; -enum { - DAV_FS_URI_DAV, /* the DAV: namespace URI */ - DAV_FS_URI_MYPROPS /* the namespace URI for our custom props */ -}; - -/* -** The single property that we define (in the DAV_FS_URI_MYPROPS namespace) -*/ -#define DAV_PROPID_FS_executable 1 - -static const dav_liveprop_spec dav_fs_props[] = -{ - { - DAV_FS_URI_DAV, - "creationdate", - DAV_PROPID_creationdate, - 0 - }, - { - DAV_FS_URI_DAV, - "getcontentlength", - DAV_PROPID_getcontentlength, - 0 - }, - { - DAV_FS_URI_DAV, - "getetag", - DAV_PROPID_getetag, - 0 - }, - { - DAV_FS_URI_DAV, - "getlastmodified", - DAV_PROPID_getlastmodified, - 0 - }, - - { - DAV_FS_URI_MYPROPS, - "executable", - DAV_PROPID_FS_executable, - 0 /* handled special in dav_fs_is_writable */ - }, - - { 0 } /* sentinel */ -}; - -static const dav_liveprop_group dav_fs_liveprop_group = -{ - dav_fs_props, - dav_fs_namespace_uris, - &dav_hooks_liveprop_fs -}; - - -/* define the dav_stream structure for our use */ -struct dav_stream { - apr_pool_t *p; - apr_file_t *f; - const char *pathname; /* we may need to remove it at close time */ -}; - -/* forward declaration for internal treewalkers */ -static dav_error * dav_fs_walk(const dav_walk_params *params, int depth, - dav_response **response); -static dav_error * dav_fs_internal_walk(const dav_walk_params *params, - int depth, int is_move, - const dav_resource *root_dst, - dav_response **response); - -/* -------------------------------------------------------------------- -** -** PRIVATE REPOSITORY FUNCTIONS -*/ -apr_pool_t *dav_fs_pool(const dav_resource *resource) -{ - return resource->info->pool; -} - -const char *dav_fs_pathname(const dav_resource *resource) -{ - return resource->info->pathname; -} - -void dav_fs_dir_file_name( - const dav_resource *resource, - const char **dirpath_p, - const char **fname_p) -{ - dav_resource_private *ctx = resource->info; - - if (resource->collection) { - *dirpath_p = ctx->pathname; - if (fname_p != NULL) - *fname_p = NULL; - } - else { - char *dirpath = ap_make_dirstr_parent(ctx->pool, ctx->pathname); - apr_size_t dirlen = strlen(dirpath); - - if (fname_p != NULL) - *fname_p = ctx->pathname + dirlen; - *dirpath_p = dirpath; - - /* remove trailing slash from dirpath, unless it's the root dir */ - /* ### Win32 check */ - if (dirlen > 1 && dirpath[dirlen - 1] == '/') { - dirpath[dirlen - 1] = '\0'; - } - } -} - -/* Note: picked up from ap_gm_timestr_822() */ -/* NOTE: buf must be at least DAV_TIMEBUF_SIZE chars in size */ -static void dav_format_time(int style, apr_time_t sec, char *buf) -{ - apr_exploded_time_t tms; - - /* ### what to do if fails? */ - (void) apr_explode_gmt(&tms, sec); - - if (style == DAV_STYLE_ISO8601) { - /* ### should we use "-00:00" instead of "Z" ?? */ - - /* 20 chars plus null term */ - sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2dZ", - tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday, - tms.tm_hour, tms.tm_min, tms.tm_sec); - return; - } - - /* RFC 822 date format; as strftime '%a, %d %b %Y %T GMT' */ - - /* 29 chars plus null term */ - sprintf(buf, - "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", - apr_day_snames[tms.tm_wday], - tms.tm_mday, apr_month_snames[tms.tm_mon], - tms.tm_year + 1900, - tms.tm_hour, tms.tm_min, tms.tm_sec); -} - -static dav_error * dav_fs_copymove_file( - int is_move, - apr_pool_t * p, - const char *src, - const char *dst, - dav_buffer *pbuf) -{ - dav_buffer work_buf = { 0 }; - apr_file_t *inf = NULL; - apr_file_t *outf = NULL; - - if (pbuf == NULL) - pbuf = &work_buf; - - dav_set_bufsize(p, pbuf, DAV_FS_COPY_BLOCKSIZE); - - if ((apr_file_open(&inf, src, APR_READ | APR_BINARY, APR_OS_DEFAULT, p)) - != APR_SUCCESS) { - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not open file for reading"); - } - - /* ### do we need to deal with the umask? */ - if ((apr_file_open(&outf, dst, APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY, - APR_OS_DEFAULT, p)) != APR_SUCCESS) { - apr_file_close(inf); - - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not open file for writing"); - } - - while (1) { - apr_size_t len = DAV_FS_COPY_BLOCKSIZE; - apr_status_t status; - - status = apr_file_read(inf, pbuf->buf, &len); - if (status != APR_SUCCESS && status != APR_EOF) { - apr_file_close(inf); - apr_file_close(outf); - - if (apr_file_remove(dst, p) != APR_SUCCESS) { - /* ### ACK! Inconsistent state... */ - - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not delete output after read " - "failure. Server is now in an " - "inconsistent state."); - } - - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not read input file"); - } - - /* write any bytes that were read (applies to APR_EOF, too) */ - if (apr_file_write_full(outf, pbuf->buf, len, NULL) != APR_SUCCESS) { - int save_errno = errno; - - apr_file_close(inf); - apr_file_close(outf); - - if (apr_file_remove(dst, p) != APR_SUCCESS) { - /* ### ACK! Inconsistent state... */ - - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not delete output after write " - "failure. Server is now in an " - "inconsistent state."); - } - - if (save_errno == ENOSPC) { - return dav_new_error(p, HTTP_INSUFFICIENT_STORAGE, 0, - "There is not enough storage to write to " - "this resource."); - } - - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not write output file"); - } - - if (status == APR_EOF) - break; - } - - apr_file_close(inf); - apr_file_close(outf); - - if (is_move && apr_file_remove(src, p) != APR_SUCCESS) { - dav_error *err; - int save_errno = errno; /* save the errno that got us here */ - - if (apr_file_remove(dst, p) != APR_SUCCESS) { - /* ### ACK. this creates an inconsistency. do more!? */ - - /* ### use something besides 500? */ - /* Note that we use the latest errno */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not remove source or destination " - "file. Server is now in an inconsistent " - "state."); - } - - /* ### use something besides 500? */ - err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not remove source file after move. " - "Destination was removed to ensure consistency."); - err->save_errno = save_errno; - return err; - } - - return NULL; -} - -/* copy/move a file from within a state dir to another state dir */ -/* ### need more buffers to replace the pool argument */ -static dav_error * dav_fs_copymove_state( - int is_move, - apr_pool_t * p, - const char *src_dir, const char *src_file, - const char *dst_dir, const char *dst_file, - dav_buffer *pbuf) -{ - apr_finfo_t src_finfo; /* finfo for source file */ - apr_finfo_t dst_state_finfo; /* finfo for STATE directory */ - apr_status_t rv; - const char *src; - const char *dst; - - /* build the propset pathname for the source file */ - src = apr_pstrcat(p, src_dir, "/" DAV_FS_STATE_DIR "/", src_file, NULL); - - /* the source file doesn't exist */ - if (apr_stat(&src_finfo, src, APR_FINFO_NORM, p) != APR_SUCCESS) { - return NULL; - } - - /* build the pathname for the destination state dir */ - dst = apr_pstrcat(p, dst_dir, "/" DAV_FS_STATE_DIR, NULL); - - /* ### do we need to deal with the umask? */ - - /* ensure that it exists */ - rv = apr_dir_make(dst, APR_OS_DEFAULT, p); - if (rv != APR_SUCCESS) { - if (!APR_STATUS_IS_EEXIST(rv)) { - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not create internal state directory"); - } - } - - /* get info about the state directory */ - if (apr_stat(&dst_state_finfo, dst, APR_FINFO_NORM, p) != APR_SUCCESS) { - /* Ack! Where'd it go? */ - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "State directory disappeared"); - } - - /* The mkdir() may have failed because a *file* exists there already */ - if (dst_state_finfo.filetype != APR_DIR) { - /* ### try to recover by deleting this file? (and mkdir again) */ - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "State directory is actually a file"); - } - - /* append the target file to the state directory pathname */ - dst = apr_pstrcat(p, dst, "/", dst_file, NULL); - - /* copy/move the file now */ - if (is_move && src_finfo.device == dst_state_finfo.device) { - /* simple rename is possible since it is on the same device */ - if (apr_file_rename(src, dst, p) != APR_SUCCESS) { - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not move state file."); - } - } - else - { - /* gotta copy (and delete) */ - return dav_fs_copymove_file(is_move, p, src, dst, pbuf); - } - - return NULL; -} - -static dav_error *dav_fs_copymoveset(int is_move, apr_pool_t *p, - const dav_resource *src, - const dav_resource *dst, - dav_buffer *pbuf) -{ - const char *src_dir; - const char *src_file; - const char *src_state1; - const char *src_state2; - const char *dst_dir; - const char *dst_file; - const char *dst_state1; - const char *dst_state2; - dav_error *err; - - /* Get directory and filename for resources */ - dav_fs_dir_file_name(src, &src_dir, &src_file); - dav_fs_dir_file_name(dst, &dst_dir, &dst_file); - - /* Get the corresponding state files for each resource */ - dav_dbm_get_statefiles(p, src_file, &src_state1, &src_state2); - dav_dbm_get_statefiles(p, dst_file, &dst_state1, &dst_state2); -#if DAV_DEBUG - if ((src_state2 != NULL && dst_state2 == NULL) || - (src_state2 == NULL && dst_state2 != NULL)) { - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "DESIGN ERROR: dav_dbm_get_statefiles() " - "returned inconsistent results."); - } -#endif - - err = dav_fs_copymove_state(is_move, p, - src_dir, src_state1, - dst_dir, dst_state1, - pbuf); - - if (err == NULL && src_state2 != NULL) { - err = dav_fs_copymove_state(is_move, p, - src_dir, src_state2, - dst_dir, dst_state2, - pbuf); - - if (err != NULL) { - /* ### CRAP. inconsistency. */ - /* ### should perform some cleanup at the target if we still - ### have the original files */ - - /* Change the error to reflect the bad server state. */ - err->status = HTTP_INTERNAL_SERVER_ERROR; - err->desc = - "Could not fully copy/move the properties. " - "The server is now in an inconsistent state."; - } - } - - return err; -} - -static dav_error *dav_fs_deleteset(apr_pool_t *p, const dav_resource *resource) -{ - const char *dirpath; - const char *fname; - const char *state1; - const char *state2; - const char *pathname; - apr_status_t status; - - /* Get directory, filename, and state-file names for the resource */ - dav_fs_dir_file_name(resource, &dirpath, &fname); - dav_dbm_get_statefiles(p, fname, &state1, &state2); - - /* build the propset pathname for the file */ - pathname = apr_pstrcat(p, - dirpath, - "/" DAV_FS_STATE_DIR "/", - state1, - NULL); - - /* note: we may get ENOENT if the state dir is not present */ - if ((status = apr_file_remove(pathname, p)) != APR_SUCCESS - && !APR_STATUS_IS_ENOENT(status)) { - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not remove properties."); - } - - if (state2 != NULL) { - /* build the propset pathname for the file */ - pathname = apr_pstrcat(p, - dirpath, - "/" DAV_FS_STATE_DIR "/", - state2, - NULL); - - if ((status = apr_file_remove(pathname, p)) != APR_SUCCESS - && !APR_STATUS_IS_ENOENT(status)) { - /* ### CRAP. only removed half. */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not fully remove properties. " - "The server is now in an inconsistent " - "state."); - } - } - - return NULL; -} - -/* -------------------------------------------------------------------- -** -** REPOSITORY HOOK FUNCTIONS -*/ - -static dav_error * dav_fs_get_resource( - request_rec *r, - const char *root_dir, - const char *label, - int use_checked_in, - dav_resource **result_resource) -{ - dav_resource_private *ctx; - dav_resource *resource; - char *s; - char *filename; - apr_size_t len; - - /* ### optimize this into a single allocation! */ - - /* Create private resource context descriptor */ - ctx = apr_pcalloc(r->pool, sizeof(*ctx)); - ctx->finfo = r->finfo; - - /* ### this should go away */ - ctx->pool = r->pool; - - /* Preserve case on OSes which fold canonical filenames */ -#if 0 - /* ### not available in Apache 2.0 yet */ - filename = r->case_preserved_filename; -#else - filename = r->filename; -#endif - - /* - ** If there is anything in the path_info, then this indicates that the - ** entire path was not used to specify the file/dir. We want to append - ** it onto the filename so that we get a "valid" pathname for null - ** resources. - */ - s = apr_pstrcat(r->pool, filename, r->path_info, NULL); - - /* make sure the pathname does not have a trailing "/" */ - len = strlen(s); - if (len > 1 && s[len - 1] == '/') { - s[len - 1] = '\0'; - } - ctx->pathname = s; - - /* Create resource descriptor */ - resource = apr_pcalloc(r->pool, sizeof(*resource)); - resource->type = DAV_RESOURCE_TYPE_REGULAR; - resource->info = ctx; - resource->hooks = &dav_hooks_repository_fs; - resource->pool = r->pool; - - /* make sure the URI does not have a trailing "/" */ - len = strlen(r->uri); - if (len > 1 && r->uri[len - 1] == '/') { - s = apr_pstrdup(r->pool, r->uri); - s[len - 1] = '\0'; - resource->uri = s; - } - else { - resource->uri = r->uri; - } - - if (r->finfo.filetype != 0) { - resource->exists = 1; - resource->collection = r->finfo.filetype == APR_DIR; - - /* unused info in the URL will indicate a null resource */ - - if (r->path_info != NULL && *r->path_info != '\0') { - if (resource->collection) { - /* only a trailing "/" is allowed */ - if (*r->path_info != '/' || r->path_info[1] != '\0') { - - /* - ** This URL/filename represents a locknull resource or - ** possibly a destination of a MOVE/COPY - */ - resource->exists = 0; - resource->collection = 0; - } - } - else - { - /* - ** The base of the path refers to a file -- nothing should - ** be in path_info. The resource is simply an error: it - ** can't be a null or a locknull resource. - */ - return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, - "The URL contains extraneous path " - "components. The resource could not " - "be identified."); - } - - /* retain proper integrity across the structures */ - if (!resource->exists) { - ctx->finfo.filetype = 0; - } - } - } - - *result_resource = resource; - return NULL; -} - -static dav_error * dav_fs_get_parent_resource(const dav_resource *resource, - dav_resource **result_parent) -{ - dav_resource_private *ctx = resource->info; - dav_resource_private *parent_ctx; - dav_resource *parent_resource; - char *dirpath; - - /* If given resource is root, then there is no parent */ - if (strcmp(resource->uri, "/") == 0 || -#ifdef WIN32 - (strlen(ctx->pathname) == 3 && ctx->pathname[1] == ':' && ctx->pathname[2] == '/') -#else - strcmp(ctx->pathname, "/") == 0 -#endif - ) { - *result_parent = NULL; - return NULL; - } - - /* ### optimize this into a single allocation! */ - - /* Create private resource context descriptor */ - parent_ctx = apr_pcalloc(ctx->pool, sizeof(*parent_ctx)); - - /* ### this should go away */ - parent_ctx->pool = ctx->pool; - - dirpath = ap_make_dirstr_parent(ctx->pool, ctx->pathname); - if (strlen(dirpath) > 1 && dirpath[strlen(dirpath) - 1] == '/') - dirpath[strlen(dirpath) - 1] = '\0'; - parent_ctx->pathname = dirpath; - - parent_resource = apr_pcalloc(ctx->pool, sizeof(*parent_resource)); - parent_resource->info = parent_ctx; - parent_resource->collection = 1; - parent_resource->hooks = &dav_hooks_repository_fs; - parent_resource->pool = resource->pool; - - if (resource->uri != NULL) { - char *uri = ap_make_dirstr_parent(ctx->pool, resource->uri); - if (strlen(uri) > 1 && uri[strlen(uri) - 1] == '/') - uri[strlen(uri) - 1] = '\0'; - parent_resource->uri = uri; - } - - if (apr_stat(&parent_ctx->finfo, parent_ctx->pathname, - APR_FINFO_NORM, ctx->pool) == APR_SUCCESS) { - parent_resource->exists = 1; - } - - *result_parent = parent_resource; - return NULL; -} - -static int dav_fs_is_same_resource( - const dav_resource *res1, - const dav_resource *res2) -{ - dav_resource_private *ctx1 = res1->info; - dav_resource_private *ctx2 = res2->info; - - if (res1->hooks != res2->hooks) - return 0; - -#ifdef WIN32 - return stricmp(ctx1->pathname, ctx2->pathname) == 0; -#else - if (ctx1->finfo.filetype != 0) - return ctx1->finfo.inode == ctx2->finfo.inode; - else - return strcmp(ctx1->pathname, ctx2->pathname) == 0; -#endif -} - -static int dav_fs_is_parent_resource( - const dav_resource *res1, - const dav_resource *res2) -{ - dav_resource_private *ctx1 = res1->info; - dav_resource_private *ctx2 = res2->info; - apr_size_t len1 = strlen(ctx1->pathname); - apr_size_t len2; - - if (res1->hooks != res2->hooks) - return 0; - - /* it is safe to use ctx2 now */ - len2 = strlen(ctx2->pathname); - - return (len2 > len1 - && memcmp(ctx1->pathname, ctx2->pathname, len1) == 0 - && ctx2->pathname[len1] == '/'); -} - -static dav_error * dav_fs_open_stream(const dav_resource *resource, - dav_stream_mode mode, - dav_stream **stream) -{ - apr_pool_t *p = resource->info->pool; - dav_stream *ds = apr_pcalloc(p, sizeof(*ds)); - apr_int32_t flags; - - switch (mode) { - case DAV_MODE_READ: - case DAV_MODE_READ_SEEKABLE: - default: - flags = APR_READ | APR_BINARY; - break; - - case DAV_MODE_WRITE_TRUNC: - flags = APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY; - break; - case DAV_MODE_WRITE_SEEKABLE: - flags = APR_WRITE | APR_CREATE | APR_BINARY; - break; - } - - ds->p = p; - ds->pathname = resource->info->pathname; - if (apr_file_open(&ds->f, ds->pathname, flags, APR_OS_DEFAULT, - ds->p) != APR_SUCCESS) { - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "An error occurred while opening a resource."); - } - - /* (APR registers cleanups for the fd with the pool) */ - - *stream = ds; - return NULL; -} - -static dav_error * dav_fs_close_stream(dav_stream *stream, int commit) -{ - apr_file_close(stream->f); - - if (!commit) { - if (apr_file_remove(stream->pathname, stream->p) != APR_SUCCESS) { - /* ### use a better description? */ - return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, - "There was a problem removing (rolling " - "back) the resource " - "when it was being closed."); - } - } - - return NULL; -} - -static dav_error * dav_fs_read_stream(dav_stream *stream, - void *buf, apr_size_t *bufsize) -{ - if (apr_file_read(stream->f, buf, bufsize) != APR_SUCCESS) { - /* ### use something besides 500? */ - return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, - "An error occurred while reading from a " - "resource."); - } - return NULL; -} - -static dav_error * dav_fs_write_stream(dav_stream *stream, - const void *buf, apr_size_t bufsize) -{ - apr_status_t status; - - status = apr_file_write_full(stream->f, buf, bufsize, NULL); - if (APR_STATUS_IS_ENOSPC(status)) { - return dav_new_error(stream->p, HTTP_INSUFFICIENT_STORAGE, 0, - "There is not enough storage to write to " - "this resource."); - } - else if (status != APR_SUCCESS) { - /* ### use something besides 500? */ - return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, - "An error occurred while writing to a " - "resource."); - } - return NULL; -} - -static dav_error * dav_fs_seek_stream(dav_stream *stream, apr_off_t abs_pos) -{ - if (apr_file_seek(stream->f, APR_SET, &abs_pos) != APR_SUCCESS) { - /* ### should check whether apr_file_seek set abs_pos was set to the - * correct position? */ - /* ### use something besides 500? */ - return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not seek to specified position in the " - "resource."); - } - return NULL; -} - -static dav_error * dav_fs_set_headers(request_rec *r, - const dav_resource *resource) -{ - /* ### this function isn't really used since we have a get_pathname */ -#if DEBUG_GET_HANDLER - if (!resource->exists) - return NULL; - - /* make sure the proper mtime is in the request record */ - ap_update_mtime(r, resource->info->finfo.mtime); - - /* ### note that these use r->filename rather than <resource> */ - ap_set_last_modified(r); - ap_set_etag(r); - - /* we accept byte-ranges */ - apr_table_setn(r->headers_out, "Accept-Ranges", "bytes"); - - /* set up the Content-Length header */ - ap_set_content_length(r, resource->info->finfo.size); - - /* ### how to set the content type? */ - /* ### until this is resolved, the Content-Type header is busted */ - -#endif - - return NULL; -} - -#if DEBUG_PATHNAME_STYLE -static const char * dav_fs_get_pathname( - const dav_resource *resource, - void **free_handle_p) -{ - return resource->info->pathname; -} -#endif - -static void dav_fs_free_file(void *free_handle) -{ - /* nothing to free ... */ -} - -static dav_error * dav_fs_create_collection(dav_resource *resource) -{ - dav_resource_private *ctx = resource->info; - apr_status_t status; - - status = apr_dir_make(ctx->pathname, APR_OS_DEFAULT, ctx->pool); - if (status == ENOSPC) { - return dav_new_error(ctx->pool, HTTP_INSUFFICIENT_STORAGE, 0, - "There is not enough storage to create " - "this collection."); - } - else if (status != APR_SUCCESS) { - /* ### refine this error message? */ - return dav_new_error(ctx->pool, HTTP_FORBIDDEN, 0, - "Unable to create collection."); - } - - /* update resource state to show it exists as a collection */ - resource->exists = 1; - resource->collection = 1; - - return NULL; -} - -static dav_error * dav_fs_copymove_walker(dav_walk_resource *wres, - int calltype) -{ - dav_fs_copymove_walk_ctx *ctx = wres->walk_ctx; - dav_resource_private *srcinfo = wres->resource->info; - dav_resource_private *dstinfo = ctx->res_dst->info; - dav_error *err = NULL; - - if (wres->resource->collection) { - if (calltype == DAV_CALLTYPE_POSTFIX) { - /* Postfix call for MOVE. delete the source dir. - * Note: when copying, we do not enable the postfix-traversal. - */ - /* ### we are ignoring any error here; what should we do? */ - (void) apr_dir_remove(srcinfo->pathname, ctx->pool); - } - else { - /* copy/move of a collection. Create the new, target collection */ - if (apr_dir_make(dstinfo->pathname, APR_OS_DEFAULT, - ctx->pool) != APR_SUCCESS) { - /* ### assume it was a permissions problem */ - /* ### need a description here */ - err = dav_new_error(ctx->pool, HTTP_FORBIDDEN, 0, NULL); - } - } - } - else { - err = dav_fs_copymove_file(ctx->is_move, ctx->pool, - srcinfo->pathname, dstinfo->pathname, - &ctx->work_buf); - /* ### push a higher-level description? */ - } - - /* - ** If we have a "not so bad" error, then it might need to go into a - ** multistatus response. - ** - ** For a MOVE, it will always go into the multistatus. It could be - ** that everything has been moved *except* for the root. Using a - ** multistatus (with no errors for the other resources) will signify - ** this condition. - ** - ** For a COPY, we are traversing in a prefix fashion. If the root fails, - ** then we can just bail out now. - */ - if (err != NULL - && !ap_is_HTTP_SERVER_ERROR(err->status) - && (ctx->is_move - || !dav_fs_is_same_resource(wres->resource, ctx->root))) { - /* ### use errno to generate DAV:responsedescription? */ - dav_add_response(wres, err->status, NULL); - - /* the error is in the multistatus now. do not stop the traversal. */ - return NULL; - } - - return err; -} - -static dav_error *dav_fs_copymove_resource( - int is_move, - const dav_resource *src, - const dav_resource *dst, - int depth, - dav_response **response) -{ - dav_error *err = NULL; - dav_buffer work_buf = { 0 }; - - *response = NULL; - - /* if a collection, recursively copy/move it and its children, - * including the state dirs - */ - if (src->collection) { - dav_walk_params params = { 0 }; - dav_response *multi_status; - - params.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_HIDDEN; - params.func = dav_fs_copymove_walker; - params.pool = src->info->pool; - params.root = src; - - /* params.walk_ctx is managed by dav_fs_internal_walk() */ - - /* postfix is needed for MOVE to delete source dirs */ - if (is_move) - params.walk_type |= DAV_WALKTYPE_POSTFIX; - - /* note that we return the error OR the multistatus. never both */ - - if ((err = dav_fs_internal_walk(¶ms, depth, is_move, dst, - &multi_status)) != NULL) { - /* on a "real" error, then just punt. nothing else to do. */ - return err; - } - - if ((*response = multi_status) != NULL) { - /* some multistatus responses exist. wrap them in a 207 */ - return dav_new_error(src->info->pool, HTTP_MULTI_STATUS, 0, - "Error(s) occurred on some resources during " - "the COPY/MOVE process."); - } - - return NULL; - } - - /* not a collection */ - if ((err = dav_fs_copymove_file(is_move, src->info->pool, - src->info->pathname, dst->info->pathname, - &work_buf)) != NULL) { - /* ### push a higher-level description? */ - return err; - } - - /* copy/move properties as well */ - return dav_fs_copymoveset(is_move, src->info->pool, src, dst, &work_buf); -} - -static dav_error * dav_fs_copy_resource( - const dav_resource *src, - dav_resource *dst, - int depth, - dav_response **response) -{ - dav_error *err; - -#if DAV_DEBUG - if (src->hooks != dst->hooks) { - /* - ** ### strictly speaking, this is a design error; we should not - ** ### have reached this point. - */ - return dav_new_error(src->info->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "DESIGN ERROR: a mix of repositories " - "was passed to copy_resource."); - } -#endif - - if ((err = dav_fs_copymove_resource(0, src, dst, depth, - response)) == NULL) { - - /* update state of destination resource to show it exists */ - dst->exists = 1; - dst->collection = src->collection; - } - - return err; -} - -static dav_error * dav_fs_move_resource( - dav_resource *src, - dav_resource *dst, - dav_response **response) -{ - dav_resource_private *srcinfo = src->info; - dav_resource_private *dstinfo = dst->info; - dav_error *err; - int can_rename = 0; - -#if DAV_DEBUG - if (src->hooks != dst->hooks) { - /* - ** ### strictly speaking, this is a design error; we should not - ** ### have reached this point. - */ - return dav_new_error(src->info->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "DESIGN ERROR: a mix of repositories " - "was passed to move_resource."); - } -#endif - - /* determine whether a simple rename will work. - * Assume source exists, else we wouldn't get called. - */ - if (dstinfo->finfo.filetype != 0) { - if (dstinfo->finfo.device == srcinfo->finfo.device) { - /* target exists and is on the same device. */ - can_rename = 1; - } - } - else { - const char *dirpath; - apr_finfo_t finfo; - - /* destination does not exist, but the parent directory should, - * so try it - */ - dirpath = ap_make_dirstr_parent(dstinfo->pool, dstinfo->pathname); - if (apr_stat(&finfo, dirpath, APR_FINFO_NORM, dstinfo->pool) == 0 - && finfo.device == srcinfo->finfo.device) { - can_rename = 1; - } - } - - /* if we can't simply rename, then do it the hard way... */ - if (!can_rename) { - if ((err = dav_fs_copymove_resource(1, src, dst, DAV_INFINITY, - response)) == NULL) { - /* update resource states */ - dst->exists = 1; - dst->collection = src->collection; - src->exists = 0; - src->collection = 0; - } - - return err; - } - - /* a rename should work. do it, and move properties as well */ - - /* no multistatus response */ - *response = NULL; - - /* ### APR has no rename? */ - if (apr_file_rename(srcinfo->pathname, dstinfo->pathname, - srcinfo->pool) != APR_SUCCESS) { - /* ### should have a better error than this. */ - return dav_new_error(srcinfo->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not rename resource."); - } - - /* update resource states */ - dst->exists = 1; - dst->collection = src->collection; - src->exists = 0; - src->collection = 0; - - if ((err = dav_fs_copymoveset(1, src->info->pool, - src, dst, NULL)) == NULL) { - /* no error. we're done. go ahead and return now. */ - return NULL; - } - - /* error occurred during properties move; try to put resource back */ - if (apr_file_rename(dstinfo->pathname, srcinfo->pathname, - srcinfo->pool) != APR_SUCCESS) { - /* couldn't put it back! */ - return dav_push_error(srcinfo->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "The resource was moved, but a failure " - "occurred during the move of its " - "properties. The resource could not be " - "restored to its original location. The " - "server is now in an inconsistent state.", - err); - } - - /* update resource states again */ - src->exists = 1; - src->collection = dst->collection; - dst->exists = 0; - dst->collection = 0; - - /* resource moved back, but properties may be inconsistent */ - return dav_push_error(srcinfo->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "The resource was moved, but a failure " - "occurred during the move of its properties. " - "The resource was moved back to its original " - "location, but its properties may have been " - "partially moved. The server may be in an " - "inconsistent state.", - err); -} - -static dav_error * dav_fs_delete_walker(dav_walk_resource *wres, int calltype) -{ - dav_resource_private *info = wres->resource->info; - - /* do not attempt to remove a null resource, - * or a collection with children - */ - if (wres->resource->exists && - (!wres->resource->collection || calltype == DAV_CALLTYPE_POSTFIX)) { - /* try to remove the resource */ - apr_status_t result; - - result = wres->resource->collection - ? apr_dir_remove(info->pathname, wres->pool) - : apr_file_remove(info->pathname, wres->pool); - - /* - ** If an error occurred, then add it to multistatus response. - ** Note that we add it for the root resource, too. It is quite - ** possible to delete the whole darn tree, yet fail on the root. - ** - ** (also: remember we are deleting via a postfix traversal) - */ - if (result != APR_SUCCESS) { - /* ### assume there is a permissions problem */ - - /* ### use errno to generate DAV:responsedescription? */ - dav_add_response(wres, HTTP_FORBIDDEN, NULL); - } - } - - return NULL; -} - -static dav_error * dav_fs_remove_resource(dav_resource *resource, - dav_response **response) -{ - dav_resource_private *info = resource->info; - - *response = NULL; - - /* if a collection, recursively remove it and its children, - * including the state dirs - */ - if (resource->collection) { - dav_walk_params params = { 0 }; - dav_error *err = NULL; - dav_response *multi_status; - - params.walk_type = (DAV_WALKTYPE_NORMAL - | DAV_WALKTYPE_HIDDEN - | DAV_WALKTYPE_POSTFIX); - params.func = dav_fs_delete_walker; - params.pool = info->pool; - params.root = resource; - - if ((err = dav_fs_walk(¶ms, DAV_INFINITY, - &multi_status)) != NULL) { - /* on a "real" error, then just punt. nothing else to do. */ - return err; - } - - if ((*response = multi_status) != NULL) { - /* some multistatus responses exist. wrap them in a 207 */ - return dav_new_error(info->pool, HTTP_MULTI_STATUS, 0, - "Error(s) occurred on some resources during " - "the deletion process."); - } - - /* no errors... update resource state */ - resource->exists = 0; - resource->collection = 0; - - return NULL; - } - - /* not a collection; remove the file and its properties */ - if (apr_file_remove(info->pathname, info->pool) != APR_SUCCESS) { - /* ### put a description in here */ - return dav_new_error(info->pool, HTTP_FORBIDDEN, 0, NULL); - } - - /* update resource state */ - resource->exists = 0; - resource->collection = 0; - - /* remove properties and return its result */ - return dav_fs_deleteset(info->pool, resource); -} - -/* ### move this to dav_util? */ -/* Walk recursively down through directories, * - * including lock-null resources as we go. */ -static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) -{ - const dav_walk_params *params = fsctx->params; - apr_pool_t *pool = params->pool; - dav_error *err = NULL; - int isdir = fsctx->res1.collection; - apr_finfo_t dirent; - apr_dir_t *dirp; - - /* ensure the context is prepared properly, then call the func */ - err = (*params->func)(&fsctx->wres, - isdir - ? DAV_CALLTYPE_COLLECTION - : DAV_CALLTYPE_MEMBER); - if (err != NULL) { - return err; - } - - if (depth == 0 || !isdir) { - return NULL; - } - - /* put a trailing slash onto the directory, in preparation for appending - * files to it as we discovery them within the directory */ - dav_check_bufsize(pool, &fsctx->path1, DAV_BUFFER_PAD); - fsctx->path1.buf[fsctx->path1.cur_len++] = '/'; - fsctx->path1.buf[fsctx->path1.cur_len] = '\0'; /* in pad area */ - - /* if a secondary path is present, then do that, too */ - if (fsctx->path2.buf != NULL) { - dav_check_bufsize(pool, &fsctx->path2, DAV_BUFFER_PAD); - fsctx->path2.buf[fsctx->path2.cur_len++] = '/'; - fsctx->path2.buf[fsctx->path2.cur_len] = '\0'; /* in pad area */ - } - - /* Note: the URI should ALREADY have a trailing "/" */ - - /* for this first pass of files, all resources exist */ - fsctx->res1.exists = 1; - - /* a file is the default; we'll adjust if we hit a directory */ - fsctx->res1.collection = 0; - fsctx->res2.collection = 0; - - /* open and scan the directory */ - if ((apr_dir_open(&dirp, fsctx->path1.buf, pool)) != APR_SUCCESS) { - /* ### need a better error */ - return dav_new_error(pool, HTTP_NOT_FOUND, 0, NULL); - } - while ((apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp)) == APR_SUCCESS) { - apr_size_t len; - - len = strlen(dirent.name); - - /* avoid recursing into our current, parent, or state directories */ - if (dirent.name[0] == '.' - && (len == 1 || (dirent.name[1] == '.' && len == 2))) { - continue; - } - - if (params->walk_type & DAV_WALKTYPE_AUTH) { - /* ### need to authorize each file */ - /* ### example: .htaccess is normally configured to fail auth */ - - /* stuff in the state directory is never authorized! */ - if (!strcmp(dirent.name, DAV_FS_STATE_DIR)) { - continue; - } - } - /* skip the state dir unless a HIDDEN is performed */ - if (!(params->walk_type & DAV_WALKTYPE_HIDDEN) - && !strcmp(dirent.name, DAV_FS_STATE_DIR)) { - continue; - } - - /* append this file onto the path buffer (copy null term) */ - dav_buffer_place_mem(pool, &fsctx->path1, dirent.name, len + 1, 0); - - - /* ### Optimize me, dirent can give us what we need! */ - if (apr_lstat(&fsctx->info1.finfo, fsctx->path1.buf, - APR_FINFO_NORM, pool) != APR_SUCCESS) { - /* woah! where'd it go? */ - /* ### should have a better error here */ - err = dav_new_error(pool, HTTP_NOT_FOUND, 0, NULL); - break; - } - - /* copy the file to the URI, too. NOTE: we will pad an extra byte - for the trailing slash later. */ - dav_buffer_place_mem(pool, &fsctx->uri_buf, dirent.name, len + 1, 1); - - /* if there is a secondary path, then do that, too */ - if (fsctx->path2.buf != NULL) { - dav_buffer_place_mem(pool, &fsctx->path2, dirent.name, len + 1, 0); - } - - /* set up the (internal) pathnames for the two resources */ - fsctx->info1.pathname = fsctx->path1.buf; - fsctx->info2.pathname = fsctx->path2.buf; - - /* set up the URI for the current resource */ - fsctx->res1.uri = fsctx->uri_buf.buf; - - /* ### for now, only process regular files (e.g. skip symlinks) */ - if (fsctx->info1.finfo.filetype == APR_REG) { - /* call the function for the specified dir + file */ - if ((err = (*params->func)(&fsctx->wres, - DAV_CALLTYPE_MEMBER)) != NULL) { - /* ### maybe add a higher-level description? */ - break; - } - } - else if (fsctx->info1.finfo.filetype == APR_DIR) { - apr_size_t save_path_len = fsctx->path1.cur_len; - apr_size_t save_uri_len = fsctx->uri_buf.cur_len; - apr_size_t save_path2_len = fsctx->path2.cur_len; - - /* adjust length to incorporate the subdir name */ - fsctx->path1.cur_len += len; - fsctx->path2.cur_len += len; - - /* adjust URI length to incorporate subdir and a slash */ - fsctx->uri_buf.cur_len += len + 1; - fsctx->uri_buf.buf[fsctx->uri_buf.cur_len - 1] = '/'; - fsctx->uri_buf.buf[fsctx->uri_buf.cur_len] = '\0'; - - /* switch over to a collection */ - fsctx->res1.collection = 1; - fsctx->res2.collection = 1; - - /* recurse on the subdir */ - /* ### don't always want to quit on error from single child */ - if ((err = dav_fs_walker(fsctx, depth - 1)) != NULL) { - /* ### maybe add a higher-level description? */ - break; - } - - /* put the various information back */ - fsctx->path1.cur_len = save_path_len; - fsctx->path2.cur_len = save_path2_len; - fsctx->uri_buf.cur_len = save_uri_len; - - fsctx->res1.collection = 0; - fsctx->res2.collection = 0; - - /* assert: res1.exists == 1 */ - } - } - - /* ### check the return value of this? */ - apr_dir_close(dirp); - - if (err != NULL) - return err; - - if (params->walk_type & DAV_WALKTYPE_LOCKNULL) { - apr_size_t offset = 0; - - /* null terminate the directory name */ - fsctx->path1.buf[fsctx->path1.cur_len - 1] = '\0'; - - /* Include any lock null resources found in this collection */ - fsctx->res1.collection = 1; - if ((err = dav_fs_get_locknull_members(&fsctx->res1, - &fsctx->locknull_buf)) != NULL) { - /* ### maybe add a higher-level description? */ - return err; - } - - /* put a slash back on the end of the directory */ - fsctx->path1.buf[fsctx->path1.cur_len - 1] = '/'; - - /* these are all non-existant (files) */ - fsctx->res1.exists = 0; - fsctx->res1.collection = 0; - memset(&fsctx->info1.finfo, 0, sizeof(fsctx->info1.finfo)); - - while (offset < fsctx->locknull_buf.cur_len) { - apr_size_t len = strlen(fsctx->locknull_buf.buf + offset); - dav_lock *locks = NULL; - - /* - ** Append the locknull file to the paths and the URI. Note that - ** we don't have to pad the URI for a slash since a locknull - ** resource is not a collection. - */ - dav_buffer_place_mem(pool, &fsctx->path1, - fsctx->locknull_buf.buf + offset, len + 1, 0); - dav_buffer_place_mem(pool, &fsctx->uri_buf, - fsctx->locknull_buf.buf + offset, len + 1, 0); - if (fsctx->path2.buf != NULL) { - dav_buffer_place_mem(pool, &fsctx->path2, - fsctx->locknull_buf.buf + offset, - len + 1, 0); - } - - /* set up the (internal) pathnames for the two resources */ - fsctx->info1.pathname = fsctx->path1.buf; - fsctx->info2.pathname = fsctx->path2.buf; - - /* set up the URI for the current resource */ - fsctx->res1.uri = fsctx->uri_buf.buf; - - /* - ** To prevent a PROPFIND showing an expired locknull - ** resource, query the lock database to force removal - ** of both the lock entry and .locknull, if necessary.. - ** Sure, the query in PROPFIND would do this.. after - ** the locknull resource was already included in the - ** return. - ** - ** NOTE: we assume the caller has opened the lock database - ** if they have provided DAV_WALKTYPE_LOCKNULL. - */ - /* ### we should also look into opening it read-only and - ### eliding timed-out items from the walk, yet leaving - ### them in the locknull database until somebody opens - ### the thing writable. - */ - /* ### probably ought to use has_locks. note the problem - ### mentioned above, though... we would traverse this as - ### a locknull, but then a PROPFIND would load the lock - ### info, causing a timeout and the locks would not be - ### reported. Therefore, a null resource would be returned - ### in the PROPFIND. - ### - ### alternative: just load unresolved locks. any direct - ### locks will be timed out (correct). any indirect will - ### not (correct; consider if a parent timed out -- the - ### timeout routines do not walk and remove indirects; - ### even the resolve func would probably fail when it - ### tried to find a timed-out direct lock). - */ - if ((err = dav_lock_query(params->lockdb, &fsctx->res1, - &locks)) != NULL) { - /* ### maybe add a higher-level description? */ - return err; - } - - /* call the function for the specified dir + file */ - if (locks != NULL && - (err = (*params->func)(&fsctx->wres, - DAV_CALLTYPE_LOCKNULL)) != NULL) { - /* ### maybe add a higher-level description? */ - return err; - } - - offset += len + 1; - } - - /* reset the exists flag */ - fsctx->res1.exists = 1; - } - - if (params->walk_type & DAV_WALKTYPE_POSTFIX) { - /* replace the dirs' trailing slashes with null terms */ - fsctx->path1.buf[--fsctx->path1.cur_len] = '\0'; - fsctx->uri_buf.buf[--fsctx->uri_buf.cur_len] = '\0'; - if (fsctx->path2.buf != NULL) { - fsctx->path2.buf[--fsctx->path2.cur_len] = '\0'; - } - - /* this is a collection which exists */ - fsctx->res1.collection = 1; - - return (*params->func)(&fsctx->wres, DAV_CALLTYPE_POSTFIX); - } - - return NULL; -} - -static dav_error * dav_fs_internal_walk(const dav_walk_params *params, - int depth, int is_move, - const dav_resource *root_dst, - dav_response **response) -{ - dav_fs_walker_context fsctx = { 0 }; - dav_error *err; - dav_fs_copymove_walk_ctx cm_ctx = { 0 }; - -#if DAV_DEBUG - if ((params->walk_type & DAV_WALKTYPE_LOCKNULL) != 0 - && params->lockdb == NULL) { - return dav_new_error(params->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "DESIGN ERROR: walker called to walk locknull " - "resources, but a lockdb was not provided."); - } -#endif - - fsctx.params = params; - fsctx.wres.walk_ctx = params->walk_ctx; - fsctx.wres.pool = params->pool; - - /* ### zero out versioned, working, baselined? */ - - fsctx.res1 = *params->root; - fsctx.res1.pool = params->pool; - - fsctx.res1.info = &fsctx.info1; - fsctx.info1 = *params->root->info; - - /* the pathname is stored in the path1 buffer */ - dav_buffer_init(params->pool, &fsctx.path1, fsctx.info1.pathname); - fsctx.info1.pathname = fsctx.path1.buf; - - if (root_dst != NULL) { - /* internal call from the COPY/MOVE code. set it up. */ - - fsctx.wres.walk_ctx = &cm_ctx; - cm_ctx.is_move = is_move; - cm_ctx.res_dst = &fsctx.res2; - cm_ctx.root = params->root; - cm_ctx.pool = params->pool; - - fsctx.res2 = *root_dst; - fsctx.res2.exists = 0; - fsctx.res2.collection = 0; - fsctx.res2.uri = NULL; /* we don't track this */ - fsctx.res2.pool = params->pool; - - fsctx.res2.info = &fsctx.info2; - fsctx.info2 = *root_dst->info; - - /* res2 does not exist -- clear its finfo structure */ - memset(&fsctx.info2.finfo, 0, sizeof(fsctx.info2.finfo)); - - /* the pathname is stored in the path2 buffer */ - dav_buffer_init(params->pool, &fsctx.path2, fsctx.info2.pathname); - fsctx.info2.pathname = fsctx.path2.buf; - } - - /* prep the URI buffer */ - dav_buffer_init(params->pool, &fsctx.uri_buf, params->root->uri); - - /* if we have a directory, then ensure the URI has a trailing "/" */ - if (fsctx.res1.collection - && fsctx.uri_buf.buf[fsctx.uri_buf.cur_len - 1] != '/') { - - /* this will fall into the pad area */ - fsctx.uri_buf.buf[fsctx.uri_buf.cur_len++] = '/'; - fsctx.uri_buf.buf[fsctx.uri_buf.cur_len] = '\0'; - } - - /* the current resource's URI is stored in the uri_buf buffer */ - fsctx.res1.uri = fsctx.uri_buf.buf; - - /* point the callback's resource at our structure */ - fsctx.wres.resource = &fsctx.res1; - - /* always return the error, and any/all multistatus responses */ - err = dav_fs_walker(&fsctx, depth); - *response = fsctx.wres.response; - return err; -} - -static dav_error * dav_fs_walk(const dav_walk_params *params, int depth, - dav_response **response) -{ - /* always return the error, and any/all multistatus responses */ - return dav_fs_internal_walk(params, depth, 0, NULL, response); -} - -/* dav_fs_etag: Stolen from ap_make_etag. Creates a strong etag - * for file path. - * ### do we need to return weak tags sometimes? - */ -static const char *dav_fs_getetag(const dav_resource *resource) -{ - dav_resource_private *ctx = resource->info; - - if (!resource->exists) - return apr_pstrdup(ctx->pool, ""); - - if (ctx->finfo.filetype != 0) { - return apr_psprintf(ctx->pool, "\"%lx-%lx-%lx\"", - (unsigned long) ctx->finfo.inode, - (unsigned long) ctx->finfo.size, - (unsigned long) ctx->finfo.mtime); - } - - return apr_psprintf(ctx->pool, "\"%lx\"", (unsigned long) ctx->finfo.mtime); -} - -static const dav_hooks_repository dav_hooks_repository_fs = -{ - DEBUG_GET_HANDLER, /* normally: special GET handling not required */ - dav_fs_get_resource, - dav_fs_get_parent_resource, - dav_fs_is_same_resource, - dav_fs_is_parent_resource, - dav_fs_open_stream, - dav_fs_close_stream, - dav_fs_read_stream, - dav_fs_write_stream, - dav_fs_seek_stream, - dav_fs_set_headers, -#if DEBUG_PATHNAME_STYLE - dav_fs_get_pathname, -#else - 0, -#endif - dav_fs_free_file, - dav_fs_create_collection, - dav_fs_copy_resource, - dav_fs_move_resource, - dav_fs_remove_resource, - dav_fs_walk, - dav_fs_getetag, -}; - -static dav_prop_insert dav_fs_insert_prop(const dav_resource *resource, - int propid, dav_prop_insert what, - ap_text_header *phdr) -{ - const char *value; - const char *s; - apr_pool_t *p = resource->info->pool; - const dav_liveprop_spec *info; - int global_ns; - - /* an HTTP-date can be 29 chars plus a null term */ - /* a 64-bit size can be 20 chars plus a null term */ - char buf[DAV_TIMEBUF_SIZE]; - - /* - ** None of FS provider properties are defined if the resource does not - ** exist. Just bail for this case. - ** - ** Even though we state that the FS properties are not defined, the - ** client cannot store dead values -- we deny that thru the is_writable - ** hook function. - */ - if (!resource->exists) - return DAV_PROP_INSERT_NOTDEF; - - switch (propid) { - case DAV_PROPID_creationdate: - /* - ** Closest thing to a creation date. since we don't actually - ** perform the operations that would modify ctime (after we - ** create the file), then we should be pretty safe here. - */ - dav_format_time(DAV_STYLE_ISO8601, - resource->info->finfo.ctime, - buf); - value = buf; - break; - - case DAV_PROPID_getcontentlength: - /* our property, but not defined on collection resources */ - if (resource->collection) - return DAV_PROP_INSERT_NOTDEF; - - (void) sprintf(buf, "%" APR_OFF_T_FMT, resource->info->finfo.size); - value = buf; - break; - - case DAV_PROPID_getetag: - value = dav_fs_getetag(resource); - break; - - case DAV_PROPID_getlastmodified: - dav_format_time(DAV_STYLE_RFC822, - resource->info->finfo.mtime, - buf); - value = buf; - break; - - case DAV_PROPID_FS_executable: - /* our property, but not defined on collection resources */ - if (resource->collection) - return DAV_PROP_INSERT_NOTDEF; - - /* our property, but not defined on this platform */ - if (!(resource->info->finfo.valid & APR_FINFO_UPROT)) - return DAV_PROP_INSERT_NOTDEF; - - /* the files are "ours" so we only need to check owner exec privs */ - if (resource->info->finfo.protection & APR_UEXECUTE) - value = "T"; - else - value = "F"; - break; - - default: - /* ### what the heck was this property? */ - return DAV_PROP_INSERT_NOTDEF; - } - - /* assert: value != NULL */ - - /* get the information and global NS index for the property */ - global_ns = dav_get_liveprop_info(propid, &dav_fs_liveprop_group, &info); - - /* assert: info != NULL && info->name != NULL */ - - /* DBG3("FS: inserting lp%d:%s (local %d)", ns, scan->name, scan->ns); */ - - if (what == DAV_PROP_INSERT_VALUE) { - s = apr_psprintf(p, "<lp%d:%s>%s</lp%d:%s>" DEBUG_CR, - global_ns, info->name, value, global_ns, info->name); - } - else if (what == DAV_PROP_INSERT_NAME) { - s = apr_psprintf(p, "<lp%d:%s/>" DEBUG_CR, global_ns, info->name); - } - else { - /* assert: what == DAV_PROP_INSERT_SUPPORTED */ - s = apr_psprintf(p, - "<D:supported-live-property D:name=\"%s\" " - "D:namespace=\"%s\"/>" DEBUG_CR, - info->name, dav_fs_namespace_uris[info->ns]); - } - ap_text_append(p, phdr, s); - - /* we inserted what was asked for */ - return what; -} - -static int dav_fs_is_writable(const dav_resource *resource, int propid) -{ - const dav_liveprop_spec *info; - -#ifndef WIN32 - /* this property is not usable (writable) on the Win32 platform */ - if (propid == DAV_PROPID_FS_executable && !resource->collection) - return 1; -#endif - - (void) dav_get_liveprop_info(propid, &dav_fs_liveprop_group, &info); - return info->is_writable; -} - -static dav_error *dav_fs_patch_validate(const dav_resource *resource, - const ap_xml_elem *elem, - int operation, - void **context, - int *defer_to_dead) -{ - const ap_text *cdata; - const ap_text *f_cdata; - char value; - dav_elem_private *priv = elem->private; - - if (priv->propid != DAV_PROPID_FS_executable) { - *defer_to_dead = 1; - return NULL; - } - - if (operation == DAV_PROP_OP_DELETE) { - return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, - "The 'executable' property cannot be removed."); - } - - cdata = elem->first_cdata.first; - - /* ### hmm. this isn't actually looking at all the possible text items */ - f_cdata = elem->first_child == NULL - ? NULL - : elem->first_child->following_cdata.first; - - /* DBG3("name=%s cdata=%s f_cdata=%s",elem->name,cdata ? cdata->text : "[null]",f_cdata ? f_cdata->text : "[null]"); */ - - if (cdata == NULL) { - if (f_cdata == NULL) { - return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, - "The 'executable' property expects a single " - "character, valued 'T' or 'F'. There was no " - "value submitted."); - } - cdata = f_cdata; - } - else if (f_cdata != NULL) - goto too_long; - - if (cdata->next != NULL || strlen(cdata->text) != 1) - goto too_long; - - value = cdata->text[0]; - if (value != 'T' && value != 'F') { - return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, - "The 'executable' property expects a single " - "character, valued 'T' or 'F'. The value " - "submitted is invalid."); - } - - *context = (void *)(value == 'T'); - - return NULL; - - too_long: - return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, - "The 'executable' property expects a single " - "character, valued 'T' or 'F'. The value submitted " - "has too many characters."); - -} - -static dav_error *dav_fs_patch_exec(const dav_resource *resource, - const ap_xml_elem *elem, - int operation, - void *context, - dav_liveprop_rollback **rollback_ctx) -{ - int value = context != NULL; - apr_fileperms_t perms = resource->info->finfo.protection; - int old_value = (perms & APR_UEXECUTE) != 0; - - /* assert: prop == executable. operation == SET. */ - - /* don't do anything if there is no change. no rollback info either. */ - /* DBG2("new value=%d (old=%d)", value, old_value); */ - if (value == old_value) - return NULL; - - perms &= ~APR_UEXECUTE; - if (value) - perms |= APR_UEXECUTE; - - if (apr_file_perms_set(resource->info->pathname, perms) != APR_SUCCESS) { - return dav_new_error(resource->info->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not set the executable flag of the " - "target resource."); - } - - /* update the resource and set up the rollback context */ - resource->info->finfo.protection = perms; - *rollback_ctx = (dav_liveprop_rollback *)old_value; - - return NULL; -} - -static void dav_fs_patch_commit(const dav_resource *resource, - int operation, - void *context, - dav_liveprop_rollback *rollback_ctx) -{ - /* nothing to do */ -} - -static dav_error *dav_fs_patch_rollback(const dav_resource *resource, - int operation, - void *context, - dav_liveprop_rollback *rollback_ctx) -{ - apr_fileperms_t perms = resource->info->finfo.protection & ~APR_UEXECUTE; - int value = rollback_ctx != NULL; - - /* assert: prop == executable. operation == SET. */ - - /* restore the executable bit */ - if (value) - perms |= APR_UEXECUTE; - - if (apr_file_perms_set(resource->info->pathname, perms) != APR_SUCCESS) { - return dav_new_error(resource->info->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "After a failure occurred, the resource's " - "executable flag could not be restored."); - } - - /* restore the resource's state */ - resource->info->finfo.protection = perms; - - return NULL; -} - - -static const dav_hooks_liveprop dav_hooks_liveprop_fs = -{ - dav_fs_insert_prop, - dav_fs_is_writable, - dav_fs_namespace_uris, - dav_fs_patch_validate, - dav_fs_patch_exec, - dav_fs_patch_commit, - dav_fs_patch_rollback -}; - -static const dav_provider dav_fs_provider = -{ - &dav_hooks_repository_fs, - &dav_hooks_db_dbm, - &dav_hooks_locks_fs, - NULL, /* vsn */ - NULL /* binding */ -}; - -void dav_fs_gather_propsets(apr_array_header_t *uris) -{ -#ifndef WIN32 - *(const char **)apr_array_push(uris) = - "<http://apache.org/dav/propset/fs/1>"; -#endif -} - -int dav_fs_find_liveprop(const dav_resource *resource, - const char *ns_uri, const char *name, - const dav_hooks_liveprop **hooks) -{ - /* don't try to find any liveprops if this isn't "our" resource */ - if (resource->hooks != &dav_hooks_repository_fs) - return 0; - return dav_do_find_liveprop(ns_uri, name, &dav_fs_liveprop_group, hooks); -} - -void dav_fs_insert_all_liveprops(request_rec *r, const dav_resource *resource, - dav_prop_insert what, ap_text_header *phdr) -{ - /* don't insert any liveprops if this isn't "our" resource */ - if (resource->hooks != &dav_hooks_repository_fs) - return; - - if (!resource->exists) { - /* a lock-null resource */ - /* - ** ### technically, we should insert empty properties. dunno offhand - ** ### what part of the spec said this, but it was essentially thus: - ** ### "the properties should be defined, but may have no value". - */ - return; - } - - (void) dav_fs_insert_prop(resource, DAV_PROPID_creationdate, - what, phdr); - (void) dav_fs_insert_prop(resource, DAV_PROPID_getcontentlength, - what, phdr); - (void) dav_fs_insert_prop(resource, DAV_PROPID_getlastmodified, - what, phdr); - (void) dav_fs_insert_prop(resource, DAV_PROPID_getetag, - what, phdr); - -#ifndef WIN32 - /* - ** Note: this property is not defined on the Win32 platform. - ** dav_fs_insert_prop() won't insert it, but we may as - ** well not even call it. - */ - (void) dav_fs_insert_prop(resource, DAV_PROPID_FS_executable, - what, phdr); -#endif - - /* ### we know the others aren't defined as liveprops */ -} - -void dav_fs_register(apr_pool_t *p) -{ - /* register the namespace URIs */ - dav_register_liveprop_group(p, &dav_fs_liveprop_group); - - /* register the repository provider */ - dav_register_provider(p, "filesystem", &dav_fs_provider); -} diff --git a/modules/dav/fs/repos.h b/modules/dav/fs/repos.h deleted file mode 100644 index 8e69773286..0000000000 --- a/modules/dav/fs/repos.h +++ /dev/null @@ -1,110 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* -** Declarations for the filesystem repository implementation -*/ - -#ifndef _DAV_FS_REPOS_H_ -#define _DAV_FS_REPOS_H_ - -/* the subdirectory to hold all DAV-related information for a directory */ -#define DAV_FS_STATE_DIR ".DAV" -#define DAV_FS_STATE_FILE_FOR_DIR ".state_for_dir" -#define DAV_FS_LOCK_NULL_FILE ".locknull" - - -/* ensure that our state subdirectory is present */ -void dav_fs_ensure_state_dir(apr_pool_t *p, const char *dirname); - -/* return the storage pool associated with a resource */ -apr_pool_t *dav_fs_pool(const dav_resource *resource); - -/* return the full pathname for a resource */ -const char *dav_fs_pathname(const dav_resource *resource); - -/* return the directory and filename for a resource */ -void dav_fs_dir_file_name(const dav_resource *resource, - const char **dirpath, - const char **fname); - -/* return the list of locknull members in this resource's directory */ -dav_error * dav_fs_get_locknull_members(const dav_resource *resource, - dav_buffer *pbuf); - - -/* DBM functions used by the repository and locking providers */ -extern const dav_hooks_db dav_hooks_db_dbm; - -dav_error * dav_dbm_open_direct(apr_pool_t *p, const char *pathname, int ro, - dav_db **pdb); -void dav_dbm_get_statefiles(apr_pool_t *p, const char *fname, - const char **state1, const char **state2); - -/* where is the lock database located? */ -const char *dav_get_lockdb_path(const request_rec *r); - -const dav_hooks_locks *dav_fs_get_lock_hooks(request_rec *r); -const dav_hooks_propdb *dav_fs_get_propdb_hooks(request_rec *r); - -void dav_fs_gather_propsets(apr_array_header_t *uris); -int dav_fs_find_liveprop(const dav_resource *resource, - const char *ns_uri, const char *name, - const dav_hooks_liveprop **hooks); -void dav_fs_insert_all_liveprops(request_rec *r, const dav_resource *resource, - dav_prop_insert what, ap_text_header *phdr); - -void dav_fs_register(apr_pool_t *p); - -#endif /* _DAV_FS_REPOS_H_ */ diff --git a/modules/dav/main/.cvsignore b/modules/dav/main/.cvsignore deleted file mode 100644 index 65f0cc30cf..0000000000 --- a/modules/dav/main/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -.deps -.libs -*.la -modules.mk -Makefile -*.lo -*.slo -*.so -Debug -Release diff --git a/modules/dav/main/Makefile.in b/modules/dav/main/Makefile.in deleted file mode 100644 index 7c5c149d85..0000000000 --- a/modules/dav/main/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ -# a modules Makefile has no explicit targets -- they will be defined by -# whatever modules are enabled. just grab special.mk to deal with this. -include $(top_srcdir)/build/special.mk diff --git a/modules/dav/main/config5.m4 b/modules/dav/main/config5.m4 deleted file mode 100644 index f576f5f579..0000000000 --- a/modules/dav/main/config5.m4 +++ /dev/null @@ -1,22 +0,0 @@ -dnl modules enabled in this directory by default - -APACHE_MODPATH_INIT(dav/main) - -dav_objects="mod_dav.lo props.lo util.lo util_lock.lo liveprop.lo providers.lo std_liveprop.lo" - -if test "$enable_http" = "no"; then - dav_enable=no -else - dav_enable=most -fi - -APACHE_MODULE(dav, WebDAV protocol handling, $dav_objects, , $dav_enable) - -if test "$enable_dav" != "no"; then - apache_need_expat=yes - - APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current]) -fi - - -APACHE_MODPATH_FINISH diff --git a/modules/dav/main/liveprop.c b/modules/dav/main/liveprop.c deleted file mode 100644 index 98358afb74..0000000000 --- a/modules/dav/main/liveprop.c +++ /dev/null @@ -1,177 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_pools.h" -#include "apr_hash.h" -#include "apr_errno.h" -#include "apr_strings.h" -#include "util_xml.h" /* for ap_text_header */ -#include "mod_dav.h" - - -static apr_hash_t *dav_liveprop_uris = NULL; -static int dav_liveprop_count = 0; - - -static apr_status_t dav_cleanup_liveprops(void *ctx) -{ - dav_liveprop_uris = NULL; - dav_liveprop_count = 0; - return APR_SUCCESS; -} - -static void dav_register_liveprop_namespace(apr_pool_t *p, const char *uri) -{ - int value; - - if (dav_liveprop_uris == NULL) { - dav_liveprop_uris = apr_hash_make(p); - apr_pool_cleanup_register(p, NULL, dav_cleanup_liveprops, apr_pool_cleanup_null); - } - - value = (int)apr_hash_get(dav_liveprop_uris, uri, APR_HASH_KEY_STRING); - if (value != 0) { - /* already registered */ - return; - } - - /* start at 1, and count up */ - apr_hash_set(dav_liveprop_uris, uri, APR_HASH_KEY_STRING, - (void *)++dav_liveprop_count); -} - -DAV_DECLARE(int) dav_get_liveprop_ns_index(const char *uri) -{ - return (int)apr_hash_get(dav_liveprop_uris, uri, APR_HASH_KEY_STRING); -} - -int dav_get_liveprop_ns_count(void) -{ - return dav_liveprop_count; -} - -void dav_add_all_liveprop_xmlns(apr_pool_t *p, ap_text_header *phdr) -{ - apr_hash_index_t *idx = apr_hash_first(dav_liveprop_uris); - - for ( ; idx != NULL; idx = apr_hash_next(idx) ) { - const void *key; - void *val; - const char *s; - - apr_hash_this(idx, &key, NULL, &val); - - s = apr_psprintf(p, " xmlns:lp%d=\"%s\"", (int)val, (const char *)key); - ap_text_append(p, phdr, s); - } -} - -DAV_DECLARE(int) dav_do_find_liveprop(const char *ns_uri, const char *name, - const dav_liveprop_group *group, - const dav_hooks_liveprop **hooks) -{ - const char * const *uris = group->namespace_uris; - const dav_liveprop_spec *scan; - int ns; - - /* first: locate the namespace in the namespace table */ - for (ns = 0; uris[ns] != NULL; ++ns) - if (strcmp(ns_uri, uris[ns]) == 0) - break; - if (uris[ns] == NULL) { - /* not our property (the namespace matched none of ours) */ - return 0; - } - - /* second: look for the property in the liveprop specs */ - for (scan = group->specs; scan->name != NULL; ++scan) - if (ns == scan->ns && strcmp(name, scan->name) == 0) { - *hooks = group->hooks; - return scan->propid; - } - - /* not our property (same namespace, but no matching prop name) */ - return 0; -} - -DAV_DECLARE(int) dav_get_liveprop_info(int propid, - const dav_liveprop_group *group, - const dav_liveprop_spec **info) -{ - const dav_liveprop_spec *scan; - - for (scan = group->specs; scan->name != NULL; ++scan) { - if (scan->propid == propid) { - *info = scan; - - /* map the provider-local NS into a global NS index */ - return dav_get_liveprop_ns_index(group->namespace_uris[scan->ns]); - } - } - - /* assert: should not reach this point */ - *info = NULL; - return 0; -} - -DAV_DECLARE(void) dav_register_liveprop_group(apr_pool_t *p, - const dav_liveprop_group *group) -{ - /* register the namespace URIs */ - const char * const * uris = group->namespace_uris; - - for ( ; *uris != NULL; ++uris) { - dav_register_liveprop_namespace(p, *uris); - } -} diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c deleted file mode 100644 index 8e29f05c7f..0000000000 --- a/modules/dav/main/mod_dav.c +++ /dev/null @@ -1,4731 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* -** DAV extension module for Apache 2.0.* -** -** This module is repository-independent. It depends on hooks provided by a -** repository implementation. -** -** APACHE ISSUES: -** - within a DAV hierarchy, if an unknown method is used and we default -** to Apache's implementation, it sends back an OPTIONS with the wrong -** set of methods -- there is NO HOOK for us. -** therefore: we need to manually handle the HTTP_METHOD_NOT_ALLOWED -** and HTTP_NOT_IMPLEMENTED responses (not ap_send_error_response). -** - process_mkcol_body() had to dup code from ap_setup_client_block(). -** - it would be nice to get status lines from Apache for arbitrary -** status codes -** - it would be nice to be able to extend Apache's set of response -** codes so that it doesn't return 500 when an unknown code is placed -** into r->status. -** - http_vhost functions should apply "const" to their params -** -** DESIGN NOTES: -** - For PROPFIND, we batch up the entire response in memory before -** sending it. We may want to reorganize around sending the information -** as we suck it in from the propdb. Alternatively, we should at least -** generate a total Content-Length if we're going to buffer in memory -** so that we can keep the connection open. -*/ - -#include "apr_strings.h" -#include "apr_lib.h" /* for apr_is* */ - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_main.h" -#include "http_protocol.h" -#include "http_request.h" -#include "util_script.h" - -#include "mod_dav.h" - - -/* ### what is the best way to set this? */ -#define DAV_DEFAULT_PROVIDER "filesystem" - -enum { - DAV_ENABLED_UNSET = 0, - DAV_ENABLED_OFF, - DAV_ENABLED_ON -}; - -/* per-dir configuration */ -typedef struct { - const char *provider_name; - const dav_provider *provider; - const char *dir; - int locktimeout; - int allow_depthinfinity; - - apr_table_t *d_params; /* per-directory DAV config parameters */ - -} dav_dir_conf; - -/* per-server configuration */ -typedef struct { - int unused; - -} dav_server_conf; - -#define DAV_INHERIT_VALUE(parent, child, field) \ - ((child)->field ? (child)->field : (parent)->field) - - -/* forward-declare for use in configuration lookup */ -extern module DAV_DECLARE_DATA dav_module; - -static void dav_init_handler(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, - server_rec *s) -{ - /* DBG0("dav_init_handler"); */ - - ap_add_version_component(p, "DAV/2"); -} - -static void *dav_create_server_config(apr_pool_t *p, server_rec *s) -{ - dav_server_conf *newconf; - - newconf = (dav_server_conf *) apr_pcalloc(p, sizeof(*newconf)); - - /* ### this isn't used at the moment... */ - - return newconf; -} - -static void *dav_merge_server_config(apr_pool_t *p, void *base, void *overrides) -{ -#if 0 - dav_server_conf *child = overrides; -#endif - dav_server_conf *newconf; - - newconf = (dav_server_conf *) apr_pcalloc(p, sizeof(*newconf)); - - /* ### nothing to merge right now... */ - - return newconf; -} - -static void *dav_create_dir_config(apr_pool_t *p, char *dir) -{ - /* NOTE: dir==NULL creates the default per-dir config */ - - dav_dir_conf *conf; - - conf = (dav_dir_conf *) apr_pcalloc(p, sizeof(*conf)); - - /* clean up the directory to remove any trailing slash */ - if (dir != NULL) { - char *d; - apr_size_t l; - - d = apr_pstrdup(p, dir); - l = strlen(d); - if (l > 1 && d[l - 1] == '/') - d[l - 1] = '\0'; - conf->dir = d; - } - - conf->d_params = apr_table_make(p, 1); - - return conf; -} - -static void *dav_merge_dir_config(apr_pool_t *p, void *base, void *overrides) -{ - dav_dir_conf *parent = base; - dav_dir_conf *child = overrides; - dav_dir_conf *newconf = (dav_dir_conf *) apr_pcalloc(p, sizeof(*newconf)); - - /* DBG3("dav_merge_dir_config: new=%08lx base=%08lx overrides=%08lx", - (long)newconf, (long)base, (long)overrides); */ - - newconf->provider_name = DAV_INHERIT_VALUE(parent, child, provider_name); - newconf->provider = DAV_INHERIT_VALUE(parent, child, provider); - if (parent->provider_name != NULL) { - if (child->provider_name == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL, - "\"DAV Off\" cannot be used to turn off a subtree " - "of a DAV-enabled location."); - } - else if (strcasecmp(child->provider_name, - parent->provider_name) != 0) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL, - "A subtree cannot specify a different DAV provider " - "than its parent."); - } - } - - newconf->locktimeout = DAV_INHERIT_VALUE(parent, child, locktimeout); - newconf->dir = DAV_INHERIT_VALUE(parent, child, dir); - newconf->allow_depthinfinity = DAV_INHERIT_VALUE(parent, child, - allow_depthinfinity); - - newconf->d_params = apr_table_copy(p, parent->d_params); - apr_table_overlap(newconf->d_params, child->d_params, - APR_OVERLAP_TABLES_SET); - - return newconf; -} - -apr_table_t *dav_get_dir_params(const request_rec *r) -{ - dav_dir_conf *conf; - - conf = ap_get_module_config(r->per_dir_config, &dav_module); - return conf->d_params; -} - -static const dav_provider * dav_get_provider(request_rec *r) -{ - dav_dir_conf *conf; - - conf = ap_get_module_config(r->per_dir_config, &dav_module); - /* assert: conf->provider_name != NULL - (otherwise, DAV is disabled, and we wouldn't be here) */ - - /* assert: conf->provider != NULL - (checked when conf->provider_name is set) */ - return conf->provider; -} - -const dav_hooks_locks *dav_get_lock_hooks(request_rec *r) -{ - return dav_get_provider(r)->locks; -} - -const dav_hooks_propdb *dav_get_propdb_hooks(request_rec *r) -{ - return dav_get_provider(r)->propdb; -} - -const dav_hooks_vsn *dav_get_vsn_hooks(request_rec *r) -{ - return dav_get_provider(r)->vsn; -} - -const dav_hooks_binding *dav_get_binding_hooks(request_rec *r) -{ - return dav_get_provider(r)->binding; -} - -/* - * Command handler for the DAV directive, which is TAKE1. - */ -static const char *dav_cmd_dav(cmd_parms *cmd, void *config, const char *arg1) -{ - dav_dir_conf *conf = (dav_dir_conf *) config; - - if (strcasecmp(arg1, "on") == 0) { - conf->provider_name = DAV_DEFAULT_PROVIDER; - } - else if (strcasecmp(arg1, "off") == 0) { - conf->provider_name = NULL; - conf->provider = NULL; - } - else { - conf->provider_name = apr_pstrdup(cmd->pool, arg1); - } - - if (conf->provider_name != NULL) { - /* lookup and cache the actual provider now */ - conf->provider = dav_lookup_provider(conf->provider_name); - - if (conf->provider == NULL) { - /* by the time they use it, the provider should be loaded and - registered with us. */ - return apr_psprintf(cmd->pool, - "Unknown DAV provider: %s", - conf->provider_name); - } - } - - return NULL; -} - -/* - * Command handler for the DAVDepthInfinity directive, which is FLAG. - */ -static const char *dav_cmd_davdepthinfinity(cmd_parms *cmd, void *config, - int arg) -{ - dav_dir_conf *conf = (dav_dir_conf *) config; - - if (arg) - conf->allow_depthinfinity = DAV_ENABLED_ON; - else - conf->allow_depthinfinity = DAV_ENABLED_OFF; - return NULL; -} - -/* - * Command handler for DAVMinTimeout directive, which is TAKE1 - */ -static const char *dav_cmd_davmintimeout(cmd_parms *cmd, void *config, - const char *arg1) -{ - dav_dir_conf *conf = (dav_dir_conf *) config; - - conf->locktimeout = atoi(arg1); - if (conf->locktimeout < 0) - return "DAVMinTimeout requires a non-negative integer."; - - return NULL; -} - -/* - * Command handler for DAVParam directive, which is TAKE2 - */ -static const char *dav_cmd_davparam(cmd_parms *cmd, void *config, - const char *arg1, const char *arg2) -{ - dav_dir_conf *conf = (dav_dir_conf *) config; - - apr_table_set(conf->d_params, arg1, arg2); - - return NULL; -} - -/* -** dav_error_response() -** -** Send a nice response back to the user. In most cases, Apache doesn't -** allow us to provide details in the body about what happened. This -** function allows us to completely specify the response body. -** -** ### this function is not logging any errors! (e.g. the body) -*/ -static int dav_error_response(request_rec *r, int status, const char *body) -{ - r->status = status; - r->status_line = ap_get_status_line(status); /* ### needed? */ - r->content_type = "text/html"; - - /* since we're returning DONE, ensure the request body is consumed. */ - (void) ap_discard_request_body(r); - - /* begin the response now... */ - ap_rvputs(r, - DAV_RESPONSE_BODY_1, - r->status_line, - DAV_RESPONSE_BODY_2, - &r->status_line[4], - DAV_RESPONSE_BODY_3, - NULL); - - ap_rputs(body, r); - - ap_rputs(ap_psignature("\n<P><HR>\n", r), r); - ap_rputs(DAV_RESPONSE_BODY_4, r); - - /* the response has been sent. */ - /* - * ### Use of DONE obviates logging..! - */ - return DONE; -} - -/* -** Apache's URI escaping does not replace '&' since that is a valid character -** in a URI (to form a query section). We must explicitly handle it so that -** we can embed the URI into an XML document. -*/ -static const char *dav_xml_escape_uri(apr_pool_t *p, const char *uri) -{ - const char *e_uri = ap_escape_uri(p, uri); - - /* check the easy case... */ - if (ap_strchr_c(e_uri, '&') == NULL) - return e_uri; - - /* there was a '&', so more work is needed... sigh. */ - - /* - ** Note: this is a teeny bit of overkill since we know there are no - ** '<' or '>' characters, but who cares. - */ - return ap_xml_quote_string(p, e_uri, 0); -} - -static void dav_send_multistatus(request_rec *r, int status, - dav_response *first, - apr_array_header_t *namespaces) -{ - /* Set the correct status and Content-Type */ - r->status = status; - r->content_type = DAV_XML_CONTENT_TYPE; - - /* Send the headers and actual multistatus response now... */ - ap_rputs(DAV_XML_HEADER DEBUG_CR - "<D:multistatus xmlns:D=\"DAV:\"", r); - - if (namespaces != NULL) { - int i; - - for (i = namespaces->nelts; i--; ) { - ap_rprintf(r, " xmlns:ns%d=\"%s\"", i, - AP_XML_GET_URI_ITEM(namespaces, i)); - } - } - - /* ap_rputc('>', r); */ - ap_rputs(">" DEBUG_CR, r); - - for (; first != NULL; first = first->next) { - ap_text *t; - - if (first->propresult.xmlns == NULL) { - ap_rputs("<D:response>", r); - } - else { - ap_rputs("<D:response", r); - for (t = first->propresult.xmlns; t; t = t->next) { - ap_rputs(t->text, r); - } - ap_rputc('>', r); - } - - ap_rputs(DEBUG_CR "<D:href>", r); - ap_rputs(dav_xml_escape_uri(r->pool, first->href), r); - ap_rputs("</D:href>" DEBUG_CR, r); - - if (first->propresult.propstats == NULL) { - /* use the Status-Line text from Apache. Note, this will - * default to 500 Internal Server Error if first->status - * is not a known (or valid) status code. */ - ap_rprintf(r, - "<D:status>HTTP/1.1 %s</D:status>" DEBUG_CR, - ap_get_status_line(first->status)); - } - else { - /* assume this includes <propstat> and is quoted properly */ - for (t = first->propresult.propstats; t; t = t->next) { - ap_rputs(t->text, r); - } - } - - if (first->desc != NULL) { - /* - ** We supply the description, so we know it doesn't have to - ** have any escaping/encoding applied to it. - */ - ap_rputs("<D:responsedescription>", r); - ap_rputs(first->desc, r); - ap_rputs("</D:responsedescription>" DEBUG_CR, r); - } - - ap_rputs("</D:response>" DEBUG_CR, r); - } - - ap_rputs("</D:multistatus>" DEBUG_CR, r); -} - -/* -** dav_log_err() -** -** Write error information to the log. -*/ -static void dav_log_err(request_rec *r, dav_error *err, int level) -{ - dav_error *errscan; - - /* Log the errors */ - /* ### should have a directive to log the first or all */ - for (errscan = err; errscan != NULL; errscan = errscan->prev) { - if (errscan->desc == NULL) - continue; - if (errscan->save_errno != 0) { - errno = errscan->save_errno; - ap_log_rerror(APLOG_MARK, level, errno, r, "%s [%d, #%d]", - errscan->desc, errscan->status, errscan->error_id); - } - else { - ap_log_rerror(APLOG_MARK, level | APLOG_NOERRNO, 0, r, - "%s [%d, #%d]", - errscan->desc, errscan->status, errscan->error_id); - } - } -} - -/* -** dav_handle_err() -** -** Handle the standard error processing. <err> must be non-NULL. -** -** <response> is set by the following: -** - dav_validate_request() -** - dav_add_lock() -** - repos_hooks->remove_resource -** - repos_hooks->move_resource -** - repos_hooks->copy_resource -** - vsn_hooks->update -*/ -static int dav_handle_err(request_rec *r, dav_error *err, - dav_response *response) -{ - /* log the errors */ - dav_log_err(r, err, APLOG_ERR); - - if (response == NULL) { - /* our error messages are safe; tell Apache this */ - apr_table_setn(r->notes, "verbose-error-to", "*"); - return err->status; - } - - /* since we're returning DONE, ensure the request body is consumed. */ - (void) ap_discard_request_body(r); - - /* send the multistatus and tell Apache the request/response is DONE. */ - dav_send_multistatus(r, err->status, response, NULL); - return DONE; -} - -/* handy function for return values of methods that (may) create things */ -static int dav_created(request_rec *r, const char *locn, const char *what, - int replaced) -{ - const char *body; - - if (locn == NULL) { - locn = r->uri; - } - - /* did the target resource already exist? */ - if (replaced) { - /* Apache will supply a default message */ - return HTTP_NO_CONTENT; - } - - /* Per HTTP/1.1, S10.2.2: add a Location header to contain the - * URI that was created. */ - - /* Convert locn to an absolute URI, and return in Location header */ - apr_table_setn(r->headers_out, "Location", ap_construct_url(r->pool, locn, r)); - - /* ### insert an ETag header? see HTTP/1.1 S10.2.2 */ - - /* Apache doesn't allow us to set a variable body for HTTP_CREATED, so - * we must manufacture the entire response. */ - body = apr_psprintf(r->pool, "%s %s has been created.", - what, ap_escape_html(r->pool, locn)); - return dav_error_response(r, HTTP_CREATED, body); -} - -/* ### move to dav_util? */ -int dav_get_depth(request_rec *r, int def_depth) -{ - const char *depth = apr_table_get(r->headers_in, "Depth"); - - if (depth == NULL) { - return def_depth; - } - if (strcasecmp(depth, "infinity") == 0) { - return DAV_INFINITY; - } - else if (strcmp(depth, "0") == 0) { - return 0; - } - else if (strcmp(depth, "1") == 0) { - return 1; - } - - /* The caller will return an HTTP_BAD_REQUEST. This will augment the - * default message that Apache provides. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "An invalid Depth header was specified."); - return -1; -} - -static int dav_get_overwrite(request_rec *r) -{ - const char *overwrite = apr_table_get(r->headers_in, "Overwrite"); - - if (overwrite == NULL) { - return 1; /* default is "T" */ - } - - if ((*overwrite == 'F' || *overwrite == 'f') && overwrite[1] == '\0') { - return 0; - } - if ((*overwrite == 'T' || *overwrite == 't') && overwrite[1] == '\0') { - return 1; - } - - /* The caller will return an HTTP_BAD_REQUEST. This will augment the - * default message that Apache provides. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "An invalid Overwrite header was specified."); - return -1; -} - -/* resolve a request URI to a resource descriptor. - * - * If label_allowed != 0, then allow the request target to be altered by - * a Label: header. - * - * If use_checked_in is true, then the repository provider should return - * the resource identified by the DAV:checked-in property of the resource - * identified by the Request-URI. - */ -static dav_error * dav_get_resource(request_rec *r, int label_allowed, - int use_checked_in, dav_resource **res_p) -{ - dav_dir_conf *conf; - const char *label = NULL; - dav_error *err; - - /* if the request target can be overridden, get any target selector */ - if (label_allowed) { - label = apr_table_get(r->headers_in, "label"); - } - - conf = ap_get_module_config(r->per_dir_config, &dav_module); - /* assert: conf->provider != NULL */ - - /* resolve the resource */ - err = (*conf->provider->repos->get_resource)(r, conf->dir, - label, use_checked_in, - res_p); - if (err != NULL) { - err = dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not fetch resource information.", err); - return err; - } - - /* Note: this shouldn't happen, but just be sure... */ - if (*res_p == NULL) { - /* ### maybe use HTTP_INTERNAL_SERVER_ERROR */ - return dav_new_error(r->pool, HTTP_NOT_FOUND, 0, - apr_psprintf(r->pool, - "The provider did not define a " - "resource for %s.", - ap_escape_html(r->pool, r->uri))); - } - - /* ### hmm. this doesn't feel like the right place or thing to do */ - /* if there were any input headers requiring a Vary header in the response, - * add it now */ - dav_add_vary_header(r, r, *res_p); - - return NULL; -} - -static dav_error * dav_open_lockdb(request_rec *r, int ro, dav_lockdb **lockdb) -{ - const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r); - - if (hooks == NULL) { - *lockdb = NULL; - return NULL; - } - - /* open the thing lazily */ - return (*hooks->open_lockdb)(r, ro, 0, lockdb); -} - -static int dav_parse_range(request_rec *r, - apr_off_t *range_start, apr_off_t *range_end) -{ - const char *range_c; - char *range; - char *dash; - char *slash; - - range_c = apr_table_get(r->headers_in, "content-range"); - if (range_c == NULL) - return 0; - - range = apr_pstrdup(r->pool, range_c); - if (strncasecmp(range, "bytes ", 6) != 0 - || (dash = ap_strchr(range, '-')) == NULL - || (slash = ap_strchr(range, '/')) == NULL) { - /* malformed header. ignore it (per S14.16 of RFC2616) */ - return 0; - } - - *dash = *slash = '\0'; - - /* ### atol may not be large enough for the apr_off_t */ - *range_start = atol(range + 6); - *range_end = atol(dash + 1); - - if (*range_end < *range_start - || (slash[1] != '*' && atol(slash + 1) <= *range_end)) { - /* invalid range. ignore it (per S14.16 of RFC2616) */ - return 0; - } - - /* we now have a valid range */ - return 1; -} - -/* handle the GET method */ -static int dav_method_get(request_rec *r) -{ - dav_resource *resource; - int result; - dav_error *err; - - /* This method should only be called when the resource is not - * visible to Apache. We will fetch the resource from the repository, - * then create a subrequest for Apache to handle. - */ - err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - if (!resource->exists) { - /* Apache will supply a default error for this. */ - return HTTP_NOT_FOUND; - } - - /* Check resource type */ - if (resource->type != DAV_RESOURCE_TYPE_REGULAR && - resource->type != DAV_RESOURCE_TYPE_VERSION && - resource->type != DAV_RESOURCE_TYPE_WORKING) - { - return dav_error_response(r, HTTP_CONFLICT, - "Cannot GET this type of resource."); - } - - /* Cannot handle GET of a collection from a repository */ - if (resource->collection) { - return dav_error_response(r, HTTP_CONFLICT, - "No default response to GET for a " - "collection."); - } - - /* - ** We can use two different approaches for a GET. - ** - ** 1) get_pathname will return a pathname to a file which should be - ** sent to the client. If the repository provides this, then we - ** use it. - ** - ** This is the best alternative since it allows us to do a sub- - ** request on the file, which gives the Apache framework a chance - ** to deal with negotiation, MIME types, or whatever. - ** - ** 2) open_stream and read_stream. - */ - if (resource->hooks->get_pathname != NULL) { - const char *pathname; - void *fhandle; - request_rec *new_req; - - /* Ask repository for copy of file */ - pathname = (*resource->hooks->get_pathname)(resource, &fhandle); - if (pathname == NULL) { - return HTTP_NOT_FOUND; - } - - /* Convert to canonical filename, so Apache detects component - * separators (on Windows, it only looks for '/', not '\') - */ - pathname = ap_os_case_canonical_filename(r->pool, pathname); - - /* Create a sub-request with the new filename */ - new_req = ap_sub_req_lookup_file(pathname, r, NULL); - if (new_req == NULL) { - (*resource->hooks->free_file)(fhandle); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* This may be a HEAD request */ - new_req->header_only = r->header_only; - - /* ### this enables header generation */ - new_req->assbackwards = 0; - - /* Run the sub-request */ - result = ap_run_sub_req(new_req); - ap_destroy_sub_req(new_req); - - /* Free resources */ - (*resource->hooks->free_file)(fhandle); - - return result; - } - else { - dav_stream_mode mode; - dav_stream *stream; - dav_error *err; - void *buffer; - int has_range; - apr_off_t range_start; - apr_off_t range_end; - - /* set up the HTTP headers for the response */ - if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) { - err = dav_push_error(r->pool, err->status, 0, - "Unable to set up HTTP headers.", - err); - return dav_handle_err(r, err, NULL); - } - - /* use plain READ mode unless we see a Content-Range */ - mode = DAV_MODE_READ; - - /* process the Content-Range header (if present) */ - has_range = dav_parse_range(r, &range_start, &range_end); - if (has_range) { - /* use a read mode which is seekable */ - mode = DAV_MODE_READ_SEEKABLE; - - /* prep the output */ - r->status = HTTP_PARTIAL_CONTENT; - apr_table_setn(r->headers_out, - "Content-Range", - apr_psprintf(r->pool, - "bytes %" APR_OFF_T_FMT - "-%" APR_OFF_T_FMT "/*", - range_start, range_end)); - ap_set_content_length(r, range_end - range_start + 1); - } - - if (r->header_only) { - return DONE; - } - - if ((err = (*resource->hooks->open_stream)(resource, mode, - &stream)) != NULL) { - /* ### assuming FORBIDDEN is probably not quite right... */ - err = dav_push_error(r->pool, HTTP_FORBIDDEN, 0, - apr_psprintf(r->pool, - "Unable to GET contents for %s.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, NULL); - } - - if (has_range - && (err = (*resource->hooks->seek_stream)(stream, - range_start)) != NULL) { - err = dav_push_error(r->pool, err->status, 0, - "Could not seek to beginning of the " - "specified Content-Range.", err); - return dav_handle_err(r, err, NULL); - } - - buffer = apr_palloc(r->pool, DAV_READ_BLOCKSIZE); - while (1) { - apr_size_t amt; - - if (!has_range) - amt = DAV_READ_BLOCKSIZE; - else if ((range_end - range_start + 1) > DAV_READ_BLOCKSIZE) - amt = DAV_READ_BLOCKSIZE; - else { - /* note: range_end - range_start is an ssize_t */ - amt = (apr_size_t)(range_end - range_start + 1); - } - - if ((err = (*resource->hooks->read_stream)(stream, buffer, - &amt)) != NULL) { - break; - } - if (amt == 0) { - /* no more content */ - break; - } - if (ap_rwrite(buffer, amt, r) < 0) { - /* ### what to do with this error? */ - break; - } - - if (has_range) { - range_start += amt; - if (range_start > range_end) - break; - } - } - - if (err != NULL) - return dav_handle_err(r, err, NULL); - - /* - ** ### range_start should equal range_end+1. if it doesn't, then - ** ### we did not send enough data to the client. the client will - ** ### hang (and timeout) waiting for the data. - ** - ** ### what to do? abort the connection? - */ - return DONE; - } - - /* NOTREACHED */ -} - -/* validate resource on POST, then pass it off to the default handler */ -static int dav_method_post(request_rec *r) -{ - dav_resource *resource; - dav_error *err; - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - /* Note: depth == 0. Implies no need for a multistatus response. */ - if ((err = dav_validate_request(r, resource, 0, NULL, NULL, - DAV_VALIDATE_RESOURCE, NULL)) != NULL) { - /* ### add a higher-level description? */ - return dav_handle_err(r, err, NULL); - } - - return DECLINED; -} - -/* handle the PUT method */ -static int dav_method_put(request_rec *r) -{ - dav_resource *resource; - int resource_state; - dav_auto_version_info av_info; - const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r); - const char *body; - dav_error *err; - dav_error *err2; - int result; - dav_stream_mode mode; - dav_stream *stream; - dav_response *multi_response; - int has_range; - apr_off_t range_start; - apr_off_t range_end; - - if ((result = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK) { - return result; - } - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - /* If not a file or collection resource, PUT not allowed */ - if (resource->type != DAV_RESOURCE_TYPE_REGULAR - && resource->type != DAV_RESOURCE_TYPE_WORKING) { - body = apr_psprintf(r->pool, - "Cannot create resource %s with PUT.", - ap_escape_html(r->pool, r->uri)); - return dav_error_response(r, HTTP_CONFLICT, body); - } - - /* Cannot PUT a collection */ - if (resource->collection) { - return dav_error_response(r, HTTP_CONFLICT, - "Cannot PUT to a collection."); - - } - - resource_state = dav_get_resource_state(r, resource); - - /* - ** Note: depth == 0 normally requires no multistatus response. However, - ** if we pass DAV_VALIDATE_PARENT, then we could get an error on a URI - ** other than the Request-URI, thereby requiring a multistatus. - ** - ** If the resource does not exist (DAV_RESOURCE_NULL), then we must - ** check the resource *and* its parent. If the resource exists or is - ** a locknull resource, then we check only the resource. - */ - if ((err = dav_validate_request(r, resource, 0, NULL, &multi_response, - resource_state == DAV_RESOURCE_NULL ? - DAV_VALIDATE_PARENT : - DAV_VALIDATE_RESOURCE, NULL)) != NULL) { - /* ### add a higher-level description? */ - return dav_handle_err(r, err, multi_response); - } - - /* make sure the resource can be modified (if versioning repository) */ - if ((err = dav_auto_checkout(r, resource, - 0 /* not parent_only */, - &av_info)) != NULL) { - /* ### add a higher-level description? */ - return dav_handle_err(r, err, NULL); - } - - /* truncate and rewrite the file unless we see a Content-Range */ - mode = DAV_MODE_WRITE_TRUNC; - - has_range = dav_parse_range(r, &range_start, &range_end); - if (has_range) { - mode = DAV_MODE_WRITE_SEEKABLE; - } - - /* Create the new file in the repository */ - if ((err = (*resource->hooks->open_stream)(resource, mode, - &stream)) != NULL) { - /* ### assuming FORBIDDEN is probably not quite right... */ - err = dav_push_error(r->pool, HTTP_FORBIDDEN, 0, - apr_psprintf(r->pool, - "Unable to PUT new contents for %s.", - ap_escape_html(r->pool, r->uri)), - err); - } - - if (err == NULL && has_range) { - /* a range was provided. seek to the start */ - err = (*resource->hooks->seek_stream)(stream, range_start); - } - - if (err == NULL) { - if (ap_should_client_block(r)) { - char *buffer = apr_palloc(r->pool, DAV_READ_BLOCKSIZE); - long len; - - /* - ** Once we start reading the request, then we must read the - ** whole darn thing. ap_discard_request_body() won't do anything - ** for a partially-read request. - */ - - while ((len = ap_get_client_block(r, buffer, - DAV_READ_BLOCKSIZE)) > 0) { - if (err == NULL) { - /* write whatever we read, until we see an error */ - err = (*resource->hooks->write_stream)(stream, - buffer, len); - } - } - - /* - ** ### what happens if we read more/less than the amount - ** ### specified in the Content-Range? eek... - */ - - if (len == -1) { - /* - ** Error reading request body. This has precedence over - ** prior errors. - */ - err = dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, - "An error occurred while reading the " - "request body."); - } - } - - err2 = (*resource->hooks->close_stream)(stream, - err == NULL /* commit */); - if (err2 != NULL && err == NULL) { - /* no error during the write, but we hit one at close. use it. */ - err = err2; - } - } - - /* - ** Ensure that we think the resource exists now. - ** ### eek. if an error occurred during the write and we did not commit, - ** ### then the resource might NOT exist (e.g. dav_fs_repos.c) - */ - if (err == NULL) { - resource->exists = 1; - } - - /* restore modifiability of resources back to what they were */ - err2 = dav_auto_checkin(r, resource, err != NULL /* undo if error */, - 0 /*unlock*/, &av_info); - - /* check for errors now */ - if (err != NULL) { - return dav_handle_err(r, err, NULL); - } - if (err2 != NULL) { - /* just log a warning */ - err2 = dav_push_error(r->pool, err->status, 0, - "The PUT was successful, but there " - "was a problem automatically checking in " - "the resource or its parent collection.", - err2); - dav_log_err(r, err2, APLOG_WARNING); - } - - /* ### place the Content-Type and Content-Language into the propdb */ - - if (locks_hooks != NULL) { - dav_lockdb *lockdb; - - if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) { - /* The file creation was successful, but the locking failed. */ - err = dav_push_error(r->pool, err->status, 0, - "The file was PUT successfully, but there " - "was a problem opening the lock database " - "which prevents inheriting locks from the " - "parent resources.", - err); - return dav_handle_err(r, err, NULL); - } - - /* notify lock system that we have created/replaced a resource */ - err = dav_notify_created(r, lockdb, resource, resource_state, 0); - - (*locks_hooks->close_lockdb)(lockdb); - - if (err != NULL) { - /* The file creation was successful, but the locking failed. */ - err = dav_push_error(r->pool, err->status, 0, - "The file was PUT successfully, but there " - "was a problem updating its lock " - "information.", - err); - return dav_handle_err(r, err, NULL); - } - } - - /* NOTE: WebDAV spec, S8.7.1 states properties should be unaffected */ - - /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */ - return dav_created(r, NULL, "Resource", resource_state == DAV_RESOURCE_EXISTS); -} - -/* ### move this to dav_util? */ -DAV_DECLARE(void) dav_add_response(dav_walk_resource *wres, - int status, dav_get_props_result *propstats) -{ - dav_response *resp; - - /* just drop some data into an dav_response */ - resp = apr_pcalloc(wres->pool, sizeof(*resp)); - resp->href = apr_pstrdup(wres->pool, wres->resource->uri); - resp->status = status; - if (propstats) { - resp->propresult = *propstats; - } - - resp->next = wres->response; - wres->response = resp; -} - -/* handle the DELETE method */ -static int dav_method_delete(request_rec *r) -{ - dav_resource *resource; - dav_auto_version_info av_info; - dav_error *err; - dav_error *err2; - dav_response *multi_response; - int result; - int depth; - - /* We don't use the request body right now, so torch it. */ - if ((result = ap_discard_request_body(r)) != OK) { - return result; - } - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - if (!resource->exists) { - /* Apache will supply a default error for this. */ - return HTTP_NOT_FOUND; - } - - /* 2518 says that depth must be infinity only for collections. - * For non-collections, depth is ignored, unless it is an illegal value (1). - */ - depth = dav_get_depth(r, DAV_INFINITY); - - if (resource->collection && depth != DAV_INFINITY) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "Depth must be \"infinity\" for DELETE of a collection."); - return HTTP_BAD_REQUEST; - } - if (!resource->collection && depth == 1) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "Depth of \"1\" is not allowed for DELETE."); - return HTTP_BAD_REQUEST; - } - - /* - ** If any resources fail the lock/If: conditions, then we must fail - ** the delete. Each of the failing resources will be listed within - ** a DAV:multistatus body, wrapped into a 424 response. - ** - ** Note that a failure on the resource itself does not generate a - ** multistatus response -- only internal members/collections. - */ - if ((err = dav_validate_request(r, resource, depth, NULL, - &multi_response, - DAV_VALIDATE_PARENT - | DAV_VALIDATE_USE_424, NULL)) != NULL) { - err = dav_push_error(r->pool, err->status, 0, - apr_psprintf(r->pool, - "Could not DELETE %s due to a failed " - "precondition (e.g. locks).", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, multi_response); - } - - /* ### RFC 2518 s. 8.10.5 says to remove _all_ locks, not just those - * locked by the token(s) in the if_header. - */ - if ((result = dav_unlock(r, resource, NULL)) != OK) { - return result; - } - - /* if versioned resource, make sure parent is checked out */ - if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */, - &av_info)) != NULL) { - /* ### add a higher-level description? */ - return dav_handle_err(r, err, NULL); - } - - /* try to remove the resource */ - err = (*resource->hooks->remove_resource)(resource, &multi_response); - - /* restore writability of parent back to what it was */ - err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */, - 0 /*unlock*/, &av_info); - - /* check for errors now */ - if (err != NULL) { - err = dav_push_error(r->pool, err->status, 0, - apr_psprintf(r->pool, - "Could not DELETE %s.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, multi_response); - } - if (err2 != NULL) { - /* just log a warning */ - err = dav_push_error(r->pool, err2->status, 0, - "The DELETE was successful, but there " - "was a problem automatically checking in " - "the parent collection.", - err2); - dav_log_err(r, err, APLOG_WARNING); - } - - /* ### HTTP_NO_CONTENT if no body, HTTP_OK if there is a body (some day) */ - - /* Apache will supply a default error for this. */ - return HTTP_NO_CONTENT; -} - -/* generate DAV:supported-method-set OPTIONS response */ -static dav_error *dav_gen_supported_methods(request_rec *r, - const ap_xml_elem *elem, - const apr_table_t *methods, - ap_text_header *body) -{ - apr_array_header_t *arr; - apr_table_entry_t *elts; - ap_xml_elem *child; - ap_xml_attr *attr; - char *s; - int i; - - ap_text_append(r->pool, body, "<D:supported-method-set>" DEBUG_CR); - - if (elem->first_child == NULL) { - /* show all supported methods */ - arr = apr_table_elts(methods); - elts = (apr_table_entry_t *) arr->elts; - - for (i = 0; i < arr->nelts; ++i) { - if (elts[i].key == NULL) - continue; - s = apr_psprintf(r->pool, - "<D:supported-method D:name=\"%s\"/>" DEBUG_CR, - elts[i].key); - ap_text_append(r->pool, body, s); - } - } - else { - /* check for support of specific methods */ - for (child = elem->first_child; child != NULL; child = child->next) { - if (child->ns == AP_XML_NS_DAV_ID - && strcmp(child->name, "supported-method") == 0) { - const char *name = NULL; - - /* go through attributes to find method name */ - for (attr = child->attr; attr != NULL; attr = attr->next) { - if (attr->ns == AP_XML_NS_DAV_ID - && strcmp(attr->name, "name") == 0) - name = attr->value; - } - - if (name == NULL) { - return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, - "A DAV:supported-method element " - "does not have a \"name\" attribute"); - } - - /* see if method is supported */ - if (apr_table_get(methods, name) != NULL) { - s = apr_psprintf(r->pool, - "<D:supported-method D:name=\"%s\"/>" DEBUG_CR, - name); - ap_text_append(r->pool, body, s); - } - } - } - } - - ap_text_append(r->pool, body, "</D:supported-method-set>" DEBUG_CR); - return NULL; -} - -/* generate DAV:supported-live-property-set OPTIONS response */ -static dav_error *dav_gen_supported_live_props(request_rec *r, - const dav_resource *resource, - const ap_xml_elem *elem, - ap_text_header *body) -{ - dav_lockdb *lockdb; - dav_propdb *propdb; - ap_xml_elem *child; - ap_xml_attr *attr; - dav_error *err; - - /* open lock database, to report on supported lock properties */ - /* ### should open read-only */ - if ((err = dav_open_lockdb(r, 0, &lockdb)) != NULL) { - return dav_push_error(r->pool, err->status, 0, - "The lock database could not be opened, " - "preventing the reporting of supported lock " - "properties.", - err); - } - - /* open the property database (readonly) for the resource */ - if ((err = dav_open_propdb(r, lockdb, resource, 1, NULL, - &propdb)) != NULL) { - if (lockdb != NULL) - (*lockdb->hooks->close_lockdb)(lockdb); - - return dav_push_error(r->pool, err->status, 0, - "The property database could not be opened, " - "preventing report of supported properties.", - err); - } - - ap_text_append(r->pool, body, "<D:supported-live-property-set>" DEBUG_CR); - - if (elem->first_child == NULL) { - /* show all supported live properties */ - dav_get_props_result props = dav_get_allprops(propdb, DAV_PROP_INSERT_SUPPORTED); - body->last->next = props.propstats; - while (body->last->next != NULL) - body->last = body->last->next; - } - else { - /* check for support of specific live property */ - for (child = elem->first_child; child != NULL; child = child->next) { - if (child->ns == AP_XML_NS_DAV_ID - && strcmp(child->name, "supported-live-property") == 0) { - const char *name = NULL; - const char *nmspace = NULL; - - /* go through attributes to find name and namespace */ - for (attr = child->attr; attr != NULL; attr = attr->next) { - if (attr->ns == AP_XML_NS_DAV_ID) { - if (strcmp(attr->name, "name") == 0) - name = attr->value; - else if (strcmp(attr->name, "namespace") == 0) - nmspace = attr->value; - } - } - - if (name == NULL) { - err = dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, - "A DAV:supported-live-property " - "element does not have a \"name\" " - "attribute"); - break; - } - - /* default namespace to DAV: */ - if (nmspace == NULL) - nmspace = "DAV:"; - - /* check for support of property */ - dav_get_liveprop_supported(propdb, nmspace, name, body); - } - } - } - - ap_text_append(r->pool, body, "</D:supported-live-property-set>" DEBUG_CR); - - dav_close_propdb(propdb); - - if (lockdb != NULL) - (*lockdb->hooks->close_lockdb)(lockdb); - - return err; -} - -/* generate DAV:supported-report-set OPTIONS response */ -static dav_error *dav_gen_supported_reports(request_rec *r, - const dav_resource *resource, - const ap_xml_elem *elem, - const dav_hooks_vsn *vsn_hooks, - ap_text_header *body) -{ - ap_xml_elem *child; - ap_xml_attr *attr; - dav_error *err; - char *s; - - ap_text_append(r->pool, body, "<D:supported-report-set>" DEBUG_CR); - - if (vsn_hooks != NULL) { - const dav_report_elem *reports; - const dav_report_elem *rp; - - if ((err = (*vsn_hooks->avail_reports)(resource, &reports)) != NULL) { - return dav_push_error(r->pool, err->status, 0, - "DAV:supported-report-set could not be " - "determined due to a problem fetching the " - "available reports for this resource.", - err); - } - - if (reports != NULL) { - if (elem->first_child == NULL) { - /* show all supported reports */ - for (rp = reports; rp->nmspace != NULL; ++rp) { - /* Note: we presume reports->namespace is properly XML/URL quoted */ - s = apr_psprintf(r->pool, - "<D:supported-report D:name=\"%s\" D:namespace=\"%s\"/>" DEBUG_CR, - rp->name, rp->nmspace); - ap_text_append(r->pool, body, s); - } - } - else { - /* check for support of specific report */ - for (child = elem->first_child; child != NULL; child = child->next) { - if (child->ns == AP_XML_NS_DAV_ID - && strcmp(child->name, "supported-report") == 0) { - const char *name = NULL; - const char *nmspace = NULL; - - /* go through attributes to find name and namespace */ - for (attr = child->attr; attr != NULL; attr = attr->next) { - if (attr->ns == AP_XML_NS_DAV_ID) { - if (strcmp(attr->name, "name") == 0) - name = attr->value; - else if (strcmp(attr->name, "namespace") == 0) - nmspace = attr->value; - } - } - - if (name == NULL) { - return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, - "A DAV:supported-report element " - "does not have a \"name\" attribute"); - } - - /* default namespace to DAV: */ - if (nmspace == NULL) - nmspace = "DAV:"; - - for (rp = reports; rp->nmspace != NULL; ++rp) { - if (strcmp(name, rp->name) == 0 - && strcmp(nmspace, rp->nmspace) == 0) { - /* Note: we presume reports->nmspace is properly XML/URL quoted */ - s = apr_psprintf(r->pool, - "<D:supported-report D:name=\"%s\" D:namespace=\"%s\"/>" DEBUG_CR, - rp->name, rp->nmspace); - ap_text_append(r->pool, body, s); - break; - } - } - } - } - } - } - } - - ap_text_append(r->pool, body, "</D:supported-report-set>" DEBUG_CR); - return NULL; -} - -/* handle the OPTIONS method */ -static int dav_method_options(request_rec *r) -{ - const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r); - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); - const dav_hooks_binding *binding_hooks = DAV_GET_HOOKS_BINDING(r); - dav_resource *resource; - const char *dav_level; - char *allow; - char *s; - apr_array_header_t *arr; - apr_table_entry_t *elts; - apr_table_t *methods = apr_table_make(r->pool, 12); - ap_text_header vsn_options = { 0 }; - ap_text_header body = { 0 }; - ap_text *t; - int text_size; - int result; - int i; - apr_array_header_t *uri_ary; - ap_xml_doc *doc; - const ap_xml_elem *elem; - dav_error *err; - - /* resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - /* parse any request body */ - if ((result = ap_xml_parse_input(r, &doc)) != OK) { - return result; - } - /* note: doc == NULL if no request body */ - - if (doc && !dav_validate_root(doc, "options")) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The \"options\" element was not found."); - return HTTP_BAD_REQUEST; - } - - /* determine which providers are available */ - dav_level = "1"; - - if (locks_hooks != NULL) { - dav_level = "1,2"; - } - - if (binding_hooks != NULL) - dav_level = apr_pstrcat(r->pool, dav_level, ",bindings", NULL); - - /* ### - ** MSFT Web Folders chokes if length of DAV header value > 63 characters! - ** To workaround that, we use separate DAV headers for versioning and - ** live prop provider namespace URIs. - ** ### - */ - apr_table_setn(r->headers_out, "DAV", dav_level); - - /* - ** If there is a versioning provider, generate DAV headers - ** for versioning options. - */ - if (vsn_hooks != NULL) { - (*vsn_hooks->get_vsn_options)(r->pool, &vsn_options); - - for (t = vsn_options.first; t != NULL; t = t->next) - apr_table_addn(r->headers_out, "DAV", t->text); - } - - /* - ** Gather property set URIs from all the liveprop providers, - ** and generate a separate DAV header for each URI, to avoid - ** problems with long header lengths. - */ - uri_ary = apr_array_make(r->pool, 5, sizeof(const char *)); - dav_run_gather_propsets(uri_ary); - for (i = 0; i < uri_ary->nelts; ++i) { - if (((char **)uri_ary->elts)[i] != NULL) - apr_table_addn(r->headers_out, "DAV", ((char **)uri_ary->elts)[i]); - } - - /* this tells MSFT products to skip looking for FrontPage extensions */ - apr_table_setn(r->headers_out, "MS-Author-Via", "DAV"); - - /* - ** Determine which methods are allowed on the resource. - ** Three cases: resource is null (3), is lock-null (7.4), or exists. - ** - ** All cases support OPTIONS, and if there is a lock provider, LOCK. - ** (Lock-) null resources also support MKCOL and PUT. - ** Lock-null supports PROPFIND and UNLOCK. - ** Existing resources support lots of stuff. - */ - - apr_table_addn(methods, "OPTIONS", ""); - - /* ### take into account resource type */ - switch (dav_get_resource_state(r, resource)) - { - case DAV_RESOURCE_EXISTS: - /* resource exists */ - apr_table_addn(methods, "GET", ""); - apr_table_addn(methods, "HEAD", ""); - apr_table_addn(methods, "POST", ""); - apr_table_addn(methods, "DELETE", ""); - apr_table_addn(methods, "TRACE", ""); - apr_table_addn(methods, "PROPFIND", ""); - apr_table_addn(methods, "PROPPATCH", ""); - apr_table_addn(methods, "COPY", ""); - apr_table_addn(methods, "MOVE", ""); - - if (!resource->collection) - apr_table_addn(methods, "PUT", ""); - - if (locks_hooks != NULL) { - apr_table_addn(methods, "LOCK", ""); - apr_table_addn(methods, "UNLOCK", ""); - } - - break; - - case DAV_RESOURCE_LOCK_NULL: - /* resource is lock-null. */ - apr_table_addn(methods, "MKCOL", ""); - apr_table_addn(methods, "PROPFIND", ""); - apr_table_addn(methods, "PUT", ""); - - if (locks_hooks != NULL) { - apr_table_addn(methods, "LOCK", ""); - apr_table_addn(methods, "UNLOCK", ""); - } - - break; - - case DAV_RESOURCE_NULL: - /* resource is null. */ - apr_table_addn(methods, "MKCOL", ""); - apr_table_addn(methods, "PUT", ""); - - if (locks_hooks != NULL) - apr_table_addn(methods, "LOCK", ""); - - break; - - default: - /* ### internal error! */ - break; - } - - /* If there is a versioning provider, add versioning methods */ - if (vsn_hooks != NULL) { - if (!resource->exists) { - if ((*vsn_hooks->versionable)(resource)) - apr_table_addn(methods, "VERSION-CONTROL", ""); - - if (vsn_hooks->can_be_workspace != NULL - && (*vsn_hooks->can_be_workspace)(resource)) - apr_table_addn(methods, "MKWORKSPACE", ""); - - if (vsn_hooks->can_be_activity != NULL - && (*vsn_hooks->can_be_activity)(resource)) - apr_table_addn(methods, "MKACTIVITY", ""); - } - else if (!resource->versioned) { - if ((*vsn_hooks->versionable)(resource)) - apr_table_addn(methods, "VERSION-CONTROL", ""); - } - else if (resource->working) { - apr_table_addn(methods, "CHECKIN", ""); - - /* ### we might not support this DeltaV option */ - apr_table_addn(methods, "UNCHECKOUT", ""); - } - else if (vsn_hooks->add_label != NULL) { - apr_table_addn(methods, "CHECKOUT", ""); - apr_table_addn(methods, "LABEL", ""); - } - else { - apr_table_addn(methods, "CHECKOUT", ""); - } - } - - /* If there is a bindings provider, see if resource is bindable */ - if (binding_hooks != NULL - && (*binding_hooks->is_bindable)(resource)) { - apr_table_addn(methods, "BIND", ""); - } - - /* Generate the Allow header */ - arr = apr_table_elts(methods); - elts = (apr_table_entry_t *) arr->elts; - text_size = 0; - - /* first, compute total length */ - for (i = 0; i < arr->nelts; ++i) { - if (elts[i].key == NULL) - continue; - - /* add 1 for comma or null */ - text_size += strlen(elts[i].key) + 1; - } - - s = allow = apr_palloc(r->pool, text_size); - - for (i = 0; i < arr->nelts; ++i) { - if (elts[i].key == NULL) - continue; - - if (s != allow) - *s++ = ','; - - strcpy(s, elts[i].key); - s += strlen(s); - } - - apr_table_setn(r->headers_out, "Allow", allow); - - /* if there was no request body, then there is no response body */ - if (doc == NULL) { - ap_set_content_length(r, 0); - - /* ### this sends a Content-Type. the default OPTIONS does not. */ - - /* ### the default (ap_send_http_options) returns OK, but I believe - * ### that is because it is the default handler and nothing else - * ### will run after the thing. */ - return DONE; - } - - /* handle each options request */ - for (elem = doc->root->first_child; elem != NULL; elem = elem->next) { - /* check for something we recognize first */ - int core_option = 0; - dav_error *err = NULL; - - if (elem->ns == AP_XML_NS_DAV_ID) { - if (strcmp(elem->name, "supported-method-set") == 0) { - err = dav_gen_supported_methods(r, elem, methods, &body); - core_option = 1; - } - else if (strcmp(elem->name, "supported-live-property-set") == 0) { - err = dav_gen_supported_live_props(r, resource, elem, &body); - core_option = 1; - } - else if (strcmp(elem->name, "supported-report-set") == 0) { - err = dav_gen_supported_reports(r, resource, elem, vsn_hooks, &body); - core_option = 1; - } - } - - if (err != NULL) - return dav_handle_err(r, err, NULL); - - /* if unrecognized option, pass to versioning provider */ - if (!core_option) { - if ((err = (*vsn_hooks->get_option)(resource, elem, &body)) - != NULL) { - return dav_handle_err(r, err, NULL); - } - } - } - - /* send the options response */ - r->status = HTTP_OK; - r->content_type = DAV_XML_CONTENT_TYPE; - - /* send the headers and response body */ - ap_rputs(DAV_XML_HEADER DEBUG_CR - "<D:options-response xmlns:D=\"DAV:\">" DEBUG_CR, r); - - for (t = body.first; t != NULL; t = t->next) - ap_rputs(t->text, r); - - ap_rputs("</D:options-response>" DEBUG_CR, r); - - /* we've sent everything necessary to the client. */ - return DONE; -} - -static void dav_cache_badprops(dav_walker_ctx *ctx) -{ - const ap_xml_elem *elem; - ap_text_header hdr = { 0 }; - - /* just return if we built the thing already */ - if (ctx->propstat_404 != NULL) { - return; - } - - ap_text_append(ctx->w.pool, &hdr, - "<D:propstat>" DEBUG_CR - "<D:prop>" DEBUG_CR); - - elem = dav_find_child(ctx->doc->root, "prop"); - for (elem = elem->first_child; elem; elem = elem->next) { - ap_text_append(ctx->w.pool, &hdr, - ap_xml_empty_elem(ctx->w.pool, elem)); - } - - ap_text_append(ctx->w.pool, &hdr, - "</D:prop>" DEBUG_CR - "<D:status>HTTP/1.1 404 Not Found</D:status>" DEBUG_CR - "</D:propstat>" DEBUG_CR); - - ctx->propstat_404 = hdr.first; -} - -static dav_error * dav_propfind_walker(dav_walk_resource *wres, int calltype) -{ - dav_walker_ctx *ctx = wres->walk_ctx; - dav_error *err; - dav_propdb *propdb; - dav_get_props_result propstats = { 0 }; - - /* - ** Note: ctx->doc can only be NULL for DAV_PROPFIND_IS_ALLPROP. Since - ** dav_get_allprops() does not need to do namespace translation, - ** we're okay. - ** - ** Note: we cast to lose the "const". The propdb won't try to change - ** the resource, however, since we are opening readonly. - */ - err = dav_open_propdb(ctx->r, ctx->w.lockdb, wres->resource, 1, - ctx->doc ? ctx->doc->namespaces : NULL, &propdb); - if (err != NULL) { - /* ### do something with err! */ - - if (ctx->propfind_type == DAV_PROPFIND_IS_PROP) { - dav_get_props_result badprops = { 0 }; - - /* some props were expected on this collection/resource */ - dav_cache_badprops(ctx); - badprops.propstats = ctx->propstat_404; - dav_add_response(wres, 0, &badprops); - } - else { - /* no props on this collection/resource */ - dav_add_response(wres, HTTP_OK, NULL); - } - return NULL; - } - /* ### what to do about closing the propdb on server failure? */ - - if (ctx->propfind_type == DAV_PROPFIND_IS_PROP) { - propstats = dav_get_props(propdb, ctx->doc); - } - else { - dav_prop_insert what = ctx->propfind_type == DAV_PROPFIND_IS_ALLPROP - ? DAV_PROP_INSERT_VALUE - : DAV_PROP_INSERT_NAME; - propstats = dav_get_allprops(propdb, what); - } - dav_close_propdb(propdb); - - dav_add_response(wres, 0, &propstats); - - return NULL; -} - -/* handle the PROPFIND method */ -static int dav_method_propfind(request_rec *r) -{ - dav_resource *resource; - int depth; - dav_error *err; - int result; - ap_xml_doc *doc; - const ap_xml_elem *child; - dav_walker_ctx ctx = { { 0 } }; - dav_response *multi_status; - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - if (dav_get_resource_state(r, resource) == DAV_RESOURCE_NULL) { - /* Apache will supply a default error for this. */ - return HTTP_NOT_FOUND; - } - - if ((depth = dav_get_depth(r, DAV_INFINITY)) < 0) { - /* dav_get_depth() supplies additional information for the - * default message. */ - return HTTP_BAD_REQUEST; - } - - if (depth == DAV_INFINITY && resource->collection) { - dav_dir_conf *conf; - conf = (dav_dir_conf *) ap_get_module_config(r->per_dir_config, - &dav_module); - /* default is to DISALLOW these requests */ - if (conf->allow_depthinfinity != DAV_ENABLED_ON) { - return dav_error_response(r, HTTP_FORBIDDEN, - apr_psprintf(r->pool, - "PROPFIND requests with a " - "Depth of \"infinity\" are " - "not allowed for %s.", - ap_escape_html(r->pool, - r->uri))); - } - } - - if ((result = ap_xml_parse_input(r, &doc)) != OK) { - return result; - } - /* note: doc == NULL if no request body */ - - if (doc && !dav_validate_root(doc, "propfind")) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The \"propfind\" element was not found."); - return HTTP_BAD_REQUEST; - } - - /* ### validate that only one of these three elements is present */ - - if (doc == NULL - || (child = dav_find_child(doc->root, "allprop")) != NULL) { - /* note: no request body implies allprop */ - ctx.propfind_type = DAV_PROPFIND_IS_ALLPROP; - } - else if ((child = dav_find_child(doc->root, "propname")) != NULL) { - ctx.propfind_type = DAV_PROPFIND_IS_PROPNAME; - } - else if ((child = dav_find_child(doc->root, "prop")) != NULL) { - ctx.propfind_type = DAV_PROPFIND_IS_PROP; - } - else { - /* "propfind" element must have one of the above three children */ - - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The \"propfind\" element does not contain one of " - "the required child elements (the specific command)."); - return HTTP_BAD_REQUEST; - } - - ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_AUTH; - ctx.w.func = dav_propfind_walker; - ctx.w.walk_ctx = &ctx; - ctx.w.pool = r->pool; - ctx.w.root = resource; - - ctx.doc = doc; - ctx.r = r; - - /* ### should open read-only */ - if ((err = dav_open_lockdb(r, 0, &ctx.w.lockdb)) != NULL) { - err = dav_push_error(r->pool, err->status, 0, - "The lock database could not be opened, " - "preventing access to the various lock " - "properties for the PROPFIND.", - err); - return dav_handle_err(r, err, NULL); - } - if (ctx.w.lockdb != NULL) { - /* if we have a lock database, then we can walk locknull resources */ - ctx.w.walk_type |= DAV_WALKTYPE_LOCKNULL; - } - - err = (*resource->hooks->walk)(&ctx.w, depth, &multi_status); - - if (ctx.w.lockdb != NULL) { - (*ctx.w.lockdb->hooks->close_lockdb)(ctx.w.lockdb); - } - - if (err != NULL) { - /* ### add a higher-level description? */ - return dav_handle_err(r, err, NULL); - } - - /* return a 207 (Multi-Status) response now. */ - - /* if a 404 was generated for an HREF, then we need to spit out the - * doc's namespaces for use by the 404. Note that <response> elements - * will override these ns0, ns1, etc, but NOT within the <response> - * scope for the badprops. */ - /* NOTE: propstat_404 != NULL implies doc != NULL */ - if (ctx.propstat_404 != NULL) { - dav_send_multistatus(r, HTTP_MULTI_STATUS, multi_status, - doc->namespaces); - } - else { - dav_send_multistatus(r, HTTP_MULTI_STATUS, multi_status, NULL); - } - - /* the response has been sent. */ - return DONE; -} - -static ap_text * dav_failed_proppatch(apr_pool_t *p, - apr_array_header_t *prop_ctx) -{ - ap_text_header hdr = { 0 }; - int i = prop_ctx->nelts; - dav_prop_ctx *ctx = (dav_prop_ctx *)prop_ctx->elts; - dav_error *err424_set = NULL; - dav_error *err424_delete = NULL; - const char *s; - - /* ### might be nice to sort by status code and description */ - - for ( ; i-- > 0; ++ctx ) { - ap_text_append(p, &hdr, - "<D:propstat>" DEBUG_CR - "<D:prop>"); - ap_text_append(p, &hdr, ap_xml_empty_elem(p, ctx->prop)); - ap_text_append(p, &hdr, "</D:prop>" DEBUG_CR); - - if (ctx->err == NULL) { - /* nothing was assigned here yet, so make it a 424 */ - - if (ctx->operation == DAV_PROP_OP_SET) { - if (err424_set == NULL) - err424_set = dav_new_error(p, HTTP_FAILED_DEPENDENCY, 0, - "Attempted DAV:set operation " - "could not be completed due " - "to other errors."); - ctx->err = err424_set; - } - else if (ctx->operation == DAV_PROP_OP_DELETE) { - if (err424_delete == NULL) - err424_delete = dav_new_error(p, HTTP_FAILED_DEPENDENCY, 0, - "Attempted DAV:remove " - "operation could not be " - "completed due to other " - "errors."); - ctx->err = err424_delete; - } - } - - s = apr_psprintf(p, - "<D:status>" - "HTTP/1.1 %d (status)" - "</D:status>" DEBUG_CR, - ctx->err->status); - ap_text_append(p, &hdr, s); - - /* ### we should use compute_desc if necessary... */ - if (ctx->err->desc != NULL) { - ap_text_append(p, &hdr, "<D:responsedescription>" DEBUG_CR); - ap_text_append(p, &hdr, ctx->err->desc); - ap_text_append(p, &hdr, "</D:responsedescription>" DEBUG_CR); - } - - ap_text_append(p, &hdr, "</D:propstat>" DEBUG_CR); - } - - return hdr.first; -} - -static ap_text * dav_success_proppatch(apr_pool_t *p, apr_array_header_t *prop_ctx) -{ - ap_text_header hdr = { 0 }; - int i = prop_ctx->nelts; - dav_prop_ctx *ctx = (dav_prop_ctx *)prop_ctx->elts; - - /* - ** ### we probably need to revise the way we assemble the response... - ** ### this code assumes everything will return status==200. - */ - - ap_text_append(p, &hdr, - "<D:propstat>" DEBUG_CR - "<D:prop>" DEBUG_CR); - - for ( ; i-- > 0; ++ctx ) { - ap_text_append(p, &hdr, ap_xml_empty_elem(p, ctx->prop)); - } - - ap_text_append(p, &hdr, - "</D:prop>" DEBUG_CR - "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR - "</D:propstat>" DEBUG_CR); - - return hdr.first; -} - -static void dav_prop_log_errors(dav_prop_ctx *ctx) -{ - dav_log_err(ctx->r, ctx->err, APLOG_ERR); -} - -/* -** Call <func> for each context. This can stop when an error occurs, or -** simply iterate through the whole list. -** -** Returns 1 if an error occurs (and the iteration is aborted). Returns 0 -** if all elements are processed. -** -** If <reverse> is true (non-zero), then the list is traversed in -** reverse order. -*/ -static int dav_process_ctx_list(void (*func)(dav_prop_ctx *ctx), - apr_array_header_t *ctx_list, int stop_on_error, - int reverse) -{ - int i = ctx_list->nelts; - dav_prop_ctx *ctx = (dav_prop_ctx *)ctx_list->elts; - - if (reverse) - ctx += i; - - while (i--) { - if (reverse) - --ctx; - - (*func)(ctx); - if (stop_on_error && DAV_PROP_CTX_HAS_ERR(*ctx)) { - return 1; - } - - if (!reverse) - ++ctx; - } - - return 0; -} - -/* handle the PROPPATCH method */ -static int dav_method_proppatch(request_rec *r) -{ - dav_error *err; - dav_resource *resource; - int result; - ap_xml_doc *doc; - ap_xml_elem *child; - dav_propdb *propdb; - int failure = 0; - dav_response resp = { 0 }; - ap_text *propstat_text; - apr_array_header_t *ctx_list; - dav_prop_ctx *ctx; - dav_auto_version_info av_info; - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - if (!resource->exists) { - /* Apache will supply a default error for this. */ - return HTTP_NOT_FOUND; - } - - if ((result = ap_xml_parse_input(r, &doc)) != OK) { - return result; - } - /* note: doc == NULL if no request body */ - - if (doc == NULL || !dav_validate_root(doc, "propertyupdate")) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The request body does not contain " - "a \"propertyupdate\" element."); - return HTTP_BAD_REQUEST; - } - - /* Check If-Headers and existing locks */ - /* Note: depth == 0. Implies no need for a multistatus response. */ - if ((err = dav_validate_request(r, resource, 0, NULL, NULL, - DAV_VALIDATE_RESOURCE, NULL)) != NULL) { - /* ### add a higher-level description? */ - return dav_handle_err(r, err, NULL); - } - - /* make sure the resource can be modified (if versioning repository) */ - if ((err = dav_auto_checkout(r, resource, - 0 /* not parent_only */, - &av_info)) != NULL) { - /* ### add a higher-level description? */ - return dav_handle_err(r, err, NULL); - } - - if ((err = dav_open_propdb(r, NULL, resource, 0, doc->namespaces, - &propdb)) != NULL) { - /* undo any auto-checkout */ - dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, &av_info); - - err = dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(r->pool, - "Could not open the property " - "database for %s.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, NULL); - } - /* ### what to do about closing the propdb on server failure? */ - - /* ### validate "live" properties */ - - /* set up an array to hold property operation contexts */ - ctx_list = apr_array_make(r->pool, 10, sizeof(dav_prop_ctx)); - - /* do a first pass to ensure that all "remove" properties exist */ - for (child = doc->root->first_child; child; child = child->next) { - int is_remove; - ap_xml_elem *prop_group; - ap_xml_elem *one_prop; - - /* Ignore children that are not set/remove */ - if (child->ns != AP_XML_NS_DAV_ID - || (!(is_remove = strcmp(child->name, "remove") == 0) - && strcmp(child->name, "set") != 0)) { - continue; - } - - /* make sure that a "prop" child exists for set/remove */ - if ((prop_group = dav_find_child(child, "prop")) == NULL) { - dav_close_propdb(propdb); - - /* undo any auto-checkout */ - dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, &av_info); - - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "A \"prop\" element is missing inside " - "the propertyupdate command."); - return HTTP_BAD_REQUEST; - } - - for (one_prop = prop_group->first_child; one_prop; - one_prop = one_prop->next) { - - ctx = (dav_prop_ctx *)apr_array_push(ctx_list); - ctx->propdb = propdb; - ctx->operation = is_remove ? DAV_PROP_OP_DELETE : DAV_PROP_OP_SET; - ctx->prop = one_prop; - - ctx->r = r; /* for later use by dav_prop_log_errors() */ - - dav_prop_validate(ctx); - - if ( DAV_PROP_CTX_HAS_ERR(*ctx) ) { - failure = 1; - } - } - } - - /* ### should test that we found at least one set/remove */ - - /* execute all of the operations */ - if (!failure && dav_process_ctx_list(dav_prop_exec, ctx_list, 1, 0)) { - failure = 1; - } - - /* generate a failure/success response */ - if (failure) { - (void)dav_process_ctx_list(dav_prop_rollback, ctx_list, 0, 1); - propstat_text = dav_failed_proppatch(r->pool, ctx_list); - } - else { - (void)dav_process_ctx_list(dav_prop_commit, ctx_list, 0, 0); - propstat_text = dav_success_proppatch(r->pool, ctx_list); - } - - /* make sure this gets closed! */ - dav_close_propdb(propdb); - - /* complete any auto-versioning */ - dav_auto_checkin(r, resource, failure, 0 /*unlock*/, &av_info); - - /* log any errors that occurred */ - (void)dav_process_ctx_list(dav_prop_log_errors, ctx_list, 0, 0); - - resp.href = resource->uri; - - /* ### should probably use something new to pass along this text... */ - resp.propresult.propstats = propstat_text; - - dav_send_multistatus(r, HTTP_MULTI_STATUS, &resp, doc->namespaces); - - /* the response has been sent. */ - return DONE; -} - -static int process_mkcol_body(request_rec *r) -{ - /* This is snarfed from ap_setup_client_block(). We could get pretty - * close to this behavior by passing REQUEST_NO_BODY, but we need to - * return HTTP_UNSUPPORTED_MEDIA_TYPE (while ap_setup_client_block - * returns HTTP_REQUEST_ENTITY_TOO_LARGE). */ - - const char *tenc = apr_table_get(r->headers_in, "Transfer-Encoding"); - const char *lenp = apr_table_get(r->headers_in, "Content-Length"); - - /* make sure to set the Apache request fields properly. */ - r->read_body = REQUEST_NO_BODY; - r->read_chunked = 0; - r->remaining = 0; - - if (tenc) { - if (strcasecmp(tenc, "chunked")) { - /* Use this instead of Apache's default error string */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "Unknown Transfer-Encoding %s", tenc); - return HTTP_NOT_IMPLEMENTED; - } - - r->read_chunked = 1; - } - else if (lenp) { - const char *pos = lenp; - - while (apr_isdigit(*pos) || apr_isspace(*pos)) { - ++pos; - } - if (*pos != '\0') { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "Invalid Content-Length %s", lenp); - return HTTP_BAD_REQUEST; - } - - r->remaining = atol(lenp); - } - - if (r->read_chunked || r->remaining > 0) { - /* ### log something? */ - - /* Apache will supply a default error for this. */ - return HTTP_UNSUPPORTED_MEDIA_TYPE; - } - - /* - ** Get rid of the body. this will call ap_setup_client_block(), but - ** our copy above has already verified its work. - */ - return ap_discard_request_body(r); -} - -/* handle the MKCOL method */ -static int dav_method_mkcol(request_rec *r) -{ - dav_resource *resource; - int resource_state; - dav_auto_version_info av_info; - const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r); - dav_error *err; - dav_error *err2; - int result; - dav_dir_conf *conf; - dav_response *multi_status; - - /* handle the request body */ - /* ### this may move lower once we start processing bodies */ - if ((result = process_mkcol_body(r)) != OK) { - return result; - } - - conf = (dav_dir_conf *) ap_get_module_config(r->per_dir_config, - &dav_module); - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - if (resource->exists) { - /* oops. something was already there! */ - - /* Apache will supply a default error for this. */ - /* ### we should provide a specific error message! */ - return HTTP_METHOD_NOT_ALLOWED; - } - - resource_state = dav_get_resource_state(r, resource); - - /* - ** Check If-Headers and existing locks. - ** - ** Note: depth == 0 normally requires no multistatus response. However, - ** if we pass DAV_VALIDATE_PARENT, then we could get an error on a URI - ** other than the Request-URI, thereby requiring a multistatus. - ** - ** If the resource does not exist (DAV_RESOURCE_NULL), then we must - ** check the resource *and* its parent. If the resource exists or is - ** a locknull resource, then we check only the resource. - */ - if ((err = dav_validate_request(r, resource, 0, NULL, &multi_status, - resource_state == DAV_RESOURCE_NULL ? - DAV_VALIDATE_PARENT : - DAV_VALIDATE_RESOURCE, NULL)) != NULL) { - /* ### add a higher-level description? */ - return dav_handle_err(r, err, multi_status); - } - - /* if versioned resource, make sure parent is checked out */ - if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */, - &av_info)) != NULL) { - /* ### add a higher-level description? */ - return dav_handle_err(r, err, NULL); - } - - /* try to create the collection */ - resource->collection = 1; - err = (*resource->hooks->create_collection)(resource); - - /* restore modifiability of parent back to what it was */ - err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */, - 0 /*unlock*/, &av_info); - - /* check for errors now */ - if (err != NULL) { - return dav_handle_err(r, err, NULL); - } - if (err2 != NULL) { - /* just log a warning */ - err = dav_push_error(r->pool, err->status, 0, - "The MKCOL was successful, but there " - "was a problem automatically checking in " - "the parent collection.", - err2); - dav_log_err(r, err, APLOG_WARNING); - } - - if (locks_hooks != NULL) { - dav_lockdb *lockdb; - - if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) { - /* The directory creation was successful, but the locking failed. */ - err = dav_push_error(r->pool, err->status, 0, - "The MKCOL was successful, but there " - "was a problem opening the lock database " - "which prevents inheriting locks from the " - "parent resources.", - err); - return dav_handle_err(r, err, NULL); - } - - /* notify lock system that we have created/replaced a resource */ - err = dav_notify_created(r, lockdb, resource, resource_state, 0); - - (*locks_hooks->close_lockdb)(lockdb); - - if (err != NULL) { - /* The dir creation was successful, but the locking failed. */ - err = dav_push_error(r->pool, err->status, 0, - "The MKCOL was successful, but there " - "was a problem updating its lock " - "information.", - err); - return dav_handle_err(r, err, NULL); - } - } - - /* return an appropriate response (HTTP_CREATED) */ - return dav_created(r, NULL, "Collection", 0); -} - -/* handle the COPY and MOVE methods */ -static int dav_method_copymove(request_rec *r, int is_move) -{ - dav_resource *resource; - dav_resource *resnew; - dav_auto_version_info src_av_info = { 0 }; - dav_auto_version_info dst_av_info = { 0 }; - const char *body; - const char *dest; - dav_error *err; - dav_error *err2; - dav_error *err3; - dav_response *multi_response; - dav_lookup_result lookup; - int is_dir; - int overwrite; - int depth; - int result; - dav_lockdb *lockdb; - int replace_dest; - int resnew_state; - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, !is_move /* label_allowed */, - 0 /* use_checked_in */, &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - if (!resource->exists) { - /* Apache will supply a default error for this. */ - return HTTP_NOT_FOUND; - } - - /* If not a file or collection resource, COPY/MOVE not allowed */ - /* ### allow COPY/MOVE of DeltaV resource types */ - if (resource->type != DAV_RESOURCE_TYPE_REGULAR) { - body = apr_psprintf(r->pool, - "Cannot COPY/MOVE resource %s.", - ap_escape_html(r->pool, r->uri)); - return dav_error_response(r, HTTP_METHOD_NOT_ALLOWED, body); - } - - /* get the destination URI */ - dest = apr_table_get(r->headers_in, "Destination"); - if (dest == NULL) { - /* Look in headers provided by Netscape's Roaming Profiles */ - const char *nscp_host = apr_table_get(r->headers_in, "Host"); - const char *nscp_path = apr_table_get(r->headers_in, "New-uri"); - - if (nscp_host != NULL && nscp_path != NULL) - dest = apr_psprintf(r->pool, "http://%s%s", nscp_host, nscp_path); - } - if (dest == NULL) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The request is missing a Destination header."); - return HTTP_BAD_REQUEST; - } - - lookup = dav_lookup_uri(dest, r, 1 /* must_be_absolute */); - if (lookup.rnew == NULL) { - if (lookup.err.status == HTTP_BAD_REQUEST) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - lookup.err.desc); - return HTTP_BAD_REQUEST; - } - - /* ### this assumes that dav_lookup_uri() only generates a status - * ### that Apache can provide a status line for!! */ - - return dav_error_response(r, lookup.err.status, lookup.err.desc); - } - if (lookup.rnew->status != HTTP_OK) { - /* ### how best to report this... */ - return dav_error_response(r, lookup.rnew->status, - "Destination URI had an error."); - } - - /* Resolve destination resource */ - err = dav_get_resource(lookup.rnew, 0 /* label_allowed */, - 0 /* use_checked_in */, &resnew); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - /* are the two resources handled by the same repository? */ - if (resource->hooks != resnew->hooks) { - /* ### this message exposes some backend config, but screw it... */ - return dav_error_response(r, HTTP_BAD_GATEWAY, - "Destination URI is handled by a " - "different repository than the source URI. " - "MOVE or COPY between repositories is " - "not possible."); - } - - /* get and parse the overwrite header value */ - if ((overwrite = dav_get_overwrite(r)) < 0) { - /* dav_get_overwrite() supplies additional information for the - * default message. */ - return HTTP_BAD_REQUEST; - } - - /* quick failure test: if dest exists and overwrite is false. */ - if (resnew->exists && !overwrite) { - /* Supply some text for the error response body. */ - return dav_error_response(r, HTTP_PRECONDITION_FAILED, - "Destination is not empty and " - "Overwrite is not \"T\""); - } - - /* are the source and destination the same? */ - if ((*resource->hooks->is_same_resource)(resource, resnew)) { - /* Supply some text for the error response body. */ - return dav_error_response(r, HTTP_FORBIDDEN, - "Source and Destination URIs are the same."); - - } - - is_dir = resource->collection; - - /* get and parse the Depth header value. "0" and "infinity" are legal. */ - if ((depth = dav_get_depth(r, DAV_INFINITY)) < 0) { - /* dav_get_depth() supplies additional information for the - * default message. */ - return HTTP_BAD_REQUEST; - } - if (depth == 1) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "Depth must be \"0\" or \"infinity\" for COPY or MOVE."); - return HTTP_BAD_REQUEST; - } - if (is_move && is_dir && depth != DAV_INFINITY) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "Depth must be \"infinity\" when moving a collection."); - return HTTP_BAD_REQUEST; - } - - /* - ** Check If-Headers and existing locks for each resource in the source - ** if we are performing a MOVE. We will return a 424 response with a - ** DAV:multistatus body. The multistatus responses will contain the - ** information about any resource that fails the validation. - ** - ** We check the parent resource, too, since this is a MOVE. Moving the - ** resource effectively removes it from the parent collection, so we - ** must ensure that we have met the appropriate conditions. - ** - ** If a problem occurs with the Request-URI itself, then a plain error - ** (rather than a multistatus) will be returned. - */ - if (is_move - && (err = dav_validate_request(r, resource, depth, NULL, - &multi_response, - DAV_VALIDATE_PARENT - | DAV_VALIDATE_USE_424, - NULL)) != NULL) { - err = dav_push_error(r->pool, err->status, 0, - apr_psprintf(r->pool, - "Could not MOVE %s due to a failed " - "precondition on the source " - "(e.g. locks).", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, multi_response); - } - - /* - ** Check If-Headers and existing locks for destination. Note that we - ** use depth==infinity since the target (hierarchy) will be deleted - ** before the move/copy is completed. - ** - ** Note that we are overwriting the target, which implies a DELETE, so - ** we are subject to the error/response rules as a DELETE. Namely, we - ** will return a 424 error if any of the validations fail. - ** (see dav_method_delete() for more information) - */ - if ((err = dav_validate_request(lookup.rnew, resnew, DAV_INFINITY, NULL, - &multi_response, - DAV_VALIDATE_PARENT - | DAV_VALIDATE_USE_424, NULL)) != NULL) { - err = dav_push_error(r->pool, err->status, 0, - apr_psprintf(r->pool, - "Could not MOVE/COPY %s due to a " - "failed precondition on the " - "destination (e.g. locks).", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, multi_response); - } - - if (is_dir - && depth == DAV_INFINITY - && (*resource->hooks->is_parent_resource)(resource, resnew)) { - /* Supply some text for the error response body. */ - return dav_error_response(r, HTTP_FORBIDDEN, - "Source collection contains the " - "Destination."); - - } - if (is_dir - && (*resnew->hooks->is_parent_resource)(resnew, resource)) { - /* The destination must exist (since it contains the source), and - * a condition above implies Overwrite==T. Obviously, we cannot - * delete the Destination before the MOVE/COPY, as that would - * delete the Source. - */ - - /* Supply some text for the error response body. */ - return dav_error_response(r, HTTP_FORBIDDEN, - "Destination collection contains the Source " - "and Overwrite has been specified."); - } - - /* ### for now, we don't need anything in the body */ - if ((result = ap_discard_request_body(r)) != OK) { - return result; - } - - if ((err = dav_open_lockdb(r, 0, &lockdb)) != NULL) { - /* ### add a higher-level description? */ - return dav_handle_err(r, err, NULL); - } - - /* remove any locks from the old resources */ - /* - ** ### this is Yet Another Traversal. if we do a rename(), then we - ** ### really don't have to do this in some cases since the inode - ** ### values will remain constant across the move. but we can't - ** ### know that fact from outside the provider :-( - ** - ** ### note that we now have a problem atomicity in the move/copy - ** ### since a failure after this would have removed locks (technically, - ** ### this is okay to do, but really...) - */ - if (is_move && lockdb != NULL) { - /* ### this is wrong! it blasts direct locks on parent resources */ - /* ### pass lockdb! */ - (void)dav_unlock(r, resource, NULL); - } - - /* if this is a move, then the source parent collection will be modified */ - if (is_move) { - if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */, - &src_av_info)) != NULL) { - if (lockdb != NULL) - (*lockdb->hooks->close_lockdb)(lockdb); - - /* ### add a higher-level description? */ - return dav_handle_err(r, err, NULL); - } - } - - /* - * Remember the initial state of the destination, so the lock system - * can be notified as to how it changed. - */ - resnew_state = dav_get_resource_state(lookup.rnew, resnew); - - /* If destination does not exist, initialize resource object - * to be same type as the source. - */ - if (!resnew->exists) { - resnew->type = resource->type; - resnew->collection = resource->collection; - } - - /* In a MOVE operation, the destination is replaced by the source. - * In a COPY operation, if the destination exists, is under version - * control, and is the same resource type as the source, - * then it should not be replaced, but modified to be a copy of - * the source. - */ - if (!resnew->exists) - replace_dest = 0; - else if (is_move || !resource->versioned) - replace_dest = 1; - else if (resource->type != resnew->type) - replace_dest = 1; - else if ((resource->collection == 0) != (resnew->collection == 0)) - replace_dest = 1; - else - replace_dest = 0; - - /* If the destination must be created or replaced, - * make sure the parent collection is writable - */ - if (!resnew->exists || replace_dest) { - if ((err = dav_auto_checkout(r, resnew, 1 /*parent_only*/, - &dst_av_info)) != NULL) { - /* could not make destination writable: - * if move, restore state of source parent - */ - if (is_move) { - (void) dav_auto_checkin(r, NULL, 1 /* undo */, - 0 /*unlock*/, &src_av_info); - } - - if (lockdb != NULL) - (*lockdb->hooks->close_lockdb)(lockdb); - - /* ### add a higher-level description? */ - return dav_handle_err(r, err, NULL); - } - } - - /* If source and destination parents are the same, then - * use the same resource object, so status updates to one are reflected - * in the other, when doing auto-versioning. Otherwise, - * we may try to checkin the parent twice. - */ - if (src_av_info.parent_resource != NULL - && dst_av_info.parent_resource != NULL - && (*src_av_info.parent_resource->hooks->is_same_resource) - (src_av_info.parent_resource, dst_av_info.parent_resource)) { - - dst_av_info.parent_resource = src_av_info.parent_resource; - } - - /* If destination is being replaced, remove it first - * (we know Ovewrite must be TRUE). Then try to copy/move the resource. - */ - if (replace_dest) - err = (*resnew->hooks->remove_resource)(resnew, &multi_response); - - if (err == NULL) { - if (is_move) - err = (*resource->hooks->move_resource)(resource, resnew, - &multi_response); - else - err = (*resource->hooks->copy_resource)(resource, resnew, depth, - &multi_response); - } - - /* perform any auto-versioning cleanup */ - err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */, - 0 /*unlock*/, &dst_av_info); - - if (is_move) { - err3 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */, - 0 /*unlock*/, &src_av_info); - } - else - err3 = NULL; - - /* check for error from remove/copy/move operations */ - if (err != NULL) { - if (lockdb != NULL) - (*lockdb->hooks->close_lockdb)(lockdb); - - err = dav_push_error(r->pool, err->status, 0, - apr_psprintf(r->pool, - "Could not MOVE/COPY %s.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, multi_response); - } - - /* check for errors from auto-versioning */ - if (err2 != NULL) { - /* just log a warning */ - err = dav_push_error(r->pool, err2->status, 0, - "The MOVE/COPY was successful, but there was a " - "problem automatically checking in the " - "source parent collection.", - err2); - dav_log_err(r, err, APLOG_WARNING); - } - if (err3 != NULL) { - /* just log a warning */ - err = dav_push_error(r->pool, err3->status, 0, - "The MOVE/COPY was successful, but there was a " - "problem automatically checking in the " - "destination or its parent collection.", - err3); - dav_log_err(r, err, APLOG_WARNING); - } - - /* propagate any indirect locks at the target */ - if (lockdb != NULL) { - - /* notify lock system that we have created/replaced a resource */ - err = dav_notify_created(r, lockdb, resnew, resnew_state, depth); - - (*lockdb->hooks->close_lockdb)(lockdb); - - if (err != NULL) { - /* The move/copy was successful, but the locking failed. */ - err = dav_push_error(r->pool, err->status, 0, - "The MOVE/COPY was successful, but there " - "was a problem updating the lock " - "information.", - err); - return dav_handle_err(r, err, NULL); - } - } - - /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */ - return dav_created(r, lookup.rnew->uri, "Destination", - resnew_state == DAV_RESOURCE_EXISTS); -} - -/* dav_method_lock: Handler to implement the DAV LOCK method -** Returns appropriate HTTP_* response. -*/ -static int dav_method_lock(request_rec *r) -{ - dav_error *err; - dav_resource *resource; - const dav_hooks_locks *locks_hooks; - int result; - int depth; - int new_lock_request = 0; - ap_xml_doc *doc; - dav_lock *lock; - dav_response *multi_response = NULL; - dav_lockdb *lockdb; - int resource_state; - - /* If no locks provider, decline the request */ - locks_hooks = DAV_GET_HOOKS_LOCKS(r); - if (locks_hooks == NULL) - return DECLINED; - - if ((result = ap_xml_parse_input(r, &doc)) != OK) - return result; - - depth = dav_get_depth(r, DAV_INFINITY); - if (depth != 0 && depth != DAV_INFINITY) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "Depth must be 0 or \"infinity\" for LOCK."); - return HTTP_BAD_REQUEST; - } - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - /* - ** Open writable. Unless an error occurs, we'll be - ** writing into the database. - */ - if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) { - /* ### add a higher-level description? */ - return dav_handle_err(r, err, NULL); - } - - if (doc != NULL) { - if ((err = dav_lock_parse_lockinfo(r, resource, lockdb, doc, - &lock)) != NULL) { - /* ### add a higher-level description to err? */ - goto error; - } - new_lock_request = 1; - - lock->auth_user = apr_pstrdup(r->pool, r->user); - } - - resource_state = dav_get_resource_state(r, resource); - - /* - ** Check If-Headers and existing locks. - ** - ** If this will create a locknull resource, then the LOCK will affect - ** the parent collection (much like a PUT/MKCOL). For that case, we must - ** validate the parent resource's conditions. - */ - if ((err = dav_validate_request(r, resource, depth, NULL, &multi_response, - (resource_state == DAV_RESOURCE_NULL - ? DAV_VALIDATE_PARENT - : DAV_VALIDATE_RESOURCE) - | (new_lock_request ? lock->scope : 0) - | DAV_VALIDATE_ADD_LD, - lockdb)) != OK) { - err = dav_push_error(r->pool, err->status, 0, - apr_psprintf(r->pool, - "Could not LOCK %s due to a failed " - "precondition (e.g. other locks).", - ap_escape_html(r->pool, r->uri)), - err); - goto error; - } - - if (new_lock_request == 0) { - dav_locktoken_list *ltl; - - /* - ** Refresh request - ** ### Assumption: We can renew multiple locks on the same resource - ** ### at once. First harvest all the positive lock-tokens given in - ** ### the If header. Then modify the lock entries for this resource - ** ### with the new Timeout val. - */ - - if ((err = dav_get_locktoken_list(r, <l)) != NULL) { - err = dav_push_error(r->pool, err->status, 0, - apr_psprintf(r->pool, - "The lock refresh for %s failed " - "because no lock tokens were " - "specified in an \"If:\" " - "header.", - ap_escape_html(r->pool, r->uri)), - err); - goto error; - } - - if ((err = (*locks_hooks->refresh_locks)(lockdb, resource, ltl, - dav_get_timeout(r), - &lock)) != NULL) { - /* ### add a higher-level description to err? */ - goto error; - } - } else { - /* New lock request */ - char *locktoken_txt; - dav_dir_conf *conf; - - conf = (dav_dir_conf *) ap_get_module_config(r->per_dir_config, - &dav_module); - - /* apply lower bound (if any) from DAVMinTimeout directive */ - if (lock->timeout != DAV_TIMEOUT_INFINITE - && lock->timeout < time(NULL) + conf->locktimeout) - lock->timeout = time(NULL) + conf->locktimeout; - - err = dav_add_lock(r, resource, lockdb, lock, &multi_response); - if (err != NULL) { - /* ### add a higher-level description to err? */ - goto error; - } - - locktoken_txt = apr_pstrcat(r->pool, "<", - (*locks_hooks->format_locktoken)(r->pool, lock->locktoken), - ">", NULL); - - apr_table_set(r->headers_out, "Lock-Token", locktoken_txt); - } - - (*locks_hooks->close_lockdb)(lockdb); - - r->status = HTTP_OK; - r->content_type = DAV_XML_CONTENT_TYPE; - - ap_rputs(DAV_XML_HEADER DEBUG_CR "<D:prop xmlns:D=\"DAV:\">" DEBUG_CR, r); - if (lock == NULL) - ap_rputs("<D:lockdiscovery/>" DEBUG_CR, r); - else { - ap_rprintf(r, - "<D:lockdiscovery>" DEBUG_CR - "%s" DEBUG_CR - "</D:lockdiscovery>" DEBUG_CR, - dav_lock_get_activelock(r, lock, NULL)); - } - ap_rputs("</D:prop>", r); - - /* the response has been sent. */ - return DONE; - - error: - (*locks_hooks->close_lockdb)(lockdb); - return dav_handle_err(r, err, multi_response); -} - -/* dav_method_unlock: Handler to implement the DAV UNLOCK method - * Returns appropriate HTTP_* response. - */ -static int dav_method_unlock(request_rec *r) -{ - dav_error *err; - dav_resource *resource; - const dav_hooks_locks *locks_hooks; - int result; - const char *const_locktoken_txt; - char *locktoken_txt; - dav_locktoken *locktoken = NULL; - int resource_state; - dav_response *multi_response; - - /* If no locks provider, decline the request */ - locks_hooks = DAV_GET_HOOKS_LOCKS(r); - if (locks_hooks == NULL) - return DECLINED; - - if ((const_locktoken_txt = apr_table_get(r->headers_in, "Lock-Token")) == NULL) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "Unlock failed (%s): No Lock-Token specified in header", r->filename); - return HTTP_BAD_REQUEST; - } - - locktoken_txt = apr_pstrdup(r->pool, const_locktoken_txt); - if (locktoken_txt[0] != '<') { - /* ### should provide more specifics... */ - return HTTP_BAD_REQUEST; - } - locktoken_txt++; - - if (locktoken_txt[strlen(locktoken_txt) - 1] != '>') { - /* ### should provide more specifics... */ - return HTTP_BAD_REQUEST; - } - locktoken_txt[strlen(locktoken_txt) - 1] = '\0'; - - if ((err = (*locks_hooks->parse_locktoken)(r->pool, locktoken_txt, - &locktoken)) != NULL) { - err = dav_push_error(r->pool, HTTP_BAD_REQUEST, 0, - apr_psprintf(r->pool, - "The UNLOCK on %s failed -- an " - "invalid lock token was specified " - "in the \"If:\" header.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, NULL); - } - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - resource_state = dav_get_resource_state(r, resource); - - /* - ** Check If-Headers and existing locks. - ** - ** Note: depth == 0 normally requires no multistatus response. However, - ** if we pass DAV_VALIDATE_PARENT, then we could get an error on a URI - ** other than the Request-URI, thereby requiring a multistatus. - ** - ** If the resource is a locknull resource, then the UNLOCK will affect - ** the parent collection (much like a delete). For that case, we must - ** validate the parent resource's conditions. - */ - if ((err = dav_validate_request(r, resource, 0, locktoken, - &multi_response, - resource_state == DAV_RESOURCE_LOCK_NULL - ? DAV_VALIDATE_PARENT - : DAV_VALIDATE_RESOURCE, NULL)) != NULL) { - /* ### add a higher-level description? */ - return dav_handle_err(r, err, multi_response); - } - - /* ### RFC 2518 s. 8.11: If this resource is locked by locktoken, - * _all_ resources locked by locktoken are released. It does not say - * resource has to be the root of an infinte lock. Thus, an UNLOCK - * on any part of an infinte lock will remove the lock on all resources. - * - * For us, if r->filename represents an indirect lock (part of an infinity lock), - * we must actually perform an UNLOCK on the direct lock for this resource. - */ - if ((result = dav_unlock(r, resource, locktoken)) != OK) { - return result; - } - - return HTTP_NO_CONTENT; -} - -static int dav_method_vsn_control(request_rec *r) -{ - dav_resource *resource; - int resource_state; - dav_auto_version_info av_info; - const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r); - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); - dav_error *err; - ap_xml_doc *doc; - const char *target = NULL; - int result; - - /* if no versioning provider, decline the request */ - if (vsn_hooks == NULL) - return DECLINED; - - /* ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - /* remember the pre-creation resource state */ - resource_state = dav_get_resource_state(r, resource); - - /* parse the request body (may be a version-control element) */ - if ((result = ap_xml_parse_input(r, &doc)) != OK) { - return result; - } - /* note: doc == NULL if no request body */ - - if (doc != NULL) { - const ap_xml_elem *child; - apr_size_t tsize; - - if (!dav_validate_root(doc, "version-control")) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The request body does not contain " - "a \"version-control\" element."); - return HTTP_BAD_REQUEST; - } - - /* get the version URI */ - if ((child = dav_find_child(doc->root, "version")) == NULL) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The \"version-control\" element does not contain " - "a \"version\" element."); - return HTTP_BAD_REQUEST; - } - - if ((child = dav_find_child(child, "href")) == NULL) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The \"version\" element does not contain " - "an \"href\" element."); - return HTTP_BAD_REQUEST; - } - - /* get version URI */ - ap_xml_to_text(r->pool, child, AP_XML_X2T_INNER, NULL, NULL, - &target, &tsize); - if (tsize == 0) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "An \"href\" element does not contain a URI."); - return HTTP_BAD_REQUEST; - } - } - - /* Check request preconditions */ - - /* ### need a general mechanism for reporting precondition violations - * ### (should be returning XML document for 403/409 responses) - */ - - /* if not versioning existing resource, must specify version to select */ - if (!resource->exists && target == NULL) { - err = dav_new_error(r->pool, HTTP_CONFLICT, 0, - "<DAV:initial-version-required/>"); - return dav_handle_err(r, err, NULL); - } - else if (resource->exists) { - /* cannot add resource to existing version history */ - if (target != NULL) { - err = dav_new_error(r->pool, HTTP_CONFLICT, 0, - "<DAV:cannot-add-to-existing-history/>"); - return dav_handle_err(r, err, NULL); - } - - /* resource must be unversioned and versionable, or version selector */ - if (resource->type != DAV_RESOURCE_TYPE_REGULAR - || (!resource->versioned && !(vsn_hooks->versionable)(resource))) { - err = dav_new_error(r->pool, HTTP_CONFLICT, 0, - "<DAV:must-be-versionable/>"); - return dav_handle_err(r, err, NULL); - } - - /* the DeltaV spec says if resource is a version selector, - * then VERSION-CONTROL is a no-op - */ - if (resource->versioned) { - /* set the Cache-Control header, per the spec */ - apr_table_setn(r->headers_out, "Cache-Control", "no-cache"); - - /* no body */ - ap_set_content_length(r, 0); - - return DONE; - } - } - - /* Check If-Headers and existing locks */ - /* Note: depth == 0. Implies no need for a multistatus response. */ - if ((err = dav_validate_request(r, resource, 0, NULL, NULL, - resource_state == DAV_RESOURCE_NULL ? - DAV_VALIDATE_PARENT : - DAV_VALIDATE_RESOURCE, NULL)) != NULL) { - return dav_handle_err(r, err, NULL); - } - - /* if in versioned collection, make sure parent is checked out */ - if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */, - &av_info)) != NULL) { - return dav_handle_err(r, err, NULL); - } - - /* attempt to version-control the resource */ - if ((err = (*vsn_hooks->vsn_control)(resource, target)) != NULL) { - dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, &av_info); - err = dav_push_error(r->pool, HTTP_CONFLICT, 0, - apr_psprintf(r->pool, - "Could not VERSION-CONTROL resource %s.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, NULL); - } - - /* revert writability of parent directory */ - err = dav_auto_checkin(r, resource, 0 /*undo*/, 0 /*unlock*/, &av_info); - if (err != NULL) { - /* just log a warning */ - err = dav_push_error(r->pool, err->status, 0, - "The VERSION-CONTROL was successful, but there " - "was a problem automatically checking in " - "the parent collection.", - err); - dav_log_err(r, err, APLOG_WARNING); - } - - /* if the resource is lockable, let lock system know of new resource */ - if (locks_hooks != NULL - && (*locks_hooks->get_supportedlock)(resource) != NULL) { - dav_lockdb *lockdb; - - if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) { - /* The resource creation was successful, but the locking failed. */ - err = dav_push_error(r->pool, err->status, 0, - "The VERSION-CONTROL was successful, but there " - "was a problem opening the lock database " - "which prevents inheriting locks from the " - "parent resources.", - err); - return dav_handle_err(r, err, NULL); - } - - /* notify lock system that we have created/replaced a resource */ - err = dav_notify_created(r, lockdb, resource, resource_state, 0); - - (*locks_hooks->close_lockdb)(lockdb); - - if (err != NULL) { - /* The dir creation was successful, but the locking failed. */ - err = dav_push_error(r->pool, err->status, 0, - "The VERSION-CONTROL was successful, but there " - "was a problem updating its lock " - "information.", - err); - return dav_handle_err(r, err, NULL); - } - } - - /* set the Cache-Control header, per the spec */ - apr_table_setn(r->headers_out, "Cache-Control", "no-cache"); - - /* return an appropriate response (HTTP_CREATED) */ - return dav_created(r, resource->uri, "Version selector", 0 /*replaced*/); -} - -/* handle the CHECKOUT method */ -static int dav_method_checkout(request_rec *r) -{ - dav_resource *resource; - dav_resource *working_resource; - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); - dav_error *err; - int result; - ap_xml_doc *doc; - int apply_to_vsn = 0; - int is_unreserved = 0; - int is_fork_ok = 0; - int create_activity = 0; - apr_array_header_t *activities = NULL; - - /* If no versioning provider, decline the request */ - if (vsn_hooks == NULL) - return DECLINED; - - if ((result = ap_xml_parse_input(r, &doc)) != OK) - return result; - - if (doc != NULL) { - const ap_xml_elem *aset; - - if (!dav_validate_root(doc, "checkout")) { - /* This supplies additional information for the default msg. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The request body, if present, must be a " - "DAV:checkout element."); - return HTTP_BAD_REQUEST; - } - - if (dav_find_child(doc->root, "apply-to-version") != NULL) { - if (apr_table_get(r->headers_in, "label") != NULL) { - /* ### we want generic 403/409 XML reporting here */ - /* ### DAV:must-not-have-label-and-apply-to-version */ - return dav_error_response(r, HTTP_CONFLICT, - "DAV:apply-to-version cannot be " - "used in conjunction with a " - "Label header."); - } - apply_to_vsn = 1; - } - - is_unreserved = dav_find_child(doc->root, "unreserved") != NULL; - is_fork_ok = dav_find_child(doc->root, "fork-ok") != NULL; - - if ((aset = dav_find_child(doc->root, "activity-set")) != NULL) { - if (dav_find_child(aset, "new") != NULL) { - create_activity = 1; - } - else { - const ap_xml_elem *child = aset->first_child; - - activities = apr_array_make(r->pool, 1, sizeof(const char *)); - - for (; child != NULL; child = child->next) { - if (child->ns == AP_XML_NS_DAV_ID - && strcmp(child->name, "href") == 0) { - const char *href; - - href = dav_xml_get_cdata(child, r->pool, - 1 /* strip_white */); - *(const char **)apr_array_push(activities) = href; - } - } - - if (activities->nelts == 0) { - /* no href's is a DTD violation: - <!ELEMENT activity-set (href+ | new)> - */ - - /* This supplies additional info for the default msg. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "Within the DAV:activity-set element, the " - "DAV:new element must be used, or at least " - "one DAV:href must be specified."); - return HTTP_BAD_REQUEST; - } - } - } - } - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 1 /*label_allowed*/, apply_to_vsn, &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - if (!resource->exists) { - /* Apache will supply a default error for this. */ - return HTTP_NOT_FOUND; - } - - /* Check the state of the resource: must be a file or collection, - * must be versioned, and must not already be checked out. - */ - if (resource->type != DAV_RESOURCE_TYPE_REGULAR - && resource->type != DAV_RESOURCE_TYPE_VERSION) { - return dav_error_response(r, HTTP_CONFLICT, - "Cannot checkout this type of resource."); - } - - if (!resource->versioned) { - return dav_error_response(r, HTTP_CONFLICT, - "Cannot checkout unversioned resource."); - } - - if (resource->working) { - return dav_error_response(r, HTTP_CONFLICT, - "The resource is already checked out to the workspace."); - } - - /* ### do lock checks, once behavior is defined */ - - /* Do the checkout */ - if ((err = (*vsn_hooks->checkout)(resource, 0 /*auto_checkout*/, - is_unreserved, is_fork_ok, - create_activity, activities, - &working_resource)) != NULL) { - err = dav_push_error(r->pool, HTTP_CONFLICT, 0, - apr_psprintf(r->pool, - "Could not CHECKOUT resource %s.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, NULL); - } - - /* set the Cache-Control header, per the spec */ - apr_table_setn(r->headers_out, "Cache-Control", "no-cache"); - - /* if no working resource created, return OK, - * else return CREATED with working resource URL in Location header - */ - if (working_resource == NULL) { - /* no body */ - ap_set_content_length(r, 0); - return DONE; - } - - return dav_created(r, working_resource->uri, "Checked-out resource", 0); -} - -/* handle the UNCHECKOUT method */ -static int dav_method_uncheckout(request_rec *r) -{ - dav_resource *resource; - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); - dav_error *err; - int result; - - /* If no versioning provider, decline the request */ - if (vsn_hooks == NULL) - return DECLINED; - - if ((result = ap_discard_request_body(r)) != OK) { - return result; - } - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - if (!resource->exists) { - /* Apache will supply a default error for this. */ - return HTTP_NOT_FOUND; - } - - /* Check the state of the resource: must be a file or collection, - * must be versioned, and must be checked out. - */ - if (resource->type != DAV_RESOURCE_TYPE_REGULAR) { - return dav_error_response(r, HTTP_CONFLICT, - "Cannot uncheckout this type of resource."); - } - - if (!resource->versioned) { - return dav_error_response(r, HTTP_CONFLICT, - "Cannot uncheckout unversioned resource."); - } - - if (!resource->working) { - return dav_error_response(r, HTTP_CONFLICT, - "The resource is not checked out to the workspace."); - } - - /* ### do lock checks, once behavior is defined */ - - /* Do the uncheckout */ - if ((err = (*vsn_hooks->uncheckout)(resource)) != NULL) { - err = dav_push_error(r->pool, HTTP_CONFLICT, 0, - apr_psprintf(r->pool, - "Could not UNCHECKOUT resource %s.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, NULL); - } - - /* no body */ - ap_set_content_length(r, 0); - - return DONE; -} - -/* handle the CHECKIN method */ -static int dav_method_checkin(request_rec *r) -{ - dav_resource *resource; - dav_resource *new_version; - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); - dav_error *err; - int result; - ap_xml_doc *doc; - int keep_checked_out = 0; - - /* If no versioning provider, decline the request */ - if (vsn_hooks == NULL) - return DECLINED; - - if ((result = ap_xml_parse_input(r, &doc)) != OK) - return result; - - if (doc != NULL) { - if (!dav_validate_root(doc, "checkin")) { - /* This supplies additional information for the default msg. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The request body, if present, must be a " - "DAV:checkin element."); - return HTTP_BAD_REQUEST; - } - - keep_checked_out = dav_find_child(doc->root, "keep-checked-out") != NULL; - } - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - if (!resource->exists) { - /* Apache will supply a default error for this. */ - return HTTP_NOT_FOUND; - } - - /* Check the state of the resource: must be a file or collection, - * must be versioned, and must be checked out. - */ - if (resource->type != DAV_RESOURCE_TYPE_REGULAR) { - return dav_error_response(r, HTTP_CONFLICT, - "Cannot checkin this type of resource."); - } - - if (!resource->versioned) { - return dav_error_response(r, HTTP_CONFLICT, - "Cannot checkin unversioned resource."); - } - - if (!resource->working) { - return dav_error_response(r, HTTP_CONFLICT, - "The resource is not checked out."); - } - - /* ### do lock checks, once behavior is defined */ - - /* Do the checkin */ - if ((err = (*vsn_hooks->checkin)(resource, keep_checked_out, &new_version)) - != NULL) { - err = dav_push_error(r->pool, HTTP_CONFLICT, 0, - apr_psprintf(r->pool, - "Could not CHECKIN resource %s.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, NULL); - } - - return dav_created(r, new_version->uri, "Version", 0); -} - -static int dav_method_update(request_rec *r) -{ - dav_resource *resource; - dav_resource *version = NULL; - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); - ap_xml_doc *doc; - ap_xml_elem *child; - int is_label = 0; - int depth; - int result; - apr_size_t tsize; - const char *target; - dav_response *multi_response; - dav_error *err; - dav_lookup_result lookup; - - /* If no versioning provider, or UPDATE not supported, - * decline the request */ - if (vsn_hooks == NULL || vsn_hooks->update == NULL) - return DECLINED; - - if ((depth = dav_get_depth(r, 0)) < 0) { - /* dav_get_depth() supplies additional information for the - * default message. */ - return HTTP_BAD_REQUEST; - } - - /* parse the request body */ - if ((result = ap_xml_parse_input(r, &doc)) != OK) { - return result; - } - - if (doc == NULL || !dav_validate_root(doc, "update")) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The request body does not contain " - "an \"update\" element."); - return HTTP_BAD_REQUEST; - } - - /* check for label-name or version element, but not both */ - if ((child = dav_find_child(doc->root, "label-name")) != NULL) - is_label = 1; - else if ((child = dav_find_child(doc->root, "version")) != NULL) { - /* get the href element */ - if ((child = dav_find_child(child, "href")) == NULL) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The version element does not contain " - "an \"href\" element."); - return HTTP_BAD_REQUEST; - } - } - else { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The \"update\" element does not contain " - "a \"label-name\" or \"version\" element."); - return HTTP_BAD_REQUEST; - } - - /* a depth greater than zero is only allowed for a label */ - if (!is_label && depth != 0) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "Depth must be zero for UPDATE with a version"); - return HTTP_BAD_REQUEST; - } - - /* get the target value (a label or a version URI) */ - ap_xml_to_text(r->pool, child, AP_XML_X2T_INNER, NULL, NULL, - &target, &tsize); - if (tsize == 0) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "A \"label-name\" or \"href\" element does not contain " - "any content."); - return HTTP_BAD_REQUEST; - } - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - if (!resource->exists) { - /* Apache will supply a default error for this. */ - return HTTP_NOT_FOUND; - } - - /* ### need a general mechanism for reporting precondition violations - * ### (should be returning XML document for 403/409 responses) - */ - if (resource->type != DAV_RESOURCE_TYPE_REGULAR - || !resource->versioned || resource->working) { - return dav_error_response(r, HTTP_CONFLICT, - "<DAV:must-be-checked-in-version-controlled-resource>"); - } - - /* if target is a version, resolve the version resource */ - /* ### dav_lookup_uri only allows absolute URIs; is that OK? */ - if (!is_label) { - lookup = dav_lookup_uri(target, r, 0 /* must_be_absolute */); - if (lookup.rnew == NULL) { - if (lookup.err.status == HTTP_BAD_REQUEST) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - lookup.err.desc); - return HTTP_BAD_REQUEST; - } - - /* ### this assumes that dav_lookup_uri() only generates a status - * ### that Apache can provide a status line for!! */ - - return dav_error_response(r, lookup.err.status, lookup.err.desc); - } - if (lookup.rnew->status != HTTP_OK) { - /* ### how best to report this... */ - return dav_error_response(r, lookup.rnew->status, - "Version URI had an error."); - } - - /* resolve version resource */ - err = dav_get_resource(lookup.rnew, 0 /* label_allowed */, - 0 /* use_checked_in */, &version); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - /* NULL out target, since we're using a version resource */ - target = NULL; - } - - /* do the UPDATE operation */ - err = (*vsn_hooks->update)(resource, version, target, depth, &multi_response); - - if (err != NULL) { - err = dav_push_error(r->pool, err->status, 0, - ap_psprintf(r->pool, - "Could not UPDATE %s.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, multi_response); - } - - /* set the Cache-Control header, per the spec */ - apr_table_setn(r->headers_out, "Cache-Control", "no-cache"); - - /* no body */ - ap_set_content_length(r, 0); - - return DONE; -} - -/* context maintained during LABEL treewalk */ -typedef struct dav_label_walker_ctx -{ - /* input: */ - dav_walk_params w; - - /* label being manipulated */ - const char *label; - - /* label operation */ - int label_op; -#define DAV_LABEL_ADD 1 -#define DAV_LABEL_SET 2 -#define DAV_LABEL_REMOVE 3 - - /* version provider hooks */ - const dav_hooks_vsn *vsn_hooks; - -} dav_label_walker_ctx; - -static dav_error * dav_label_walker(dav_walk_resource *wres, int calltype) -{ - dav_label_walker_ctx *ctx = wres->walk_ctx; - dav_error *err = NULL; - - /* Check the state of the resource: must be a version or - * non-checkedout version selector - */ - /* ### need a general mechanism for reporting precondition violations - * ### (should be returning XML document for 403/409 responses) - */ - if (wres->resource->type != DAV_RESOURCE_TYPE_VERSION && - (wres->resource->type != DAV_RESOURCE_TYPE_REGULAR - || !wres->resource->versioned)) { - err = dav_new_error(ctx->w.pool, HTTP_CONFLICT, 0, - "<DAV:must-be-version-or-version-selector/>"); - } - else if (wres->resource->working) { - err = dav_new_error(ctx->w.pool, HTTP_CONFLICT, 0, - "<DAV:must-not-be-checked-out/>"); - } - else { - /* do the label operation */ - if (ctx->label_op == DAV_LABEL_REMOVE) - err = (*ctx->vsn_hooks->remove_label)(wres->resource, ctx->label); - else - err = (*ctx->vsn_hooks->add_label)(wres->resource, ctx->label, - ctx->label_op == DAV_LABEL_SET); - } - - if (err != NULL) { - /* ### need utility routine to add response with description? */ - dav_add_response(wres, err->status, NULL); - wres->response->desc = err->desc; - } - - return NULL; -} - -static int dav_method_label(request_rec *r) -{ - dav_resource *resource; - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); - ap_xml_doc *doc; - ap_xml_elem *child; - int depth; - int result; - apr_size_t tsize; - dav_error *err; - dav_label_walker_ctx ctx = { { 0 } }; - dav_response *multi_status; - - /* If no versioning provider, or the provider doesn't support - * labels, decline the request */ - if (vsn_hooks == NULL || vsn_hooks->add_label == NULL) - return DECLINED; - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - if (!resource->exists) { - /* Apache will supply a default error for this. */ - return HTTP_NOT_FOUND; - } - - if ((depth = dav_get_depth(r, 0)) < 0) { - /* dav_get_depth() supplies additional information for the - * default message. */ - return HTTP_BAD_REQUEST; - } - - /* parse the request body */ - if ((result = ap_xml_parse_input(r, &doc)) != OK) { - return result; - } - - if (doc == NULL || !dav_validate_root(doc, "label")) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The request body does not contain " - "a \"label\" element."); - return HTTP_BAD_REQUEST; - } - - /* check for add, set, or remove element */ - if ((child = dav_find_child(doc->root, "add")) != NULL) { - ctx.label_op = DAV_LABEL_ADD; - } - else if ((child = dav_find_child(doc->root, "set")) != NULL) { - ctx.label_op = DAV_LABEL_SET; - } - else if ((child = dav_find_child(doc->root, "remove")) != NULL) { - ctx.label_op = DAV_LABEL_REMOVE; - } - else { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The \"label\" element does not contain " - "an \"add\", \"set\", or \"remove\" element."); - return HTTP_BAD_REQUEST; - } - - /* get the label string */ - if ((child = dav_find_child(child, "label-name")) == NULL) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The label command element does not contain " - "a \"label-name\" element."); - return HTTP_BAD_REQUEST; - } - - ap_xml_to_text(r->pool, child, AP_XML_X2T_INNER, NULL, NULL, - &ctx.label, &tsize); - if (tsize == 0) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "A \"label-name\" element does not contain " - "a label name."); - return HTTP_BAD_REQUEST; - } - - /* do the label operation walk */ - ctx.w.walk_type = DAV_WALKTYPE_NORMAL; - ctx.w.func = dav_label_walker; - ctx.w.walk_ctx = &ctx; - ctx.w.pool = r->pool; - ctx.w.root = resource; - ctx.vsn_hooks = vsn_hooks; - - err = (*resource->hooks->walk)(&ctx.w, depth, &multi_status); - - if (err != NULL) { - /* some sort of error occurred which terminated the walk */ - err = dav_push_error(r->pool, err->status, 0, - "The LABEL operation was terminated prematurely.", - err); - return dav_handle_err(r, err, multi_status); - } - - if (multi_status != NULL) { - /* One or more resources had errors. If depth was zero, convert - * response to simple error, else make sure there is an - * overall error to pass to dav_handle_err() - */ - if (depth == 0) { - err = dav_new_error(r->pool, multi_status->status, 0, multi_status->desc); - multi_status = NULL; - } - else { - err = dav_new_error(r->pool, HTTP_MULTI_STATUS, 0, - "Errors occurred during the LABEL operation."); - } - - return dav_handle_err(r, err, multi_status); - } - - /* set the Cache-Control header, per the spec */ - apr_table_setn(r->headers_out, "Cache-Control", "no-cache"); - - /* no body */ - ap_set_content_length(r, 0); - - return DONE; -} - -static int dav_method_report(request_rec *r) -{ - dav_resource *resource; - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); - int result; - int label_allowed; - ap_xml_doc *doc; - ap_text_header hdr = { 0 }; - ap_text *t; - dav_error *err; - - /* If no versioning provider, decline the request */ - if (vsn_hooks == NULL) - return DECLINED; - - if ((result = ap_xml_parse_input(r, &doc)) != OK) - return result; - if (doc == NULL) { - /* This supplies additional information for the default msg. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The request body must specify a report."); - return HTTP_BAD_REQUEST; - } - - /* Ask repository module to resolve the resource. - * First determine whether a Target-Selector header is allowed - * for this report. - */ - label_allowed = (*vsn_hooks->report_label_header_allowed)(doc); - err = dav_get_resource(r, label_allowed, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - if (!resource->exists) { - /* Apache will supply a default error for this. */ - return HTTP_NOT_FOUND; - } - - /* run report hook */ - /* ### writing large reports to memory could be bad... - * ### but if provider generated output directly, it would - * ### have to handle error responses as well. - */ - if ((err = (*vsn_hooks->get_report)(r, resource, doc, &hdr)) != NULL) - return dav_handle_err(r, err, NULL); - - /* send the report response */ - r->status = HTTP_OK; - r->content_type = DAV_XML_CONTENT_TYPE; - - /* send the headers and response body */ - ap_rputs(DAV_XML_HEADER DEBUG_CR, r); - - for (t = hdr.first; t != NULL; t = t->next) - ap_rputs(t->text, r); - - return DONE; -} - -static int dav_method_make_workspace(request_rec *r) -{ - dav_resource *resource; - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); - dav_error *err; - ap_xml_doc *doc; - int result; - - /* if no versioning provider, or the provider does not support workspaces, - * decline the request - */ - if (vsn_hooks == NULL || vsn_hooks->make_workspace == NULL) - return DECLINED; - - /* ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - /* parse the request body (must be a mkworkspace element) */ - if ((result = ap_xml_parse_input(r, &doc)) != OK) { - return result; - } - - if (doc == NULL - || !dav_validate_root(doc, "mkworkspace")) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The request body does not contain " - "a \"mkworkspace\" element."); - return HTTP_BAD_REQUEST; - } - - /* Check request preconditions */ - - /* ### need a general mechanism for reporting precondition violations - * ### (should be returning XML document for 403/409 responses) - */ - - /* resource must not already exist */ - if (resource->exists) { - err = dav_new_error(r->pool, HTTP_CONFLICT, 0, - "<DAV:resource-must-be-null/>"); - return dav_handle_err(r, err, NULL); - } - - /* ### what about locking? */ - - /* attempt to create the workspace */ - if ((err = (*vsn_hooks->make_workspace)(resource, doc)) != NULL) { - err = dav_push_error(r->pool, err->status, 0, - apr_psprintf(r->pool, - "Could not create workspace %s.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, NULL); - } - - /* set the Cache-Control header, per the spec */ - apr_table_setn(r->headers_out, "Cache-Control", "no-cache"); - - /* return an appropriate response (HTTP_CREATED) */ - return dav_created(r, resource->uri, "Workspace", 0 /*replaced*/); -} - -static int dav_method_make_activity(request_rec *r) -{ - dav_resource *resource; - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); - dav_error *err; - int result; - - /* if no versioning provider, or the provider does not support activities, - * decline the request - */ - if (vsn_hooks == NULL || vsn_hooks->make_activity == NULL) - return DECLINED; - - /* ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - /* MKACTIVITY does not have a defined request body. */ - if ((result = ap_discard_request_body(r)) != OK) { - return result; - } - - /* Check request preconditions */ - - /* ### need a general mechanism for reporting precondition violations - * ### (should be returning XML document for 403/409 responses) - */ - - /* resource must not already exist */ - if (resource->exists) { - err = dav_new_error(r->pool, HTTP_CONFLICT, 0, - "<DAV:resource-must-be-null/>"); - return dav_handle_err(r, err, NULL); - } - - /* ### what about locking? */ - - /* attempt to create the activity */ - if ((err = (*vsn_hooks->make_activity)(resource)) != NULL) { - err = dav_push_error(r->pool, err->status, 0, - apr_psprintf(r->pool, - "Could not create activity %s.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, NULL); - } - - /* set the Cache-Control header, per the spec */ - apr_table_setn(r->headers_out, "Cache-Control", "no-cache"); - - /* return an appropriate response (HTTP_CREATED) */ - return dav_created(r, resource->uri, "Activity", 0 /*replaced*/); -} - -static int dav_method_baseline_control(request_rec *r) -{ - /* ### */ - return HTTP_METHOD_NOT_ALLOWED; -} - -static int dav_method_merge(request_rec *r) -{ - dav_resource *resource; - dav_resource *source_resource; - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); - dav_error *err; - int result; - ap_xml_doc *doc; - ap_xml_elem *source_elem; - ap_xml_elem *href_elem; - ap_xml_elem *prop_elem; - const char *source; - int no_auto_merge; - int no_checkout; - dav_lookup_result lookup; - - /* If no versioning provider, decline the request */ - if (vsn_hooks == NULL) - return DECLINED; - - if ((result = ap_xml_parse_input(r, &doc)) != OK) - return result; - - if (doc == NULL || !dav_validate_root(doc, "merge")) { - /* This supplies additional information for the default msg. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The request body must be present and must be a " - "DAV:merge element."); - return HTTP_BAD_REQUEST; - } - - if ((source_elem = dav_find_child(doc->root, "source")) == NULL) { - /* This supplies additional information for the default msg. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The DAV:merge element must contain a DAV:source " - "element."); - return HTTP_BAD_REQUEST; - } - if ((href_elem = dav_find_child(source_elem, "href")) == NULL) { - /* This supplies additional information for the default msg. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The DAV:source element must contain a DAV:href " - "element."); - return HTTP_BAD_REQUEST; - } - source = dav_xml_get_cdata(href_elem, r->pool, 1 /* strip_white */); - - /* get a subrequest for the source, so that we can get a dav_resource - for that source. */ - lookup = dav_lookup_uri(source, r, 0 /* must_be_absolute */); - if (lookup.rnew == NULL) { - if (lookup.err.status == HTTP_BAD_REQUEST) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - lookup.err.desc); - return HTTP_BAD_REQUEST; - } - - /* ### this assumes that dav_lookup_uri() only generates a status - * ### that Apache can provide a status line for!! */ - - return dav_error_response(r, lookup.err.status, lookup.err.desc); - } - if (lookup.rnew->status != HTTP_OK) { - /* ### how best to report this... */ - return dav_error_response(r, lookup.rnew->status, - "Merge source URI had an error."); - } - err = dav_get_resource(lookup.rnew, 0 /* label_allowed */, - 0 /* use_checked_in */, &source_resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - no_auto_merge = dav_find_child(doc->root, "no-auto-merge") != NULL; - no_checkout = dav_find_child(doc->root, "no-checkout") != NULL; - - prop_elem = dav_find_child(doc->root, "prop"); - - /* ### check RFC. I believe the DAV:merge element may contain any - ### element also allowed within DAV:checkout. need to extract them - ### here, and pass them along. - ### if so, then refactor the CHECKOUT method handling so we can reuse - ### the code. maybe create a structure to hold CHECKOUT parameters - ### which can be passed to the checkout() and merge() hooks. */ - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - if (!resource->exists) { - /* Apache will supply a default error for this. */ - return HTTP_NOT_FOUND; - } - - /* ### check the source and target resources flags/types */ - - /* ### do lock checks, once behavior is defined */ - - /* set the Cache-Control header, per the spec */ - /* ### correct? */ - apr_table_setn(r->headers_out, "Cache-Control", "no-cache"); - - /* Initialize these values for a standard MERGE response. If the MERGE - is going to do something different (i.e. an error), then it must - return a dav_error, and we'll reset these values properly. */ - r->status = HTTP_OK; - r->status_line = ap_get_status_line(HTTP_OK); /* ### needed? */ - r->content_type = "text/xml"; - - /* ### should we do any preliminary response generation? probably not, - ### because we may have an error, thus demanding something else in - ### the response body. */ - - /* Do the merge, including any response generation. */ - if ((err = (*vsn_hooks->merge)(resource, source_resource, - no_auto_merge, no_checkout, - prop_elem, - r->output_filters)) != NULL) { - /* ### is err->status the right error here? */ - err = dav_push_error(r->pool, err->status, 0, - apr_psprintf(r->pool, - "Could not MERGE resource \"%s\" " - "into \"%s\".", - ap_escape_html(r->pool, source), - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, NULL); - } - - /* the response was fully generated by the merge() hook. */ - /* ### urk. does this prevent logging? need to check... */ - return DONE; -} - -static int dav_method_bind(request_rec *r) -{ - dav_resource *resource; - dav_resource *binding; - dav_auto_version_info av_info; - const dav_hooks_binding *binding_hooks = DAV_GET_HOOKS_BINDING(r); - const char *dest; - dav_error *err; - dav_error *err2; - dav_response *multi_response = NULL; - dav_lookup_result lookup; - int overwrite; - - /* If no bindings provider, decline the request */ - if (binding_hooks == NULL) - return DECLINED; - - /* Ask repository module to resolve the resource */ - err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, - &resource); - if (err != NULL) - return dav_handle_err(r, err, NULL); - if (!resource->exists) { - /* Apache will supply a default error for this. */ - return HTTP_NOT_FOUND; - } - - /* get the destination URI */ - dest = apr_table_get(r->headers_in, "Destination"); - if (dest == NULL) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "The request is missing a Destination header."); - return HTTP_BAD_REQUEST; - } - - lookup = dav_lookup_uri(dest, r, 0 /* must_be_absolute */); - if (lookup.rnew == NULL) { - if (lookup.err.status == HTTP_BAD_REQUEST) { - /* This supplies additional information for the default message. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - lookup.err.desc); - return HTTP_BAD_REQUEST; - } - else if (lookup.err.status == HTTP_BAD_GATEWAY) { - /* ### Bindings protocol draft 02 says to return 507 - * ### (Cross Server Binding Forbidden); Apache already defines 507 - * ### as HTTP_INSUFFICIENT_STORAGE. So, for now, we'll return - * ### HTTP_FORBIDDEN - */ - return dav_error_response(r, HTTP_FORBIDDEN, - "Cross server bindings are not allowed by this server."); - } - - /* ### this assumes that dav_lookup_uri() only generates a status - * ### that Apache can provide a status line for!! */ - - return dav_error_response(r, lookup.err.status, lookup.err.desc); - } - if (lookup.rnew->status != HTTP_OK) { - /* ### how best to report this... */ - return dav_error_response(r, lookup.rnew->status, - "Destination URI had an error."); - } - - /* resolve binding resource */ - err = dav_get_resource(lookup.rnew, 0 /* label_allowed */, - 0 /* use_checked_in */, &binding); - if (err != NULL) - return dav_handle_err(r, err, NULL); - - /* are the two resources handled by the same repository? */ - if (resource->hooks != binding->hooks) { - /* ### this message exposes some backend config, but screw it... */ - return dav_error_response(r, HTTP_BAD_GATEWAY, - "Destination URI is handled by a " - "different repository than the source URI. " - "BIND between repositories is not possible."); - } - - /* get and parse the overwrite header value */ - if ((overwrite = dav_get_overwrite(r)) < 0) { - /* dav_get_overwrite() supplies additional information for the - * default message. */ - return HTTP_BAD_REQUEST; - } - - /* quick failure test: if dest exists and overwrite is false. */ - if (binding->exists && !overwrite) { - return dav_error_response(r, HTTP_PRECONDITION_FAILED, - "Destination is not empty and " - "Overwrite is not \"T\""); - } - - /* are the source and destination the same? */ - if ((*resource->hooks->is_same_resource)(resource, binding)) { - return dav_error_response(r, HTTP_FORBIDDEN, - "Source and Destination URIs are the same."); - } - - /* - ** Check If-Headers and existing locks for destination. Note that we - ** use depth==infinity since the target (hierarchy) will be deleted - ** before the move/copy is completed. - ** - ** Note that we are overwriting the target, which implies a DELETE, so - ** we are subject to the error/response rules as a DELETE. Namely, we - ** will return a 424 error if any of the validations fail. - ** (see dav_method_delete() for more information) - */ - if ((err = dav_validate_request(lookup.rnew, binding, DAV_INFINITY, NULL, - &multi_response, - DAV_VALIDATE_PARENT - | DAV_VALIDATE_USE_424, NULL)) != NULL) { - err = dav_push_error(r->pool, err->status, 0, - apr_psprintf(r->pool, - "Could not BIND %s due to a " - "failed precondition on the " - "destination (e.g. locks).", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, multi_response); - } - - /* guard against creating circular bindings */ - if (resource->collection - && (*resource->hooks->is_parent_resource)(resource, binding)) { - return dav_error_response(r, HTTP_FORBIDDEN, - "Source collection contains the Destination."); - } - if (resource->collection - && (*resource->hooks->is_parent_resource)(binding, resource)) { - /* The destination must exist (since it contains the source), and - * a condition above implies Overwrite==T. Obviously, we cannot - * delete the Destination before the BIND, as that would - * delete the Source. - */ - - return dav_error_response(r, HTTP_FORBIDDEN, - "Destination collection contains the Source and " - "Overwrite has been specified."); - } - - /* prepare the destination collection for modification */ - if ((err = dav_auto_checkout(r, binding, 1 /* parent_only */, - &av_info)) != NULL) { - /* could not make destination writable */ - return dav_handle_err(r, err, NULL); - } - - /* If target exists, remove it first (we know Ovewrite must be TRUE). - * Then try to bind to the resource. - */ - if (binding->exists) - err = (*resource->hooks->remove_resource)(binding, &multi_response); - - if (err == NULL) { - err = (*binding_hooks->bind_resource)(resource, binding); - } - - /* restore parent collection states */ - err2 = dav_auto_checkin(r, NULL, - err != NULL /* undo if error */, - 0 /*unlock*/, &av_info); - - /* check for error from remove/bind operations */ - if (err != NULL) { - err = dav_push_error(r->pool, err->status, 0, - apr_psprintf(r->pool, - "Could not BIND %s.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, multi_response); - } - - /* check for errors from reverting writability */ - if (err2 != NULL) { - /* just log a warning */ - err = dav_push_error(r->pool, err2->status, 0, - "The BIND was successful, but there was a " - "problem automatically checking in the " - "source parent collection.", - err2); - dav_log_err(r, err, APLOG_WARNING); - } - - /* return an appropriate response (HTTP_CREATED) */ - /* ### spec doesn't say what happens when destination was replaced */ - return dav_created(r, lookup.rnew->uri, "Binding", 0); -} - - -/* - * Response handler for DAV resources - */ -static int dav_handler(request_rec *r) -{ - dav_dir_conf *conf; - - if (strcmp(r->handler, "dav-handler")) { - return DECLINED; - } - - /* quickly ignore any HTTP/0.9 requests */ - if (r->assbackwards) { - return DECLINED; - } - - /* ### do we need to do anything with r->proxyreq ?? */ - - conf = (dav_dir_conf *) ap_get_module_config(r->per_dir_config, - &dav_module); - - /* - * Set up the methods mask, since that's one of the reasons this handler - * gets called, and lower-level things may need the info. - * - * First, set the mask to the methods we handle directly. Since by - * definition we own our managed space, we unconditionally set - * the r->allowed field rather than ORing our values with anything - * any other module may have put in there. - * - * These are the HTTP-defined methods that we handle directly. - */ - r->allowed = 0 - | (1 << M_GET) - | (1 << M_PUT) - | (1 << M_DELETE) - | (1 << M_OPTIONS) - | (1 << M_INVALID); - /* - * These are the DAV methods we handle. - */ - r->allowed |= 0 - | (1 << M_COPY) - | (1 << M_LOCK) - | (1 << M_UNLOCK) - | (1 << M_MKCOL) - | (1 << M_MOVE) - | (1 << M_PROPFIND) - | (1 << M_PROPPATCH); - /* - * These are methods that we don't handle directly, but let the - * server's default handler do for us as our agent. - */ - r->allowed |= 0 - | (1 << M_POST); - - /* ### hrm. if we return HTTP_METHOD_NOT_ALLOWED, then an Allow header - * ### is sent; it will need the other allowed states; since the default - * ### handler is not called on error, then it doesn't add the other - * ### allowed states, so we must */ - /* ### we might need to refine this for just where we return the error. - * ### also, there is the issue with other methods (see ISSUES) */ - /* ### more work necessary, now that we have M_foo for DAV methods */ - - /* dispatch the appropriate method handler */ - if (r->method_number == M_GET) { - return dav_method_get(r); - } - - if (r->method_number == M_PUT) { - return dav_method_put(r); - } - - if (r->method_number == M_POST) { - return dav_method_post(r); - } - - if (r->method_number == M_DELETE) { - return dav_method_delete(r); - } - - if (r->method_number == M_OPTIONS) { - return dav_method_options(r); - } - - if (r->method_number == M_PROPFIND) { - return dav_method_propfind(r); - } - - if (r->method_number == M_PROPPATCH) { - return dav_method_proppatch(r); - } - - if (r->method_number == M_MKCOL) { - return dav_method_mkcol(r); - } - - if (r->method_number == M_COPY) { - return dav_method_copymove(r, DAV_DO_COPY); - } - - if (r->method_number == M_MOVE) { - return dav_method_copymove(r, DAV_DO_MOVE); - } - - if (r->method_number == M_LOCK) { - return dav_method_lock(r); - } - - if (r->method_number == M_UNLOCK) { - return dav_method_unlock(r); - } - - /* - * NOTE: When Apache moves creates defines for the add'l DAV methods, - * then it will no longer use M_INVALID. This code must be - * updated each time Apache adds method defines. - */ - if (r->method_number != M_INVALID) { - return DECLINED; - } - - if (!strcmp(r->method, "VERSION-CONTROL")) { - return dav_method_vsn_control(r); - } - - if (!strcmp(r->method, "CHECKOUT")) { - return dav_method_checkout(r); - } - - if (!strcmp(r->method, "UNCHECKOUT")) { - return dav_method_uncheckout(r); - } - - if (!strcmp(r->method, "CHECKIN")) { - return dav_method_checkin(r); - } - - if (!strcmp(r->method, "UPDATE")) { - return dav_method_update(r); - } - - if (!strcmp(r->method, "LABEL")) { - return dav_method_label(r); - } - - if (!strcmp(r->method, "REPORT")) { - return dav_method_report(r); - } - - if (!strcmp(r->method, "MKWORKSPACE")) { - return dav_method_make_workspace(r); - } - - if (!strcmp(r->method, "MKACTIVITY")) { - return dav_method_make_activity(r); - } - - if (!strcmp(r->method, "BASELINE-CONTROL")) { - return dav_method_baseline_control(r); - } - - if (!strcmp(r->method, "MERGE")) { - return dav_method_merge(r); - } - - if (!strcmp(r->method, "BIND")) { - return dav_method_bind(r); - } - - /* ### add'l methods for Advanced Collections, ACLs, DASL */ - - return DECLINED; -} - -static int dav_type_checker(request_rec *r) -{ - dav_dir_conf *conf; - - conf = (dav_dir_conf *) ap_get_module_config(r->per_dir_config, - &dav_module); - - /* if DAV is not enabled, then we've got nothing to do */ - if (conf->provider == NULL) { - return DECLINED; - } - - if (r->method_number == M_GET) { - /* - ** ### need some work to pull Content-Type and Content-Language - ** ### from the property database. - */ - - /* - ** If the repository hasn't indicated that it will handle the - ** GET method, then just punt. - ** - ** ### this isn't quite right... taking over the response can break - ** ### things like mod_negotiation. need to look into this some more. - */ - if (!conf->provider->repos->handle_get) { - return DECLINED; - } - } - - /* ### we should (instead) trap the ones that we DO understand */ - /* ### the handler DOES handle POST, so we need to fix one of these */ - if (r->method_number != M_POST) { - - /* - ** ### anything else to do here? could another module and/or - ** ### config option "take over" the handler here? i.e. how do - ** ### we lock down this hierarchy so that we are the ultimate - ** ### arbiter? (or do we simply depend on the administrator - ** ### to avoid conflicting configurations?) - ** - ** ### I think the OK stops running type-checkers. need to look. - */ - r->handler = "dav-handler"; - return OK; - } - - return DECLINED; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_handler(dav_handler, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_config(dav_init_handler, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_type_checker(dav_type_checker, NULL, NULL, APR_HOOK_FIRST); - - dav_hook_find_liveprop(dav_core_find_liveprop, NULL, NULL, APR_HOOK_LAST); - dav_hook_insert_all_liveprops(dav_core_insert_all_liveprops, - NULL, NULL, APR_HOOK_MIDDLE); - - dav_core_register_uris(p); -} - -/*--------------------------------------------------------------------------- -** -** Configuration info for the module -*/ - -static const command_rec dav_cmds[] = -{ - /* per directory/location */ - AP_INIT_TAKE1("DAV", dav_cmd_dav, NULL, ACCESS_CONF, - "specify the DAV provider for a directory or location"), - - /* per directory/location, or per server */ - AP_INIT_TAKE1("DAVMinTimeout", dav_cmd_davmintimeout, NULL, - ACCESS_CONF|RSRC_CONF, - "specify minimum allowed timeout"), - - /* per directory/location, or per server */ - AP_INIT_FLAG("DAVDepthInfinity", dav_cmd_davdepthinfinity, NULL, - ACCESS_CONF|RSRC_CONF, - "allow Depth infinity PROPFIND requests"), - - /* per directory/location, or per server */ - AP_INIT_TAKE2("DAVParam", dav_cmd_davparam, NULL, - ACCESS_CONF|RSRC_CONF, - "DAVParam <parameter name> <parameter value>"), - - { NULL } -}; - -module DAV_DECLARE_DATA dav_module = -{ - STANDARD20_MODULE_STUFF, - dav_create_dir_config, /* dir config creater */ - dav_merge_dir_config, /* dir merger --- default is to override */ - dav_create_server_config, /* server config */ - dav_merge_server_config, /* merge server config */ - dav_cmds, /* command table */ - register_hooks, /* register hooks */ -}; - -APR_HOOK_STRUCT( - APR_HOOK_LINK(gather_propsets) - APR_HOOK_LINK(find_liveprop) - APR_HOOK_LINK(insert_all_liveprops) - ) -APR_IMPLEMENT_EXTERNAL_HOOK_VOID(dav, DAV, gather_propsets, - (apr_array_header_t *uris), - (uris)) -APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(dav, DAV, int, find_liveprop, - (const dav_resource *resource, - const char *ns_uri, const char *name, - const dav_hooks_liveprop **hooks), - (resource, ns_uri, name, hooks), 0); -APR_IMPLEMENT_EXTERNAL_HOOK_VOID(dav, DAV, insert_all_liveprops, - (request_rec *r, const dav_resource *resource, - dav_prop_insert what, ap_text_header *phdr), - (r, resource, what, phdr)); diff --git a/modules/dav/main/mod_dav.dsp b/modules/dav/main/mod_dav.dsp deleted file mode 100644 index ba781d9d56..0000000000 --- a/modules/dav/main/mod_dav.dsp +++ /dev/null @@ -1,131 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_dav" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_dav - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_dav.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_dav.mak" CFG="mod_dav - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_dav - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_dav - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_dav - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\..\srclib\aputil" /I "..\..\..\srclib\sdbm" /I "..\..\..\srclib\expat-lite" /I "..\..\..\srclib\apr\include" /I "../../../srclib/apr-util/include" /I "..\..\..\include" /I "..\..\..\os\win32" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "DAV_DECLARE_EXPORT" /Fd"Release\mod_dav" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_dav.so" /machine:I386 /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav -# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_dav.so" /machine:I386 /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav - -!ELSEIF "$(CFG)" == "mod_dav - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\..\srclib\aputil" /I "..\..\..\srclib\sdbm" /I "..\..\..\srclib\expat-lite" /I "..\..\..\srclib\apr\include" /I "../../../srclib/apr-util/include" /I "..\..\..\include" /I "..\..\..\os\win32" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "DAV_DECLARE_EXPORT" /Fd"Debug\mod_dav" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_dav.so" /machine:I386 /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav -# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /map /debug /out:"Debug/mod_dav.so" /machine:I386 /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav - -!ENDIF - -# Begin Target - -# Name "mod_dav - Win32 Release" -# Name "mod_dav - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" -# Begin Source File - -SOURCE=.\liveprop.c -# End Source File -# Begin Source File - -SOURCE=.\mod_dav.c -# End Source File -# Begin Source File - -SOURCE=.\props.c -# End Source File -# Begin Source File - -SOURCE=.\providers.c -# End Source File -# Begin Source File - -SOURCE=.\std_liveprop.c -# End Source File -# Begin Source File - -SOURCE=.\util.c -# End Source File -# Begin Source File - -SOURCE=.\util_lock.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" -# Begin Source File - -SOURCE=.\mod_dav.h -# End Source File -# End Group -# End Target -# End Project diff --git a/modules/dav/main/mod_dav.h b/modules/dav/main/mod_dav.h deleted file mode 100644 index 162f7bff66..0000000000 --- a/modules/dav/main/mod_dav.h +++ /dev/null @@ -1,2231 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* -** DAV extension module for Apache 2.0.* -*/ - -#ifndef _MOD_DAV_H_ -#define _MOD_DAV_H_ - -#include "apr_hooks.h" -#include "apr_hash.h" -#include "apr_dbm.h" -#include "apr_tables.h" - -#include "httpd.h" -#include "util_filter.h" -#include "util_xml.h" - -#include <limits.h> /* for INT_MAX */ -#include <time.h> /* for time_t */ - -#ifdef __cplusplus -extern "C" { -#endif - - -#define DAV_VERSION AP_SERVER_BASEREVISION - -#define DAV_XML_HEADER "<?xml version=\"1.0\" encoding=\"utf-8\"?>" -#define DAV_XML_CONTENT_TYPE "text/xml; charset=\"utf-8\"" - -#define DAV_READ_BLOCKSIZE 2048 /* used for reading input blocks */ - -#define DAV_RESPONSE_BODY_1 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<HTML><HEAD>\n<TITLE>" -#define DAV_RESPONSE_BODY_2 "</TITLE>\n</HEAD><BODY>\n<H1>" -#define DAV_RESPONSE_BODY_3 "</H1>\n" -#define DAV_RESPONSE_BODY_4 "</BODY></HTML>\n" - -#define DAV_DO_COPY 0 -#define DAV_DO_MOVE 1 - - -#if 1 -#define DAV_DEBUG 1 -#define DEBUG_CR "\n" -#define DBG0(f) ap_log_error(APLOG_MARK, \ - APLOG_ERR|APLOG_NOERRNO, 0, NULL, (f)) -#define DBG1(f,a1) ap_log_error(APLOG_MARK, \ - APLOG_ERR|APLOG_NOERRNO, 0, NULL, f, a1) -#define DBG2(f,a1,a2) ap_log_error(APLOG_MARK, \ - APLOG_ERR|APLOG_NOERRNO, 0, NULL, f, a1, a2) -#define DBG3(f,a1,a2,a3) ap_log_error(APLOG_MARK, \ - APLOG_ERR|APLOG_NOERRNO, 0, NULL, f, a1, a2, a3) -#else -#undef DAV_DEBUG -#define DEBUG_CR "" -#endif - -#define DAV_INFINITY INT_MAX /* for the Depth: header */ - -/* Create a set of DAV_DECLARE(type), DAV_DECLARE_NONSTD(type) and - * DAV_DECLARE_DATA with appropriate export and import tags for the platform - */ -#if !defined(WIN32) -#define DAV_DECLARE(type) type -#define DAV_DECLARE_NONSTD(type) type -#define DAV_DECLARE_DATA -#elif defined(DAV_DECLARE_STATIC) -#define DAV_DECLARE(type) type __stdcall -#define DAV_DECLARE_NONSTD(type) type -#define DAV_DECLARE_DATA -#elif defined(DAV_DECLARE_EXPORT) -#define DAV_DECLARE(type) __declspec(dllexport) type __stdcall -#define DAV_DECLARE_NONSTD(type) __declspec(dllexport) type -#define DAV_DECLARE_DATA __declspec(dllexport) -#else -#define DAV_DECLARE(type) __declspec(dllimport) type __stdcall -#define DAV_DECLARE_NONSTD(type) __declspec(dllimport) type -#define DAV_DECLARE_DATA __declspec(dllimport) -#endif - -/* -------------------------------------------------------------------- -** -** ERROR MANAGEMENT -*/ - -/* -** dav_error structure. -** -** In most cases, mod_dav uses a pointer to a dav_error structure. If the -** pointer is NULL, then no error has occurred. -** -** In certain cases, a dav_error structure is directly used. In these cases, -** a status value of 0 means that an error has not occurred. -** -** Note: this implies that status != 0 whenever an error occurs. -** -** The desc field is optional (it may be NULL). When NULL, it typically -** implies that Apache has a proper description for the specified status. -*/ -typedef struct dav_error { - int status; /* suggested HTTP status (0 for no error) */ - int error_id; /* DAV-specific error ID */ - const char *desc; /* DAV:responsedescription and error log */ - - int save_errno; /* copy of errno causing the error */ - - struct dav_error *prev; /* previous error (in stack) */ - - /* deferred computation of the description */ - void (*compute_desc)(struct dav_error *err, apr_pool_t *p); - int ctx_i; - const char *ctx_s; - void *ctx_p; - -} dav_error; - -/* -** Create a new error structure. save_errno will be filled with the current -** errno value. -*/ -DAV_DECLARE(dav_error*) dav_new_error(apr_pool_t *p, int status, - int error_id, const char *desc); - -/* -** Push a new error description onto the stack of errors. -** -** This function is used to provide an additional description to an existing -** error. -** -** <status> should contain the caller's view of what the current status is, -** given the underlying error. If it doesn't have a better idea, then the -** caller should pass prev->status. -** -** <error_id> can specify a new error_id since the topmost description has -** changed. -*/ -DAV_DECLARE(dav_error*) dav_push_error(apr_pool_t *p, int status, int error_id, - const char *desc, dav_error *prev); - - -/* error ID values... */ - -/* IF: header errors */ -#define DAV_ERR_IF_PARSE 100 /* general parsing error */ -#define DAV_ERR_IF_MULTIPLE_NOT 101 /* multiple "Not" found */ -#define DAV_ERR_IF_UNK_CHAR 102 /* unknown char in header */ -#define DAV_ERR_IF_ABSENT 103 /* no locktokens given */ -#define DAV_ERR_IF_TAGGED 104 /* in parsing tagged-list */ -#define DAV_ERR_IF_UNCLOSED_PAREN 105 /* in no-tagged-list */ - -/* Prop DB errors */ -#define DAV_ERR_PROP_BAD_MAJOR 200 /* major version was wrong */ -#define DAV_ERR_PROP_READONLY 201 /* prop is read-only */ -#define DAV_ERR_PROP_NO_DATABASE 202 /* writable db not avail */ -#define DAV_ERR_PROP_NOT_FOUND 203 /* prop not found */ -#define DAV_ERR_PROP_BAD_LOCKDB 204 /* could not open lockdb */ -#define DAV_ERR_PROP_OPENING 205 /* problem opening propdb */ -#define DAV_ERR_PROP_EXEC 206 /* problem exec'ing patch */ - -/* Predefined DB errors */ -/* ### any to define?? */ - -/* Predefined locking system errors */ -#define DAV_ERR_LOCK_OPENDB 400 /* could not open lockdb */ -#define DAV_ERR_LOCK_NO_DB 401 /* no database defined */ -#define DAV_ERR_LOCK_CORRUPT_DB 402 /* DB is corrupt */ -#define DAV_ERR_LOCK_UNK_STATE_TOKEN 403 /* unknown State-token */ -#define DAV_ERR_LOCK_PARSE_TOKEN 404 /* bad opaquelocktoken */ -#define DAV_ERR_LOCK_SAVE_LOCK 405 /* err saving locks */ - -/* -** Some comments on Error ID values: -** -** The numbers do not necessarily need to be unique. Uniqueness simply means -** that two errors that have not been predefined above can be distinguished -** from each other. At the moment, mod_dav does not use this distinguishing -** feature, but it could be used in the future to collapse <response> elements -** into groups based on the error ID (and associated responsedescription). -** -** If a compute_desc is provided, then the error ID should be unique within -** the context of the compute_desc function (so the function can figure out -** what to filled into the desc). -** -** Basically, subsystems can ignore defining new error ID values if they want -** to. The subsystems *do* need to return the predefined errors when -** appropriate, so that mod_dav can figure out what to do. Subsystems can -** simply leave the error ID field unfilled (zero) if there isn't an error -** that must be placed there. -*/ - - -/* -------------------------------------------------------------------- -** -** HOOK STRUCTURES -** -** These are here for forward-declaration purposes. For more info, see -** the section title "HOOK HANDLING" for more information, plus each -** structure definition. -*/ - -/* forward-declare this structure */ -typedef struct dav_hooks_propdb dav_hooks_propdb; -typedef struct dav_hooks_locks dav_hooks_locks; -typedef struct dav_hooks_vsn dav_hooks_vsn; -typedef struct dav_hooks_repository dav_hooks_repository; -typedef struct dav_hooks_liveprop dav_hooks_liveprop; -typedef struct dav_hooks_binding dav_hooks_binding; - -/* ### deprecated name */ -typedef dav_hooks_propdb dav_hooks_db; - - -/* -------------------------------------------------------------------- -** -** RESOURCE HANDLING -*/ - -/* -** Resource Types: -** The base protocol defines only file and collection resources. -** The versioning protocol defines several additional resource types -** to represent artifacts of a version control system. -** -** This enumeration identifies the type of URL used to identify the -** resource. Since the same resource may have more than one type of -** URL which can identify it, dav_resource_type cannot be used -** alone to determine the type of the resource; attributes of the -** dav_resource object must also be consulted. -*/ -typedef enum { - DAV_RESOURCE_TYPE_UNKNOWN, - - DAV_RESOURCE_TYPE_REGULAR, /* file or collection; could be - * unversioned, or version selector, - * or baseline selector */ - - DAV_RESOURCE_TYPE_VERSION, /* version or baseline URL */ - - DAV_RESOURCE_TYPE_HISTORY, /* version or baseline history URL */ - - DAV_RESOURCE_TYPE_WORKING, /* working resource URL */ - - DAV_RESOURCE_TYPE_WORKSPACE, /* workspace URL */ - - DAV_RESOURCE_TYPE_ACTIVITY, /* activity URL */ - - DAV_RESOURCE_TYPE_PRIVATE /* repository-private type */ - -} dav_resource_type; - -/* -** Opaque, repository-specific information for a resource. -*/ -typedef struct dav_resource_private dav_resource_private; - -/* -** Resource descriptor, generated by a repository provider. -** -** Note: the lock-null state is not explicitly represented here, -** since it may be expensive to compute. Use dav_get_resource_state() -** to determine whether a non-existent resource is a lock-null resource. -** -** A quick explanation of how the flags can apply to different resources: -** -** unversioned file or collection: -** type = DAV_RESOURCE_TYPE_REGULAR -** exists = ? (1 if exists) -** collection = ? (1 if collection) -** versioned = 0 -** baselined = 0 -** working = 0 -** -** version-controlled resource or configuration: -** type = DAV_RESOURCE_TYPE_REGULAR -** exists = 1 -** collection = ? (1 if collection) -** versioned = 1 -** baselined = ? (1 if configuration) -** working = ? (1 if checked out) -** -** version/baseline history: -** type = DAV_RESOURCE_TYPE_HISTORY -** exists = 1 -** collection = 0 -** versioned = 0 -** baselined = 0 -** working = 0 -** -** version/baseline: -** type = DAV_RESOURCE_TYPE_VERSION -** exists = 1 -** collection = ? (1 if collection) -** versioned = 1 -** baselined = ? (1 if baseline) -** working = 0 -** -** working resource: -** type = DAV_RESOURCE_TYPE_WORKING -** exists = 1 -** collection = ? (1 if collection) -** versioned = 1 -** baselined = 0 -** working = 1 -** -** workspace: -** type = DAV_RESOURCE_TYPE_WORKSPACE -** exists = ? (1 if exists) -** collection = 1 -** versioned = ? (1 if version-controlled) -** baselined = ? (1 if baseline-controlled) -** working = ? (1 if checked out) -** -** activity: -** type = DAV_RESOURCE_TYPE_ACTIVITY -** exists = ? (1 if exists) -** collection = 0 -** versioned = 0 -** baselined = 0 -** working = 0 -*/ -typedef struct dav_resource { - dav_resource_type type; - - int exists; /* 0 => null resource */ - - int collection; /* 0 => file; can be 1 for - * REGULAR, VERSION, and WORKING resources, - * and is always 1 for WORKSPACE */ - - int versioned; /* 0 => unversioned; can be 1 for - * REGULAR and WORKSPACE resources, - * and is always 1 for VERSION and WORKING */ - - int baselined; /* 0 => not baselined; can be 1 for - * REGULAR, VERSION, and WORKSPACE resources; - * versioned == 1 when baselined == 1 */ - - int working; /* 0 => not checked out; can be 1 for - * REGULAR and WORKSPACE resources, - * and is always 1 for WORKING */ - - const char *uri; /* the URI for this resource */ - - dav_resource_private *info; /* the provider's private info */ - - const dav_hooks_repository *hooks; /* hooks used for this resource */ - - /* When allocating items related specifically to this resource, the - following pool should be used. Its lifetime will be at least as - long as the dav_resource structure. */ - apr_pool_t *pool; - -} dav_resource; - -/* -** Lock token type. Lock providers define the details of a lock token. -** However, all providers are expected to at least be able to parse -** the "opaquelocktoken" scheme, which is represented by a uuid_t. -*/ -typedef struct dav_locktoken dav_locktoken; - - -/* -------------------------------------------------------------------- -** -** BUFFER HANDLING -** -** These buffers are used as a lightweight buffer reuse mechanism. Apache -** provides sub-pool creation and destruction to much the same effect, but -** the sub-pools are a bit more general and heavyweight than these buffers. -*/ - -/* buffer for reuse; can grow to accomodate needed size */ -typedef struct -{ - apr_size_t alloc_len; /* how much has been allocated */ - apr_size_t cur_len; /* how much is currently being used */ - char *buf; /* buffer contents */ -} dav_buffer; -#define DAV_BUFFER_MINSIZE 256 /* minimum size for buffer */ -#define DAV_BUFFER_PAD 64 /* amount of pad when growing */ - -/* set the cur_len to the given size and ensure space is available */ -DAV_DECLARE(void) dav_set_bufsize(apr_pool_t *p, dav_buffer *pbuf, - apr_size_t size); - -/* initialize a buffer and copy the specified (null-term'd) string into it */ -DAV_DECLARE(void) dav_buffer_init(apr_pool_t *p, dav_buffer *pbuf, - const char *str); - -/* check that the buffer can accomodate <extra_needed> more bytes */ -DAV_DECLARE(void) dav_check_bufsize(apr_pool_t *p, dav_buffer *pbuf, - apr_size_t extra_needed); - -/* append a string to the end of the buffer, adjust length */ -DAV_DECLARE(void) dav_buffer_append(apr_pool_t *p, dav_buffer *pbuf, - const char *str); - -/* place a string on the end of the buffer, do NOT adjust length */ -DAV_DECLARE(void) dav_buffer_place(apr_pool_t *p, dav_buffer *pbuf, - const char *str); - -/* place some memory on the end of a buffer; do NOT adjust length */ -DAV_DECLARE(void) dav_buffer_place_mem(apr_pool_t *p, dav_buffer *pbuf, - const void *mem, apr_size_t amt, - apr_size_t pad); - - -/* -------------------------------------------------------------------- -** -** HANDY UTILITIES -*/ - -/* contains results from one of the getprop functions */ -typedef struct -{ - ap_text * propstats; /* <propstat> element text */ - ap_text * xmlns; /* namespace decls for <response> elem */ -} dav_get_props_result; - -/* holds the contents of a <response> element */ -typedef struct dav_response -{ - const char *href; /* always */ - const char *desc; /* optional description at <response> level */ - - /* use status if propresult.propstats is NULL. */ - dav_get_props_result propresult; - - int status; - - struct dav_response *next; -} dav_response; - -typedef struct -{ - request_rec *rnew; /* new subrequest */ - dav_error err; /* potential error response */ -} dav_lookup_result; - - -dav_lookup_result dav_lookup_uri(const char *uri, request_rec *r, - int must_be_absolute); - -/* defines type of property info a provider is to return */ -typedef enum { - DAV_PROP_INSERT_NOTDEF, /* property is defined by this provider, - but nothing was inserted because the - (live) property is not defined for this - resource (it may be present as a dead - property). */ - DAV_PROP_INSERT_NOTSUPP, /* property is recognized by this provider, - but it is not supported, and cannot be - treated as a dead property */ - DAV_PROP_INSERT_NAME, /* a property name (empty elem) was - inserted into the text block */ - DAV_PROP_INSERT_VALUE, /* a property name/value pair was inserted - into the text block */ - DAV_PROP_INSERT_SUPPORTED /* a supported live property was added to - the text block as a - <DAV:supported-live-property> element */ -} dav_prop_insert; - -/* ### this stuff is private to dav/fs/repos.c; move it... */ -/* format a time string (buf must be at least DAV_TIMEBUF_SIZE chars) */ -#define DAV_STYLE_ISO8601 1 -#define DAV_STYLE_RFC822 2 -#define DAV_TIMEBUF_SIZE 30 - -int dav_get_depth(request_rec *r, int def_depth); - -int dav_validate_root(const ap_xml_doc *doc, const char *tagname); -ap_xml_elem *dav_find_child(const ap_xml_elem *elem, const char *tagname); - -/* gather up all the CDATA into a single string */ -const char *dav_xml_get_cdata(const ap_xml_elem *elem, apr_pool_t *pool, - int strip_white); - - -/* -------------------------------------------------------------------- -** -** DAV PLUGINS -*/ - -/* ### docco ... */ - -/* -** dav_provider -** -** This structure wraps up all of the hooks that a mod_dav provider can -** supply. The provider MUST supply <repos> and <propdb>. The rest are -** optional and should contain NULL if that feature is not supplied. -** -** Note that a provider cannot pick and choose portions. There are too many -** dependencies between a dav_resource (defined by <repos>) and the other -** functionality. -** -** Live properties are not part of the dav_provider structure because they -** are handled through the APR_HOOK interface (to allow for multiple liveprop -** providers). The core always provides some properties, and then a given -** provider will add more properties. -*/ -typedef struct { - const dav_hooks_repository *repos; - const dav_hooks_propdb *propdb; - const dav_hooks_locks *locks; - const dav_hooks_vsn *vsn; - const dav_hooks_binding *binding; - -} dav_provider; - -/* -** gather_propsets: gather all live property propset-URIs -** -** The hook implementor should push one or more URIs into the specified -** array. These URIs are returned in the DAV: header to let clients know -** what sets of live properties are supported by the installation. mod_dav -** will place open/close angle brackets around each value (much like -** a Coded-URL); quotes and brackets should not be in the value. -** -** Example: http://apache.org/dav/props/ -** -** (of course, use your own domain to ensure a unique value) -*/ -APR_DECLARE_EXTERNAL_HOOK(dav, DAV, void, gather_propsets, - (apr_array_header_t *uris)) - -/* -** find_liveprop: find a live property, returning a non-zero, unique, -** opaque identifier. -** -** If the hook implementor determines the specified URI/name refers to -** one of its properties, then it should fill in HOOKS and return a -** non-zero value. The returned value is the "property ID" and will -** be passed to the various liveprop hook functions. -** -** Return 0 if the property is not defined by the hook implementor. -*/ -APR_DECLARE_EXTERNAL_HOOK(dav, DAV, int, find_liveprop, - (const dav_resource *resource, - const char *ns_uri, const char *name, - const dav_hooks_liveprop **hooks)) - -/* -** insert_all_liveprops: insert all (known) live property names/values. -** -** The hook implementor should append XML text to PHDR, containing liveprop -** names. If INSVALUE is true, then the property values should also be -** inserted into the output XML stream. -** -** The liveprop provider should insert *all* known and *defined* live -** properties on the specified resource. If a particular liveprop is -** not defined for this resource, then it should not be inserted. -*/ -APR_DECLARE_EXTERNAL_HOOK(dav, DAV, void, insert_all_liveprops, - (request_rec *r, const dav_resource *resource, - dav_prop_insert what, ap_text_header *phdr)) - -const dav_hooks_locks *dav_get_lock_hooks(request_rec *r); -const dav_hooks_propdb *dav_get_propdb_hooks(request_rec *r); -const dav_hooks_vsn *dav_get_vsn_hooks(request_rec *r); -const dav_hooks_binding *dav_get_binding_hooks(request_rec *r); - -DAV_DECLARE(void) dav_register_provider(apr_pool_t *p, const char *name, - const dav_provider *hooks); -const dav_provider * dav_lookup_provider(const char *name); - - -/* ### deprecated */ -#define DAV_GET_HOOKS_PROPDB(r) dav_get_propdb_hooks(r) -#define DAV_GET_HOOKS_LOCKS(r) dav_get_lock_hooks(r) -#define DAV_GET_HOOKS_VSN(r) dav_get_vsn_hooks(r) -#define DAV_GET_HOOKS_BINDING(r) dav_get_binding_hooks(r) - - -/* -------------------------------------------------------------------- -** -** IF HEADER PROCESSING -** -** Here is the definition of the If: header from RFC 2518, S9.4: -** -** If = "If" ":" (1*No-tag-list | 1*Tagged-list) -** No-tag-list = List -** Tagged-list = Resource 1*List -** Resource = Coded-URL -** List = "(" 1*(["Not"](State-token | "[" entity-tag "]")) ")" -** State-token = Coded-URL -** Coded-URL = "<" absoluteURI ">" ; absoluteURI from RFC 2616 -** -** List corresponds to dav_if_state_list. No-tag-list corresponds to -** dav_if_header with uri==NULL. Tagged-list corresponds to a sequence of -** dav_if_header structures with (duplicate) uri==Resource -- one -** dav_if_header per state_list. A second Tagged-list will start a new -** sequence of dav_if_header structures with the new URI. -** -** A summary of the semantics, mapped into our structures: -** - Chained dav_if_headers: OR -** - Chained dav_if_state_lists: AND -** - NULL uri matches all resources -*/ - -typedef enum -{ - dav_if_etag, - dav_if_opaquelock -} dav_if_state_type; - -typedef struct dav_if_state_list -{ - dav_if_state_type type; - - int condition; -#define DAV_IF_COND_NORMAL 0 -#define DAV_IF_COND_NOT 1 /* "Not" was applied */ - - const char *etag; /* etag */ - dav_locktoken *locktoken; /* locktoken */ - - struct dav_if_state_list *next; -} dav_if_state_list; - -typedef struct dav_if_header -{ - const char *uri; - apr_size_t uri_len; - struct dav_if_state_list *state; - struct dav_if_header *next; - - int dummy_header; /* used internally by the lock/etag validation */ -} dav_if_header; - -typedef struct dav_locktoken_list -{ - dav_locktoken *locktoken; - struct dav_locktoken_list *next; -} dav_locktoken_list; - -dav_error * dav_get_locktoken_list(request_rec *r, dav_locktoken_list **ltl); - - -/* -------------------------------------------------------------------- -** -** LIVE PROPERTY HANDLING -*/ - -/* opaque type for PROPPATCH rollback information */ -typedef struct dav_liveprop_rollback dav_liveprop_rollback; - -struct dav_hooks_liveprop -{ - /* - ** Insert property information into a text block. The property to - ** insert is identified by the propid value. The information to insert - ** is identified by the "what" argument, as follows: - ** DAV_PROP_INSERT_NAME - ** property name, as an empty XML element - ** DAV_PROP_INSERT_VALUE - ** property name/value, as an XML element - ** DAV_PROP_INSERT_SUPPORTED - ** if the property is defined on the resource, then - ** a DAV:supported-live-property element, as defined - ** by the DeltaV extensions to RFC2518. - ** - ** Providers should return DAV_PROP_INSERT_NOTDEF if the property is - ** known and not defined for this resource, so should be handled as a - ** dead property. If a provider recognizes, but does not support, a - ** property, and does not want it handled as a dead property, it should - ** return DAV_PROP_INSERT_NOTSUPP. - ** - ** Returns one of DAV_PROP_INSERT_* based on what happened. - ** - ** ### we may need more context... ie. the lock database - */ - dav_prop_insert (*insert_prop)(const dav_resource *resource, - int propid, dav_prop_insert what, - ap_text_header *phdr); - - /* - ** Determine whether a given property is writable. - ** - ** ### we may want a different semantic. i.e. maybe it should be - ** ### "can we write <value> into this property?" - ** - ** Returns 1 if the live property can be written, 0 if read-only. - */ - int (*is_writable)(const dav_resource *resource, int propid); - - /* - ** This member defines the set of namespace URIs that the provider - ** uses for its properties. When insert_all is called, it will be - ** passed a list of integers that map from indices into this list - ** to namespace IDs for output generation. - ** - ** The last entry in this list should be a NULL value (sentinel). - */ - const char * const * namespace_uris; - - /* - ** ### this is not the final design. we want an open-ended way for - ** ### liveprop providers to attach *new* properties. To this end, - ** ### we'll have a "give me a list of the props you define", a way - ** ### to check for a prop's existence, a way to validate a set/remove - ** ### of a prop, and a way to execute/commit/rollback that change. - */ - - /* - ** Validate that the live property can be assigned a value, and that - ** the provided value is valid. - ** - ** elem will point to the XML element that names the property. For - ** example: - ** <lp1:executable>T</lp1:executable> - ** - ** The provider can access the cdata fields and the child elements - ** to extract the relevant pieces. - ** - ** operation is one of DAV_PROP_OP_SET or _DELETE. - ** - ** The provider may return a value in *context which will be passed - ** to each of the exec/commit/rollback functions. For example, this - ** may contain an internal value which has been processed from the - ** input element. - ** - ** The provider must set defer_to_dead to true (non-zero) or false. - ** If true, then the set/remove is deferred to the dead property - ** database. Note: it will be set to zero on entry. - */ - dav_error * (*patch_validate)(const dav_resource *resource, - const ap_xml_elem *elem, - int operation, - void **context, - int *defer_to_dead); - - /* ### doc... */ - dav_error * (*patch_exec)(const dav_resource *resource, - const ap_xml_elem *elem, - int operation, - void *context, - dav_liveprop_rollback **rollback_ctx); - - /* ### doc... */ - void (*patch_commit)(const dav_resource *resource, - int operation, - void *context, - dav_liveprop_rollback *rollback_ctx); - - /* ### doc... */ - dav_error * (*patch_rollback)(const dav_resource *resource, - int operation, - void *context, - dav_liveprop_rollback *rollback_ctx); -}; - -/* -** dav_liveprop_spec: specify a live property -** -** This structure is used as a standard way to determine if a particular -** property is a live property. Its use is not part of the mandated liveprop -** interface, but can be used by liveprop providers in conjuction with the -** utility routines below. -** -** spec->name == NULL is the defined end-sentinel for a list of specs. -*/ -typedef struct { - int ns; /* provider-local namespace index */ - const char *name; /* name of the property */ - - int propid; /* provider-local property ID */ - - int is_writable; /* is the property writable? */ - -} dav_liveprop_spec; - -/* -** dav_liveprop_group: specify a group of liveprops -** -** This structure specifies a group of live properties, their namespaces, -** and how to handle them. -*/ -typedef struct { - const dav_liveprop_spec *specs; - const char * const *namespace_uris; - const dav_hooks_liveprop *hooks; - -} dav_liveprop_group; - -/* ### docco */ -DAV_DECLARE(int) dav_do_find_liveprop(const char *ns_uri, const char *name, - const dav_liveprop_group *group, - const dav_hooks_liveprop **hooks); - -/* ### docco */ -DAV_DECLARE(int) dav_get_liveprop_info(int propid, - const dav_liveprop_group *group, - const dav_liveprop_spec **info); - -/* ### docco */ -DAV_DECLARE(void) dav_register_liveprop_group(apr_pool_t *pool, - const dav_liveprop_group *group); - -/* ### docco */ -DAV_DECLARE(int) dav_get_liveprop_ns_index(const char *uri); - -/* ### docco */ -int dav_get_liveprop_ns_count(void); - -/* ### docco */ -void dav_add_all_liveprop_xmlns(apr_pool_t *p, ap_text_header *phdr); - -/* -** The following three functions are part of mod_dav's internal handling -** for the core WebDAV properties. They are not part of mod_dav's API. -*/ -int dav_core_find_liveprop(const dav_resource *resource, - const char *ns_uri, const char *name, - const dav_hooks_liveprop **hooks); -void dav_core_insert_all_liveprops(request_rec *r, - const dav_resource *resource, - dav_prop_insert what, ap_text_header *phdr); -void dav_core_register_uris(apr_pool_t *p); - - -/* -** Standard WebDAV Property Identifiers -** -** A live property provider does not need to use these; they are simply -** provided for convenience. -** -** Property identifiers need to be unique within a given provider, but not -** *across* providers (note: this uniqueness constraint was different in -** older versions of mod_dav). -** -** The identifiers start at 20000 to make it easier for providers to avoid -** conflicts with the standard properties. The properties are arranged -** alphabetically, and may be reordered from time to time (as properties -** are introduced). -** -** NOTE: there is no problem with reordering (e.g. binary compat) since the -** identifiers are only used within a given provider, which would pick up -** the entire set of changes upon a recompile. -*/ -enum { - DAV_PROPID_BEGIN = 20000, - - /* Standard WebDAV properties (RFC 2518) */ - DAV_PROPID_creationdate, - DAV_PROPID_displayname, - DAV_PROPID_getcontentlanguage, - DAV_PROPID_getcontentlength, - DAV_PROPID_getcontenttype, - DAV_PROPID_getetag, - DAV_PROPID_getlastmodified, - DAV_PROPID_lockdiscovery, - DAV_PROPID_resourcetype, - DAV_PROPID_source, - DAV_PROPID_supportedlock, - - /* DeltaV properties (from the I-D (#14)) */ - DAV_PROPID_activity_checkout_set, - DAV_PROPID_activity_set, - DAV_PROPID_activity_version_set, - DAV_PROPID_auto_merge_set, - DAV_PROPID_auto_version, - DAV_PROPID_baseline_collection, - DAV_PROPID_baseline_controlled_collection, - DAV_PROPID_baseline_controlled_collection_set, - DAV_PROPID_checked_in, - DAV_PROPID_checked_out, - DAV_PROPID_checkin_fork, - DAV_PROPID_checkout_fork, - DAV_PROPID_checkout_set, - DAV_PROPID_comment, - DAV_PROPID_creator_displayname, - DAV_PROPID_current_activity_set, - DAV_PROPID_current_workspace_set, - DAV_PROPID_default_variant, - DAV_PROPID_eclipsed_set, - DAV_PROPID_label_name_set, - DAV_PROPID_merge_set, - DAV_PROPID_precursor_set, - DAV_PROPID_predecessor_set, - DAV_PROPID_root_version, - DAV_PROPID_subactivity_set, - DAV_PROPID_subbaseline_set, - DAV_PROPID_successor_set, - DAV_PROPID_supported_method_set, - DAV_PROPID_supported_live_property_set, - DAV_PROPID_supported_report_set, - DAV_PROPID_unreserved, - DAV_PROPID_variant_set, - DAV_PROPID_version_controlled_binding_set, - DAV_PROPID_version_controlled_configuration, - DAV_PROPID_version_history, - DAV_PROPID_version_name, - DAV_PROPID_workspace, - DAV_PROPID_workspace_checkout_set, - - DAV_PROPID_END -}; - -/* -** Property Identifier Registration -** -** At the moment, mod_dav requires live property providers to ensure that -** each property returned has a unique value. For now, this is done through -** central registration (there are no known providers other than the default, -** so this remains manageable). -** -** WARNING: the TEST ranges should never be "shipped". -*/ -#define DAV_PROPID_CORE 10000 /* ..10099. defined by mod_dav */ -#define DAV_PROPID_FS 10100 /* ..10299. - mod_dav filesystem provider. */ -#define DAV_PROPID_TEST1 10300 /* ..10399 */ -#define DAV_PROPID_TEST2 10400 /* ..10499 */ -#define DAV_PROPID_TEST3 10500 /* ..10599 */ -/* Next: 10600 */ - - -/* -------------------------------------------------------------------- -** -** DATABASE FUNCTIONS -*/ - -typedef struct dav_db dav_db; -typedef apr_datum_t dav_datum; - -/* hook functions to enable pluggable databases */ -struct dav_hooks_propdb -{ - dav_error * (*open)(apr_pool_t *p, const dav_resource *resource, int ro, - dav_db **pdb); - void (*close)(dav_db *db); - - /* - ** Fetch the value from the database. If the value does not exist, - ** then *pvalue should be zeroed. - ** - ** Note: it is NOT an error for the key/value pair to not exist. - */ - dav_error * (*fetch)(dav_db *db, dav_datum key, dav_datum *pvalue); - - dav_error * (*store)(dav_db *db, dav_datum key, dav_datum value); - dav_error * (*remove)(dav_db *db, dav_datum key); - - /* returns 1 if the record specified by "key" exists; 0 otherwise */ - int (*exists)(dav_db *db, dav_datum key); - - dav_error * (*firstkey)(dav_db *db, dav_datum *pkey); - dav_error * (*nextkey)(dav_db *db, dav_datum *pkey); - - void (*freedatum)(dav_db *db, dav_datum data); -}; - - -/* -------------------------------------------------------------------- -** -** LOCK FUNCTIONS -*/ - -/* Used to represent a Timeout header of "Infinity" */ -#define DAV_TIMEOUT_INFINITE 0 - -time_t dav_get_timeout(request_rec *r); - -/* -** Opaque, provider-specific information for a lock database. -*/ -typedef struct dav_lockdb_private dav_lockdb_private; - -/* -** Opaque, provider-specific information for a lock record. -*/ -typedef struct dav_lock_private dav_lock_private; - -/* -** Lock database type. Lock providers are urged to implement a "lazy" open, so -** doing an "open" is cheap until something is actually needed from the DB. -*/ -typedef struct -{ - const dav_hooks_locks *hooks; /* the hooks used for this lockdb */ - int ro; /* was it opened readonly? */ - - dav_lockdb_private *info; - -} dav_lockdb; - -typedef enum { - DAV_LOCKSCOPE_UNKNOWN, - DAV_LOCKSCOPE_EXCLUSIVE, - DAV_LOCKSCOPE_SHARED -} dav_lock_scope; - -typedef enum { - DAV_LOCKTYPE_UNKNOWN, - DAV_LOCKTYPE_WRITE -} dav_lock_type; - -typedef enum { - DAV_LOCKREC_DIRECT, /* lock asserted on this resource */ - DAV_LOCKREC_INDIRECT, /* lock inherited from a parent */ - DAV_LOCKREC_INDIRECT_PARTIAL /* most info is not filled in */ -} dav_lock_rectype; - -/* -** dav_lock: hold information about a lock on a resource. -** -** This structure is used for both direct and indirect locks. A direct lock -** is a lock applied to a specific resource by the client. An indirect lock -** is one that is inherited from a parent resource by virtue of a non-zero -** Depth: header when the lock was applied. -** -** mod_dav records both types of locks in the lock database, managing their -** addition/removal as resources are moved about the namespace. -** -** Note that the lockdb is free to marshal this structure in any form that -** it likes. -** -** For a "partial" lock, the <rectype> and <locktoken> fields must be filled -** in. All other (user) fields should be zeroed. The lock provider will -** usually fill in the <info> field, and the <next> field may be used to -** construct a list of partial locks. -** -** The lock provider MUST use the info field to store a value such that a -** dav_lock structure can locate itself in the underlying lock database. -** This requirement is needed for refreshing: when an indirect dav_lock is -** refreshed, its reference to the direct lock does not specify the direct's -** resource, so the only way to locate the (refreshed, direct) lock in the -** database is to use the info field. -** -** Note that <is_locknull> only refers to the resource where this lock was -** found. -** ### hrm. that says the abstraction is wrong. is_locknull may disappear. -*/ -typedef struct dav_lock -{ - dav_lock_rectype rectype; /* type of lock record */ - int is_locknull; /* lock establishes a locknull resource */ - - /* ### put the resource in here? */ - - dav_lock_scope scope; /* scope of the lock */ - dav_lock_type type; /* type of lock */ - int depth; /* depth of the lock */ - time_t timeout; /* when the lock will timeout */ - - const dav_locktoken *locktoken; /* the token that was issued */ - - const char *owner; /* (XML) owner of the lock */ - const char *auth_user; /* auth'd username owning lock */ - - dav_lock_private *info; /* private to the lockdb */ - - struct dav_lock *next; /* for managing a list of locks */ -} dav_lock; - -/* Property-related public lock functions */ -const char *dav_lock_get_activelock(request_rec *r, dav_lock *locks, - dav_buffer *pbuf); - -/* LockDB-related public lock functions */ -dav_error * dav_lock_parse_lockinfo(request_rec *r, - const dav_resource *resrouce, - dav_lockdb *lockdb, - const ap_xml_doc *doc, - dav_lock **lock_request); -int dav_unlock(request_rec *r, const dav_resource *resource, - const dav_locktoken *locktoken); -dav_error * dav_add_lock(request_rec *r, const dav_resource *resource, - dav_lockdb *lockdb, dav_lock *request, - dav_response **response); -dav_error * dav_notify_created(request_rec *r, - dav_lockdb *lockdb, - const dav_resource *resource, - int resource_state, - int depth); - -DAV_DECLARE(dav_error*) dav_lock_query(dav_lockdb *lockdb, - const dav_resource *resource, - dav_lock **locks); - -dav_error * dav_validate_request(request_rec *r, dav_resource *resource, - int depth, dav_locktoken *locktoken, - dav_response **response, int flags, - dav_lockdb *lockdb); -/* -** flags: -** 0x0F -- reserved for <dav_lock_scope> values -** -** other flags, detailed below -*/ -#define DAV_VALIDATE_RESOURCE 0x0010 /* validate just the resource */ -#define DAV_VALIDATE_PARENT 0x0020 /* validate resource AND its parent */ -#define DAV_VALIDATE_ADD_LD 0x0040 /* add DAV:lockdiscovery into - the 424 DAV:response */ -#define DAV_VALIDATE_USE_424 0x0080 /* return 424 status, not 207 */ -#define DAV_VALIDATE_IS_PARENT 0x0100 /* for internal use */ - -/* Lock-null related public lock functions */ -int dav_get_resource_state(request_rec *r, const dav_resource *resource); - -/* Lock provider hooks. Locking is optional, so there may be no - * lock provider for a given repository. - */ -struct dav_hooks_locks -{ - /* Return the supportedlock property for a resource */ - const char * (*get_supportedlock)( - const dav_resource *resource - ); - - /* Parse a lock token URI, returning a lock token object allocated - * in the given pool. - */ - dav_error * (*parse_locktoken)( - apr_pool_t *p, - const char *char_token, - dav_locktoken **locktoken_p - ); - - /* Format a lock token object into a URI string, allocated in - * the given pool. - * - * Always returns non-NULL. - */ - const char * (*format_locktoken)( - apr_pool_t *p, - const dav_locktoken *locktoken - ); - - /* Compare two lock tokens. - * - * Result < 0 => lt1 < lt2 - * Result == 0 => lt1 == lt2 - * Result > 0 => lt1 > lt2 - */ - int (*compare_locktoken)( - const dav_locktoken *lt1, - const dav_locktoken *lt2 - ); - - /* Open the provider's lock database. - * - * The provider may or may not use a "real" database for locks - * (a lock could be an attribute on a resource, for example). - * - * The provider may choose to use the value of the DAVLockDB directive - * (as returned by dav_get_lockdb_path()) to decide where to place - * any storage it may need. - * - * The request storage pool should be associated with the lockdb, - * so it can be used in subsequent operations. - * - * If ro != 0, only readonly operations will be performed. - * If force == 0, the open can be "lazy"; no subsequent locking operations - * may occur. - * If force != 0, locking operations will definitely occur. - */ - dav_error * (*open_lockdb)( - request_rec *r, - int ro, - int force, - dav_lockdb **lockdb - ); - - /* Indicates completion of locking operations */ - void (*close_lockdb)( - dav_lockdb *lockdb - ); - - /* Take a resource out of the lock-null state. */ - dav_error * (*remove_locknull_state)( - dav_lockdb *lockdb, - const dav_resource *resource - ); - - /* - ** Create a (direct) lock structure for the given resource. A locktoken - ** will be created. - ** - ** The lock provider may store private information into lock->info. - */ - dav_error * (*create_lock)(dav_lockdb *lockdb, - const dav_resource *resource, - dav_lock **lock); - - /* - ** Get the locks associated with the specified resource. - ** - ** If resolve_locks is true (non-zero), then any indirect locks are - ** resolved to their actual, direct lock (i.e. the reference to followed - ** to the original lock). - ** - ** The locks, if any, are returned as a linked list in no particular - ** order. If no locks are present, then *locks will be NULL. - */ - dav_error * (*get_locks)(dav_lockdb *lockdb, - const dav_resource *resource, - int calltype, - dav_lock **locks); - -#define DAV_GETLOCKS_RESOLVED 0 /* resolve indirects to directs */ -#define DAV_GETLOCKS_PARTIAL 1 /* leave indirects partially filled */ -#define DAV_GETLOCKS_COMPLETE 2 /* fill out indirect locks */ - - /* - ** Find a particular lock on a resource (specified by its locktoken). - ** - ** *lock will be set to NULL if the lock is not found. - ** - ** Note that the provider can optimize the unmarshalling -- only one - ** lock (or none) must be constructed and returned. - ** - ** If partial_ok is true (non-zero), then an indirect lock can be - ** partially filled in. Otherwise, another lookup is done and the - ** lock structure will be filled out as a DAV_LOCKREC_INDIRECT. - */ - dav_error * (*find_lock)(dav_lockdb *lockdb, - const dav_resource *resource, - const dav_locktoken *locktoken, - int partial_ok, - dav_lock **lock); - - /* - ** Quick test to see if the resource has *any* locks on it. - ** - ** This is typically used to determine if a non-existent resource - ** has a lock and is (therefore) a locknull resource. - ** - ** WARNING: this function may return TRUE even when timed-out locks - ** exist (i.e. it may not perform timeout checks). - */ - dav_error * (*has_locks)(dav_lockdb *lockdb, - const dav_resource *resource, - int *locks_present); - - /* - ** Append the specified lock(s) to the set of locks on this resource. - ** - ** If "make_indirect" is true (non-zero), then the specified lock(s) - ** should be converted to an indirect lock (if it is a direct lock) - ** before appending. Note that the conversion to an indirect lock does - ** not alter the passed-in lock -- the change is internal the - ** append_locks function. - ** - ** Multiple locks are specified using the lock->next links. - */ - dav_error * (*append_locks)(dav_lockdb *lockdb, - const dav_resource *resource, - int make_indirect, - const dav_lock *lock); - - /* - ** Remove any lock that has the specified locktoken. - ** - ** If locktoken == NULL, then ALL locks are removed. - */ - dav_error * (*remove_lock)(dav_lockdb *lockdb, - const dav_resource *resource, - const dav_locktoken *locktoken); - - /* - ** Refresh all locks, found on the specified resource, which has a - ** locktoken in the provided list. - ** - ** If the lock is indirect, then the direct lock is referenced and - ** refreshed. - ** - ** Each lock that is updated is returned in the <locks> argument. - ** Note that the locks will be fully resolved. - */ - dav_error * (*refresh_locks)(dav_lockdb *lockdb, - const dav_resource *resource, - const dav_locktoken_list *ltl, - time_t new_time, - dav_lock **locks); - - /* - ** Look up the resource associated with a particular locktoken. - ** - ** The search begins at the specified <start_resource> and the lock - ** specified by <locktoken>. - ** - ** If the resource/token specifies an indirect lock, then the direct - ** lock will be looked up, and THAT resource will be returned. In other - ** words, this function always returns the resource where a particular - ** lock (token) was asserted. - ** - ** NOTE: this function pointer is allowed to be NULL, indicating that - ** the provider does not support this type of functionality. The - ** caller should then traverse up the repository hierarchy looking - ** for the resource defining a lock with this locktoken. - */ - dav_error * (*lookup_resource)(dav_lockdb *lockdb, - const dav_locktoken *locktoken, - const dav_resource *start_resource, - const dav_resource **resource); -}; - -/* what types of resources can be discovered by dav_get_resource_state() */ -#define DAV_RESOURCE_LOCK_NULL 10 /* resource lock-null */ -#define DAV_RESOURCE_NULL 11 /* resource null */ -#define DAV_RESOURCE_EXISTS 12 /* resource exists */ -#define DAV_RESOURCE_ERROR 13 /* an error occurred */ - - -/* -------------------------------------------------------------------- -** -** PROPERTY HANDLING -*/ - -typedef struct dav_propdb dav_propdb; - - -dav_error *dav_open_propdb( - request_rec *r, - dav_lockdb *lockdb, - const dav_resource *resource, - int ro, - apr_array_header_t *ns_xlate, - dav_propdb **propdb); - -void dav_close_propdb(dav_propdb *db); - -dav_get_props_result dav_get_props( - dav_propdb *db, - ap_xml_doc *doc); - -dav_get_props_result dav_get_allprops( - dav_propdb *db, - dav_prop_insert what); - -void dav_get_liveprop_supported( - dav_propdb *propdb, - const char *ns_uri, - const char *propname, - ap_text_header *body); - -/* -** 3-phase property modification. -** -** 1) validate props. readable? unlocked? ACLs allow access? -** 2) execute operation (set/delete) -** 3) commit or rollback -** -** ### eventually, auth must be available. a ref to the request_rec (which -** ### contains the auth info) should be in the shared context struct. -** -** Each function may alter the error values and information contained within -** the context record. This should be done as an "increasing" level of -** error, rather than overwriting any previous error. -** -** Note that commit() cannot generate errors. It should simply free the -** rollback information. -** -** rollback() may generate additional errors because the rollback operation -** can sometimes fail(!). -** -** The caller should allocate an array of these, one per operation. It should -** be zero-initialized, then the db, operation, and prop fields should be -** filled in before calling dav_prop_validate. Note that the set/delete -** operations are order-dependent. For a given (logical) context, the same -** pointer must be passed to each phase. -** -** error_type is an internal value, but will have the same numeric value -** for each possible "desc" value. This allows the caller to group the -** descriptions via the error_type variable, rather than through string -** comparisons. Note that "status" does not provide enough granularity to -** differentiate/group the "desc" values. -** -** Note that the propdb will maintain some (global) context across all -** of the property change contexts. This implies that you can have only -** one open transaction per propdb. -*/ -typedef struct dav_prop_ctx -{ - dav_propdb *propdb; - - int operation; -#define DAV_PROP_OP_SET 1 /* set a property value */ -#define DAV_PROP_OP_DELETE 2 /* delete a prop value */ -/* ### add a GET? */ - - ap_xml_elem *prop; /* property to affect */ - - dav_error *err; /* error (if any) */ - - /* private items to the propdb */ - int is_liveprop; - void *liveprop_ctx; - struct dav_rollback_item *rollback; /* optional rollback info */ - - /* private to mod_dav.c */ - request_rec *r; - -} dav_prop_ctx; - -void dav_prop_validate(dav_prop_ctx *ctx); -void dav_prop_exec(dav_prop_ctx *ctx); -void dav_prop_commit(dav_prop_ctx *ctx); -void dav_prop_rollback(dav_prop_ctx *ctx); - -#define DAV_PROP_CTX_HAS_ERR(dpc) ((dpc).err && (dpc).err->status >= 300) - - -/* -------------------------------------------------------------------- -** -** WALKER STRUCTURE -*/ - -enum { - DAV_CALLTYPE_MEMBER = 1, /* called for a member resource */ - DAV_CALLTYPE_COLLECTION, /* called for a collection */ - DAV_CALLTYPE_LOCKNULL /* called for a locknull resource */ -}; - -typedef struct -{ - /* the client-provided context */ - void *walk_ctx; - - /* pool to use for allocations in the callback */ - apr_pool_t *pool; - - /* the current resource */ - const dav_resource *resource; - - /* OUTPUT: add responses to this */ - dav_response *response; - -} dav_walk_resource; - -typedef struct -{ - int walk_type; -#define DAV_WALKTYPE_AUTH 0x0001 /* limit to authorized files */ -#define DAV_WALKTYPE_NORMAL 0x0002 /* walk normal files */ -#define DAV_WALKTYPE_LOCKNULL 0x0004 /* walk locknull resources */ - - /* callback function and a client context for the walk */ - dav_error * (*func)(dav_walk_resource *wres, int calltype); - void *walk_ctx; - - /* what pool to use for allocations needed by walk logic */ - apr_pool_t *pool; - - /* beginning root of the walk */ - const dav_resource *root; - - /* lock database to enable walking LOCKNULL resources */ - dav_lockdb *lockdb; - -} dav_walk_params; - -/* directory tree walking context */ -typedef struct dav_walker_ctx -{ - /* input: */ - dav_walk_params w; - - - /* ### client data... phasing out this big glom */ - - request_rec *r; /* original request */ - - /* for PROPFIND operations */ - ap_xml_doc *doc; - int propfind_type; -#define DAV_PROPFIND_IS_ALLPROP 1 -#define DAV_PROPFIND_IS_PROPNAME 2 -#define DAV_PROPFIND_IS_PROP 3 - - ap_text *propstat_404; /* (cached) propstat giving a 404 error */ - - const dav_if_header *if_header; /* for validation */ - const dav_locktoken *locktoken; /* for UNLOCK */ - const dav_lock *lock; /* for LOCK */ - int skip_root; /* for dav_inherit_locks() */ - - int flags; - - dav_buffer work_buf; /* for dav_validate_request() */ - -} dav_walker_ctx; - -DAV_DECLARE(void) dav_add_response(dav_walk_resource *wres, - int status, - dav_get_props_result *propstats); - - -/* -------------------------------------------------------------------- -** -** "STREAM" STRUCTURE -** -** mod_dav uses this abstraction for interacting with the repository -** while fetching/storing resources. mod_dav views resources as a stream -** of bytes. -** -** Note that the structure is opaque -- it is private to the repository -** that created the stream in the repository's "open" function. -*/ - -typedef struct dav_stream dav_stream; - -typedef enum { - DAV_MODE_READ, /* open for reading */ - DAV_MODE_READ_SEEKABLE, /* open for random access reading */ - DAV_MODE_WRITE_TRUNC, /* truncate and open for writing */ - DAV_MODE_WRITE_SEEKABLE /* open for writing; random access */ -} dav_stream_mode; - - -/* -------------------------------------------------------------------- -** -** REPOSITORY FUNCTIONS -*/ - -/* Repository provider hooks */ -struct dav_hooks_repository -{ - /* Flag for whether repository requires special GET handling. - * If resources in the repository are not visible in the - * filesystem location which URLs map to, then special handling - * is required to first fetch a resource from the repository, - * respond to the GET request, then free the resource copy. - */ - int handle_get; - - /* Get a resource descriptor for the URI in a request. A descriptor - * should always be returned even if the resource does not exist. This - * repository has been identified as handling the resource given by - * the URI, so an answer must be given. If there is a problem with the - * URI or accessing the resource or whatever, then an error should be - * returned. - * - * root_dir: - * the root of the directory for which this repository is configured. - * - * label: - * if a Label: header is present (and allowed), this is the label - * to use to identify a version resource from the resource's - * corresponding version history. Otherwise, it will be NULL. - * - * use_checked_in: - * use the DAV:checked-in property of the resource identified by the - * Request-URI to identify and return a version resource - * - * The provider may associate the request storage pool with the resource - * (in the resource->pool field), to use in other operations on that - * resource. - */ - dav_error * (*get_resource)( - request_rec *r, - const char *root_dir, - const char *label, - int use_checked_in, - dav_resource **resource - ); - - /* Get a resource descriptor for the parent of the given resource. - * The resources need not exist. NULL is returned if the resource - * is the root collection. - * - * An error should be returned only if there is a fatal error in - * fetching information about the parent resource. - */ - dav_error * (*get_parent_resource)( - const dav_resource *resource, - dav_resource **parent_resource - ); - - /* Determine whether two resource descriptors refer to the same resource. - * - * Result != 0 => the resources are the same. - */ - int (*is_same_resource)( - const dav_resource *res1, - const dav_resource *res2 - ); - - /* Determine whether one resource is a parent (immediate or otherwise) - * of another. - * - * Result != 0 => res1 is a parent of res2. - */ - int (*is_parent_resource)( - const dav_resource *res1, - const dav_resource *res2 - ); - - /* - ** Open a stream for this resource, using the specified mode. The - ** stream will be returned in *stream. - */ - dav_error * (*open_stream)(const dav_resource *resource, - dav_stream_mode mode, - dav_stream **stream); - - /* - ** Close the specified stream. - ** - ** mod_dav will (ideally) make sure to call this. For safety purposes, - ** a provider should (ideally) register a cleanup function with the - ** request pool to get this closed and cleaned up. - ** - ** Note the possibility of an error from the close -- it is entirely - ** feasible that the close does a "commit" of some kind, which can - ** produce an error. - ** - ** commit should be TRUE (non-zero) or FALSE (0) if the stream was - ** opened for writing. This flag states whether to retain the file - ** or not. - ** Note: the commit flag is ignored for streams opened for reading. - */ - dav_error * (*close_stream)(dav_stream *stream, int commit); - - /* - ** Read data from the stream. - ** - ** The size of the buffer is passed in *bufsize, and the amount read - ** is returned in *bufsize. - ** - ** *bufsize should be set to zero when the end of file is reached. - ** As a corollary, this function should always read at least one byte - ** on each call, until the EOF condition is met. - */ - dav_error * (*read_stream)(dav_stream *stream, - void *buf, apr_size_t *bufsize); - - /* - ** Write data to the stream. - ** - ** All of the bytes must be written, or an error should be returned. - */ - dav_error * (*write_stream)(dav_stream *stream, - const void *buf, apr_size_t bufsize); - - /* - ** Seek to an absolute position in the stream. This is used to support - ** Content-Range in a GET/PUT. - ** - ** NOTE: if this function is NULL (which is allowed), then any - ** operations using Content-Range will be refused. - */ - dav_error * (*seek_stream)(dav_stream *stream, apr_off_t abs_position); - - /* - ** If a GET is processed using a stream (open_stream, read_stream) - ** rather than via a sub-request (on get_pathname), then this function - ** is used to provide the repository with a way to set the headers - ** in the response. - ** - ** It may be NULL if get_pathname is provided. - */ - dav_error * (*set_headers)(request_rec *r, - const dav_resource *resource); - - /* Get a pathname for the file represented by the resource descriptor. - * A provider may need to create a temporary copy of the file, if it is - * not directly accessible in a filesystem. free_handle_p will be set by - * the provider to point to information needed to clean up any temporary - * storage used. - * - * Returns NULL if the file could not be made accessible. - */ - const char * (*get_pathname)( - const dav_resource *resource, - void **free_handle_p - ); - - /* Free any temporary storage associated with a file made accessible by - * get_pathname(). - */ - void (*free_file)( - void *free_handle - ); - - /* Create a collection resource. The resource must not already exist. - * - * Result == NULL if the collection was created successfully. Also, the - * resource object is updated to reflect that the resource exists, and - * is a collection. - */ - dav_error * (*create_collection)( - dav_resource *resource - ); - - /* Copy one resource to another. The destination may exist, if it is - * versioned. - * Handles both files and collections. Properties are copied as well. - * If the destination exists and is versioned, the provider must update - * the destination to have identical content to the source, - * recursively for collections. - * The depth argument is ignored for a file, and can be either 0 or - * DAV_INFINITY for a collection. - * If an error occurs in a child resource, then the return value is - * non-NULL, and *response is set to a multistatus response. - * If the copy is successful, the dst resource object is - * updated to reflect that the resource exists. - */ - dav_error * (*copy_resource)( - const dav_resource *src, - dav_resource *dst, - int depth, - dav_response **response - ); - - /* Move one resource to another. The destination must not exist. - * Handles both files and collections. Properties are moved as well. - * If an error occurs in a child resource, then the return value is - * non-NULL, and *response is set to a multistatus response. - * If the move is successful, the src and dst resource objects are - * updated to reflect that the source no longer exists, and the - * destination does. - */ - dav_error * (*move_resource)( - dav_resource *src, - dav_resource *dst, - dav_response **response - ); - - /* Remove a resource. Handles both files and collections. - * Removes any associated properties as well. - * If an error occurs in a child resource, then the return value is - * non-NULL, and *response is set to a multistatus response. - * If the delete is successful, the resource object is updated to - * reflect that the resource no longer exists. - */ - dav_error * (*remove_resource)( - dav_resource *resource, - dav_response **response - ); - - /* Walk a resource hierarchy. - * - * Iterates over the resource hierarchy specified by params->root. - * Control of the walk and the callback are specified by 'params'. - * - * An error may be returned. *response will contain multistatus - * responses (if any) suitable for the body of the error. It is also - * possible to return NULL, yet still have multistatus responses. - * In this case, typically the caller should return a 207 (Multistatus) - * and the responses (in the body) as the HTTP response. - */ - dav_error * (*walk)(const dav_walk_params *params, int depth, - dav_response **response); - - /* Get the entity tag for a resource */ - const char * (*getetag)(const dav_resource *resource); -}; - - -/* -------------------------------------------------------------------- -** -** VERSIONING FUNCTIONS -*/ - - -/* dav_add_vary_header - * - * If there were any headers in the request which require a Vary header - * in the response, add it. - */ -void dav_add_vary_header(request_rec *in_req, - request_rec *out_req, - const dav_resource *resource); - -/* -** Flags specifying auto-versioning behavior, returned by -** the auto_versionable hook. The value returned depends -** on both the state of the resource and the value of the -** DAV:auto-versioning property for the resource. -** -** If the resource does not exist (null or lock-null), -** DAV_AUTO_VERSION_ALWAYS causes creation of a new version-controlled resource -** -** If the resource is checked in, -** DAV_AUTO_VERSION_ALWAYS causes it to be checked out always, -** DAV_AUTO_VERSION_LOCKED causes it to be checked out only when locked -** -** If the resource is checked out, -** DAV_AUTO_VERSION_ALWAYS causes it to be checked in always, -** DAV_AUTO_VERSION_LOCKED causes it to be checked in when unlocked -** (note: a provider should allow auto-checkin only for resources which -** were automatically checked out) -** -** In all cases, DAV_AUTO_VERSION_NEVER results in no auto-versioning behavior. -*/ -typedef enum { - DAV_AUTO_VERSION_NEVER, - DAV_AUTO_VERSION_ALWAYS, - DAV_AUTO_VERSION_LOCKED -} dav_auto_version; - -/* -** This structure is used to record what auto-versioning operations -** were done to make a resource writable, so that they can be undone -** at the end of a request. -*/ -typedef struct { - int resource_versioned; /* 1 => resource was auto-version-controlled */ - int resource_checkedout; /* 1 => resource was auto-checked-out */ - int parent_checkedout; /* 1 => parent was auto-checked-out */ - dav_resource *parent_resource; /* parent resource, if it was needed */ -} dav_auto_version_info; - -/* Ensure that a resource is writable. If there is no versioning - * provider, then this is essentially a no-op. Versioning repositories - * require explicit resource creation and checkout before they can - * be written to. If a new resource is to be created, or an existing - * resource deleted, the parent collection must be checked out as well. - * - * Set the parent_only flag to only make the parent collection writable. - * Otherwise, both parent and child are made writable as needed. If the - * child does not exist, then a new versioned resource is created and - * checked out. - * - * If auto-versioning is not enabled for a versioned resource, then an error is - * returned, since the resource cannot be modified. - * - * The dav_auto_version_info structure is filled in with enough information - * to restore both parent and child resources to the state they were in - * before the auto-versioning operations occurred. - */ -dav_error *dav_auto_checkout( - request_rec *r, - dav_resource *resource, - int parent_only, - dav_auto_version_info *av_info); - -/* Revert the writability of resources back to what they were - * before they were modified. If undo == 0, then the resource - * modifications are maintained (i.e. they are checked in). - * If undo != 0, then resource modifications are discarded - * (i.e. they are unchecked out). - * - * Set the unlock flag to indicate that the resource is about - * to be unlocked; it will be checked in if the resource - * auto-versioning property indicates it should be. In this case, - * av_info is ignored, so it can be NULL. - * - * The resource argument may be NULL if only the parent resource - * was checked out (i.e. the parent_only was != 0 in the - * dav_auto_checkout call). - */ -dav_error *dav_auto_checkin( - request_rec *r, - dav_resource *resource, - int undo, - int unlock, - dav_auto_version_info *av_info); - -/* -** This structure is used to describe available reports -** -** "nmspace" should be valid XML and URL-quoted. mod_dav will place -** double-quotes around it and use it in an xmlns declaration. -*/ -typedef struct { - const char *nmspace; /* namespace of the XML report element */ - const char *name; /* element name for the XML report */ -} dav_report_elem; - - -/* Versioning provider hooks */ -struct dav_hooks_vsn -{ - /* - ** MANDATORY HOOKS - ** The following hooks are mandatory for all versioning providers; - ** they define the functionality needed to implement "core" versioning. - */ - - /* Return supported versioning options. - * Each dav_text item in the list will be returned as a separate - * DAV header. Providers are advised to limit the length of an - * individual text item to 63 characters, to conform to the limit - * used by MS Web Folders. - */ - void (*get_vsn_options)(apr_pool_t *p, ap_text_header *phdr); - - /* Get the value of a specific option for an OPTIONS request. - * The option being requested is given by the parsed XML - * element object "elem". The value of the option should be - * appended to the "option" text object. - */ - dav_error * (*get_option)(const dav_resource *resource, - const ap_xml_elem *elem, - ap_text_header *option); - - /* Determine whether a non-versioned (or non-existent) resource - * is versionable. Returns != 0 if resource can be versioned. - */ - int (*versionable)(const dav_resource *resource); - - /* Determine whether auto-versioning is enabled for a resource - * (which may not exist, or may not be versioned). If the resource - * is a checked-out resource, the provider must only enable - * auto-checkin if the resource was automatically checked out. - * - * The value returned depends on both the state of the resource - * and the value of its DAV:auto-version property. See the description - * of the dav_auto_version enumeration above for the details. - */ - dav_auto_version (*auto_versionable)(const dav_resource *resource); - - /* Put a resource under version control. If the resource already - * exists unversioned, then it becomes the initial version of the - * new version history, and it is replaced by a version selector - * which targets the new version. - * - * If the resource does not exist, then a new version-controlled - * resource is created which either targets an existing version (if the - * "target" argument is not NULL), or the initial, empty version - * in a new history resource (if the "target" argument is NULL). - * - * If successful, the resource object state is updated appropriately - * (that is, changed to refer to the new version-controlled resource). - */ - dav_error * (*vsn_control)(dav_resource *resource, - const char *target); - - /* Checkout a resource. If successful, the resource - * object state is updated appropriately. - * - * The auto_checkout flag will be set if this checkout is being - * done automatically, as part of some method which modifies - * the resource. The provider must remember that the resource - * was automatically checked out, so it can determine whether it - * can be automatically checked in. (Auto-checkin should only be - * enabled for resources which were automatically checked out.) - * - * If the working resource has a different URL from the - * target resource, a dav_resource descriptor is returned - * for the new working resource. Otherwise, the original - * resource descriptor will refer to the working resource. - * The working_resource argument can be NULL if the caller - * is not interested in the working resource. - * - * If the client has specified DAV:unreserved or DAV:fork-ok in the - * checkout request, then the corresponding flags are set. If - * DAV:activity-set has been specified, then create_activity is set - * if DAV:new was specified; otherwise, the DAV:href elements' CDATA - * (the actual href text) is passed in the "activities" array (each - * element of the array is a const char *). activities will be NULL - * no DAV:activity-set was provided or when create_activity is set. - */ - dav_error * (*checkout)(dav_resource *resource, - int auto_checkout, - int is_unreserved, int is_fork_ok, - int create_activity, - apr_array_header_t *activities, - dav_resource **working_resource); - - /* Uncheckout a checked-out resource. If successful, the resource - * object state is updated appropriately. - */ - dav_error * (*uncheckout)(dav_resource *resource); - - /* Checkin a checked-out resource. If successful, the resource - * object state is updated appropriately, and the - * version_resource descriptor will refer to the new version. - * The version_resource argument can be NULL if the caller - * is not interested in the new version resource. - * - * If the client has specified DAV:keep-checked-out in the checkin - * request, then the keep_checked_out flag is set. The provider - * should create a new version, but keep the resource in the - * checked-out state. - */ - dav_error * (*checkin)(dav_resource *resource, - int keep_checked_out, - dav_resource **version_resource); - - /* - ** Return the set of reports available at this resource. - ** - ** An array of report elements should be returned, with an end-marker - ** element containing namespace==NULL. The value of the - ** DAV:supported-report-set property will be constructed and - ** returned. - */ - dav_error * (*avail_reports)(const dav_resource *resource, - const dav_report_elem **reports); - - /* - ** Determine whether a Label header can be used - ** with a particular report. The dav_xml_doc structure - ** contains the parsed report request body. - ** Returns 0 if the Label header is not allowed. - */ - int (*report_label_header_allowed)(const ap_xml_doc *doc); - - /* - ** Generate a report on a resource. Since a provider is free - ** to define its own reports, and the value of request headers - ** may affect the interpretation of a report, the request record - ** must be passed to this routine. - ** - ** The dav_xml_doc structure contains the parsed report request - ** body. The report response is generated into the ap_text_header - ** structure. - ** - ** ### shouldn't generate large responses to memory ### - */ - dav_error * (*get_report)(request_rec *r, - const dav_resource *resource, - const ap_xml_doc *doc, - ap_text_header *report); - - /* - ** OPTIONAL HOOKS - ** The following hooks are optional; if not defined, then the - ** corresponding protocol methods will be unsupported. - */ - - /* - ** Set the state of a checked-in version-controlled resource. - ** - ** If the request specified a version, the version resource - ** represents that version. If the request specified a label, - ** then "version" is NULL, and "label" is the label. - ** - ** The depth argument is ignored for a file, and can be 0, 1, or - ** DAV_INFINITY for a collection. The depth argument only applies - ** with a label, not a version. - ** - ** If an error occurs in a child resource, then the return value is - ** non-NULL, and *response is set to a multistatus response. - ** - ** This hook is optional; if not defined, then the UPDATE method - ** will not be supported. - */ - dav_error * (*update)(const dav_resource *resource, - const dav_resource *version, - const char *label, - int depth, - dav_response **response); - - /* - ** Add a label to a version. The resource is either a specific - ** version, or a version selector, in which case the label should - ** be added to the current target of the version selector. The - ** version selector cannot be checked out. - ** - ** If replace != 0, any existing label by the same name is - ** effectively deleted first. Otherwise, it is an error to - ** attempt to add a label which already exists on some version - ** of the same history resource. - ** - ** This hook is optional; if not defined, then the LABEL method - ** will not be supported. If it is defined, then the remove_label - ** hook must be defined also. - */ - dav_error * (*add_label)(const dav_resource *resource, - const char *label, - int replace); - - /* - ** Remove a label from a version. The resource is either a specific - ** version, or a version selector, in which case the label should - ** be added to the current target of the version selector. The - ** version selector cannot be checked out. - ** - ** It is an error if no such label exists on the specified version. - ** - ** This hook is optional, but if defined, the add_label hook - ** must be defined also. - */ - dav_error * (*remove_label)(const dav_resource *resource, - const char *label); - - /* - ** Determine whether a null resource can be created as a workspace. - ** The provider may restrict workspaces to certain locations. - ** Returns 0 if the resource cannot be a workspace. - ** - ** This hook is optional; if the provider does not support workspaces, - ** it should be set to NULL. - */ - int (*can_be_workspace)(const dav_resource *resource); - - /* - ** Create a workspace resource. The resource must not already - ** exist. Any <DAV:mkworkspace> element is passed to the provider - ** in the "doc" structure; it may be empty. - ** - ** If workspace creation is succesful, the state of the resource - ** object is updated appropriately. - ** - ** This hook is optional; if the provider does not support workspaces, - ** it should be set to NULL. - */ - dav_error * (*make_workspace)(dav_resource *resource, - ap_xml_doc *doc); - - /* - ** Determine whether a null resource can be created as an activity. - ** The provider may restrict activities to certain locations. - ** Returns 0 if the resource cannot be an activity. - ** - ** This hook is optional; if the provider does not support activities, - ** it should be set to NULL. - */ - int (*can_be_activity)(const dav_resource *resource); - - /* - ** Create an activity resource. The resource must not already - ** exist. - ** - ** If activity creation is succesful, the state of the resource - ** object is updated appropriately. - ** - ** This hook is optional; if the provider does not support activities, - ** it should be set to NULL. - */ - dav_error * (*make_activity)(dav_resource *resource); - - /* - ** Merge a resource (tree) into target resource (tree). - ** - ** ### more doc... - ** - ** This hook is optional; if the provider does not support merging, - ** then this should be set to NULL. - */ - dav_error * (*merge)(dav_resource *target, dav_resource *source, - int no_auto_merge, int no_checkout, - ap_xml_elem *prop_elem, - ap_filter_t *output); -}; - - -/* -------------------------------------------------------------------- -** -** BINDING FUNCTIONS -*/ - -/* binding provider hooks */ -struct dav_hooks_binding { - - /* Determine whether a resource can be the target of a binding. - * Returns 0 if the resource cannot be a binding target. - */ - int (*is_bindable)(const dav_resource *resource); - - /* Create a binding to a resource. - * The resource argument is the target of the binding; - * the binding argument must be a resource which does not already - * exist. - */ - dav_error * (*bind_resource)(const dav_resource *resource, - dav_resource *binding); - -}; - - -/* -------------------------------------------------------------------- -** -** MISCELLANEOUS STUFF -*/ - -/* allow providers access to the per-directory parameters */ -apr_table_t *dav_get_dir_params(const request_rec *r); - -/* fetch the "LimitXMLRequestBody" in force for this resource */ -apr_size_t dav_get_limit_xml_body(const request_rec *r); - -typedef struct { - int propid; /* live property ID */ - const dav_hooks_liveprop *provider; /* the provider defining this prop */ -} dav_elem_private; - -#ifdef __cplusplus -} -#endif - -#endif /* _MOD_DAV_H_ */ diff --git a/modules/dav/main/mod_dav.mak b/modules/dav/main/mod_dav.mak deleted file mode 100644 index 531297978c..0000000000 --- a/modules/dav/main/mod_dav.mak +++ /dev/null @@ -1,659 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_dav.dsp -!IF "$(CFG)" == "" -CFG=mod_dav - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_dav - Win32 Release. -!ENDIF - -!IF "$(CFG)" != "mod_dav - Win32 Release" && "$(CFG)" !=\ - "mod_dav - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_dav.mak" CFG="mod_dav - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_dav - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_dav - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_dav - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_dav.so" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release"\ - "libapr - Win32 Release" "$(OUTDIR)\mod_dav.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN"\ - "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\liveprop.obj" - -@erase "$(INTDIR)\mod_dav.idb" - -@erase "$(INTDIR)\mod_dav.obj" - -@erase "$(INTDIR)\props.obj" - -@erase "$(INTDIR)\providers.obj" - -@erase "$(INTDIR)\std_liveprop.obj" - -@erase "$(INTDIR)\util.obj" - -@erase "$(INTDIR)\util_lock.obj" - -@erase "$(OUTDIR)\mod_dav.exp" - -@erase "$(OUTDIR)\mod_dav.lib" - -@erase "$(OUTDIR)\mod_dav.map" - -@erase "$(OUTDIR)\mod_dav.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\..\srclib\aputil" /I\ - "..\..\..\srclib\sdbm" /I "..\..\..\srclib\expat-lite" /I\ - "..\..\..\srclib\apr\include" /I "../../../srclib/apr-util/include" /I\ - "..\..\..\include" /I "..\..\..\os\win32" /D "NDEBUG" /D "WIN32" /D "_WINDOWS"\ - /D "DAV_DECLARE_EXPORT" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_dav" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_dav.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows\ - /dll /incremental:no /pdb:"$(OUTDIR)\mod_dav.pdb" /map:"$(INTDIR)\mod_dav.map"\ - /machine:I386 /out:"$(OUTDIR)\mod_dav.so" /implib:"$(OUTDIR)\mod_dav.lib"\ - /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav -LINK32_OBJS= \ - "$(INTDIR)\liveprop.obj" \ - "$(INTDIR)\mod_dav.obj" \ - "$(INTDIR)\props.obj" \ - "$(INTDIR)\providers.obj" \ - "$(INTDIR)\std_liveprop.obj" \ - "$(INTDIR)\util.obj" \ - "$(INTDIR)\util_lock.obj" \ - "..\..\..\Release\libhttpd.lib" \ - "..\..\..\srclib\apr-util\Release\libaprutil.lib" \ - "..\..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_dav.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_dav - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_dav.so" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug"\ - "libapr - Win32 Debug" "$(OUTDIR)\mod_dav.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN"\ - "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\liveprop.obj" - -@erase "$(INTDIR)\mod_dav.idb" - -@erase "$(INTDIR)\mod_dav.obj" - -@erase "$(INTDIR)\props.obj" - -@erase "$(INTDIR)\providers.obj" - -@erase "$(INTDIR)\std_liveprop.obj" - -@erase "$(INTDIR)\util.obj" - -@erase "$(INTDIR)\util_lock.obj" - -@erase "$(OUTDIR)\mod_dav.exp" - -@erase "$(OUTDIR)\mod_dav.ilk" - -@erase "$(OUTDIR)\mod_dav.lib" - -@erase "$(OUTDIR)\mod_dav.map" - -@erase "$(OUTDIR)\mod_dav.pdb" - -@erase "$(OUTDIR)\mod_dav.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\..\..\srclib\aputil" /I\ - "..\..\..\srclib\sdbm" /I "..\..\..\srclib\expat-lite" /I\ - "..\..\..\srclib\apr\include" /I "../../../srclib/apr-util/include" /I\ - "..\..\..\include" /I "..\..\..\os\win32" /D "_DEBUG" /D "WIN32" /D "_WINDOWS"\ - /D "DAV_DECLARE_EXPORT" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_dav" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_dav.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows\ - /dll /incremental:yes /pdb:"$(OUTDIR)\mod_dav.pdb" /map:"$(INTDIR)\mod_dav.map"\ - /debug /machine:I386 /out:"$(OUTDIR)\mod_dav.so"\ - /implib:"$(OUTDIR)\mod_dav.lib" /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav -LINK32_OBJS= \ - "$(INTDIR)\liveprop.obj" \ - "$(INTDIR)\mod_dav.obj" \ - "$(INTDIR)\props.obj" \ - "$(INTDIR)\providers.obj" \ - "$(INTDIR)\std_liveprop.obj" \ - "$(INTDIR)\util.obj" \ - "$(INTDIR)\util_lock.obj" \ - "..\..\..\Debug\libhttpd.lib" \ - "..\..\..\srclib\apr-util\Debug\libaprutil.lib" \ - "..\..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_dav.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_dav - Win32 Release" || "$(CFG)" ==\ - "mod_dav - Win32 Debug" -SOURCE=.\liveprop.c -DEP_CPP_LIVEP=\ - "..\..\..\include\ap_config.h"\ - "..\..\..\include\ap_mmn.h"\ - "..\..\..\include\ap_release.h"\ - "..\..\..\include\httpd.h"\ - "..\..\..\include\pcreposix.h"\ - "..\..\..\include\util_uri.h"\ - "..\..\..\include\util_xml.h"\ - "..\..\..\os\win32\os.h"\ - "..\..\..\srclib\apr-util\include\apr_dbm.h"\ - "..\..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\..\srclib\apr-util\include\apr_xml.h"\ - "..\..\..\srclib\apr-util\include\apu.h"\ - "..\..\..\srclib\apr-util\include\apu_compat.h"\ - "..\..\..\srclib\apr\include\apr.h"\ - "..\..\..\srclib\apr\include\apr_compat.h"\ - "..\..\..\srclib\apr\include\apr_errno.h"\ - "..\..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\..\srclib\apr\include\apr_general.h"\ - "..\..\..\srclib\apr\include\apr_hash.h"\ - "..\..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\..\srclib\apr\include\apr_pools.h"\ - "..\..\..\srclib\apr\include\apr_strings.h"\ - "..\..\..\srclib\apr\include\apr_tables.h"\ - "..\..\..\srclib\apr\include\apr_time.h"\ - "..\..\..\srclib\apr\include\apr_user.h"\ - "..\..\..\srclib\apr\include\apr_want.h"\ - ".\mod_dav.h"\ - -NODEP_CPP_LIVEP=\ - "..\..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\liveprop.obj" : $(SOURCE) $(DEP_CPP_LIVEP) "$(INTDIR)" - - -SOURCE=.\mod_dav.c -DEP_CPP_MOD_D=\ - "..\..\..\include\ap_config.h"\ - "..\..\..\include\ap_mmn.h"\ - "..\..\..\include\ap_release.h"\ - "..\..\..\include\http_config.h"\ - "..\..\..\include\http_core.h"\ - "..\..\..\include\http_log.h"\ - "..\..\..\include\http_main.h"\ - "..\..\..\include\http_protocol.h"\ - "..\..\..\include\http_request.h"\ - "..\..\..\include\httpd.h"\ - "..\..\..\include\pcreposix.h"\ - "..\..\..\include\util_cfgtree.h"\ - "..\..\..\include\util_filter.h"\ - "..\..\..\include\util_script.h"\ - "..\..\..\include\util_uri.h"\ - "..\..\..\include\util_xml.h"\ - "..\..\..\os\win32\os.h"\ - "..\..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\..\srclib\apr-util\include\apr_dbm.h"\ - "..\..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\..\srclib\apr-util\include\apr_xml.h"\ - "..\..\..\srclib\apr-util\include\apu.h"\ - "..\..\..\srclib\apr-util\include\apu_compat.h"\ - "..\..\..\srclib\apr\include\apr.h"\ - "..\..\..\srclib\apr\include\apr_compat.h"\ - "..\..\..\srclib\apr\include\apr_dso.h"\ - "..\..\..\srclib\apr\include\apr_errno.h"\ - "..\..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\..\srclib\apr\include\apr_general.h"\ - "..\..\..\srclib\apr\include\apr_hash.h"\ - "..\..\..\srclib\apr\include\apr_lib.h"\ - "..\..\..\srclib\apr\include\apr_lock.h"\ - "..\..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\..\srclib\apr\include\apr_pools.h"\ - "..\..\..\srclib\apr\include\apr_portable.h"\ - "..\..\..\srclib\apr\include\apr_strings.h"\ - "..\..\..\srclib\apr\include\apr_tables.h"\ - "..\..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\..\srclib\apr\include\apr_time.h"\ - "..\..\..\srclib\apr\include\apr_user.h"\ - "..\..\..\srclib\apr\include\apr_want.h"\ - ".\mod_dav.h"\ - -NODEP_CPP_MOD_D=\ - "..\..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\mod_dav.obj" : $(SOURCE) $(DEP_CPP_MOD_D) "$(INTDIR)" - - -SOURCE=.\props.c -DEP_CPP_PROPS=\ - "..\..\..\include\ap_config.h"\ - "..\..\..\include\ap_mmn.h"\ - "..\..\..\include\ap_release.h"\ - "..\..\..\include\http_log.h"\ - "..\..\..\include\http_request.h"\ - "..\..\..\include\httpd.h"\ - "..\..\..\include\pcreposix.h"\ - "..\..\..\include\util_filter.h"\ - "..\..\..\include\util_uri.h"\ - "..\..\..\include\util_xml.h"\ - "..\..\..\os\win32\os.h"\ - "..\..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\..\srclib\apr-util\include\apr_dbm.h"\ - "..\..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\..\srclib\apr-util\include\apr_xml.h"\ - "..\..\..\srclib\apr-util\include\apu.h"\ - "..\..\..\srclib\apr-util\include\apu_compat.h"\ - "..\..\..\srclib\apr\include\apr.h"\ - "..\..\..\srclib\apr\include\apr_compat.h"\ - "..\..\..\srclib\apr\include\apr_errno.h"\ - "..\..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\..\srclib\apr\include\apr_general.h"\ - "..\..\..\srclib\apr\include\apr_hash.h"\ - "..\..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\..\srclib\apr\include\apr_pools.h"\ - "..\..\..\srclib\apr\include\apr_strings.h"\ - "..\..\..\srclib\apr\include\apr_tables.h"\ - "..\..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\..\srclib\apr\include\apr_time.h"\ - "..\..\..\srclib\apr\include\apr_user.h"\ - "..\..\..\srclib\apr\include\apr_want.h"\ - ".\mod_dav.h"\ - -NODEP_CPP_PROPS=\ - "..\..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\props.obj" : $(SOURCE) $(DEP_CPP_PROPS) "$(INTDIR)" - - -SOURCE=.\providers.c -DEP_CPP_PROVI=\ - "..\..\..\include\ap_config.h"\ - "..\..\..\include\ap_mmn.h"\ - "..\..\..\include\ap_release.h"\ - "..\..\..\include\httpd.h"\ - "..\..\..\include\pcreposix.h"\ - "..\..\..\include\util_uri.h"\ - "..\..\..\include\util_xml.h"\ - "..\..\..\os\win32\os.h"\ - "..\..\..\srclib\apr-util\include\apr_dbm.h"\ - "..\..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\..\srclib\apr-util\include\apr_xml.h"\ - "..\..\..\srclib\apr-util\include\apu.h"\ - "..\..\..\srclib\apr-util\include\apu_compat.h"\ - "..\..\..\srclib\apr\include\apr.h"\ - "..\..\..\srclib\apr\include\apr_compat.h"\ - "..\..\..\srclib\apr\include\apr_errno.h"\ - "..\..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\..\srclib\apr\include\apr_general.h"\ - "..\..\..\srclib\apr\include\apr_hash.h"\ - "..\..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\..\srclib\apr\include\apr_pools.h"\ - "..\..\..\srclib\apr\include\apr_tables.h"\ - "..\..\..\srclib\apr\include\apr_time.h"\ - "..\..\..\srclib\apr\include\apr_user.h"\ - "..\..\..\srclib\apr\include\apr_want.h"\ - ".\mod_dav.h"\ - -NODEP_CPP_PROVI=\ - "..\..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\providers.obj" : $(SOURCE) $(DEP_CPP_PROVI) "$(INTDIR)" - - -SOURCE=.\std_liveprop.c -DEP_CPP_STD_L=\ - "..\..\..\include\ap_config.h"\ - "..\..\..\include\ap_mmn.h"\ - "..\..\..\include\ap_release.h"\ - "..\..\..\include\httpd.h"\ - "..\..\..\include\pcreposix.h"\ - "..\..\..\include\util_uri.h"\ - "..\..\..\include\util_xml.h"\ - "..\..\..\os\win32\os.h"\ - "..\..\..\srclib\apr-util\include\apr_dbm.h"\ - "..\..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\..\srclib\apr-util\include\apr_xml.h"\ - "..\..\..\srclib\apr-util\include\apu.h"\ - "..\..\..\srclib\apr-util\include\apu_compat.h"\ - "..\..\..\srclib\apr\include\apr.h"\ - "..\..\..\srclib\apr\include\apr_compat.h"\ - "..\..\..\srclib\apr\include\apr_errno.h"\ - "..\..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\..\srclib\apr\include\apr_general.h"\ - "..\..\..\srclib\apr\include\apr_hash.h"\ - "..\..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\..\srclib\apr\include\apr_pools.h"\ - "..\..\..\srclib\apr\include\apr_strings.h"\ - "..\..\..\srclib\apr\include\apr_tables.h"\ - "..\..\..\srclib\apr\include\apr_time.h"\ - "..\..\..\srclib\apr\include\apr_user.h"\ - "..\..\..\srclib\apr\include\apr_want.h"\ - ".\mod_dav.h"\ - -NODEP_CPP_STD_L=\ - "..\..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\std_liveprop.obj" : $(SOURCE) $(DEP_CPP_STD_L) "$(INTDIR)" - - -SOURCE=.\util.c -DEP_CPP_UTIL_=\ - "..\..\..\include\ap_config.h"\ - "..\..\..\include\ap_mmn.h"\ - "..\..\..\include\ap_release.h"\ - "..\..\..\include\http_config.h"\ - "..\..\..\include\http_log.h"\ - "..\..\..\include\http_protocol.h"\ - "..\..\..\include\http_request.h"\ - "..\..\..\include\http_vhost.h"\ - "..\..\..\include\httpd.h"\ - "..\..\..\include\pcreposix.h"\ - "..\..\..\include\util_cfgtree.h"\ - "..\..\..\include\util_filter.h"\ - "..\..\..\include\util_uri.h"\ - "..\..\..\include\util_xml.h"\ - "..\..\..\os\win32\os.h"\ - "..\..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\..\srclib\apr-util\include\apr_dbm.h"\ - "..\..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\..\srclib\apr-util\include\apr_xml.h"\ - "..\..\..\srclib\apr-util\include\apu.h"\ - "..\..\..\srclib\apr-util\include\apu_compat.h"\ - "..\..\..\srclib\apr\include\apr.h"\ - "..\..\..\srclib\apr\include\apr_compat.h"\ - "..\..\..\srclib\apr\include\apr_dso.h"\ - "..\..\..\srclib\apr\include\apr_errno.h"\ - "..\..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\..\srclib\apr\include\apr_general.h"\ - "..\..\..\srclib\apr\include\apr_hash.h"\ - "..\..\..\srclib\apr\include\apr_lib.h"\ - "..\..\..\srclib\apr\include\apr_lock.h"\ - "..\..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\..\srclib\apr\include\apr_pools.h"\ - "..\..\..\srclib\apr\include\apr_portable.h"\ - "..\..\..\srclib\apr\include\apr_strings.h"\ - "..\..\..\srclib\apr\include\apr_tables.h"\ - "..\..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\..\srclib\apr\include\apr_time.h"\ - "..\..\..\srclib\apr\include\apr_user.h"\ - "..\..\..\srclib\apr\include\apr_want.h"\ - ".\mod_dav.h"\ - -NODEP_CPP_UTIL_=\ - "..\..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\util.obj" : $(SOURCE) $(DEP_CPP_UTIL_) "$(INTDIR)" - - -SOURCE=.\util_lock.c -DEP_CPP_UTIL_L=\ - "..\..\..\include\ap_config.h"\ - "..\..\..\include\ap_mmn.h"\ - "..\..\..\include\ap_release.h"\ - "..\..\..\include\http_config.h"\ - "..\..\..\include\http_core.h"\ - "..\..\..\include\http_log.h"\ - "..\..\..\include\http_protocol.h"\ - "..\..\..\include\httpd.h"\ - "..\..\..\include\pcreposix.h"\ - "..\..\..\include\util_cfgtree.h"\ - "..\..\..\include\util_filter.h"\ - "..\..\..\include\util_uri.h"\ - "..\..\..\include\util_xml.h"\ - "..\..\..\os\win32\os.h"\ - "..\..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\..\srclib\apr-util\include\apr_dbm.h"\ - "..\..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\..\srclib\apr-util\include\apr_xml.h"\ - "..\..\..\srclib\apr-util\include\apu.h"\ - "..\..\..\srclib\apr-util\include\apu_compat.h"\ - "..\..\..\srclib\apr\include\apr.h"\ - "..\..\..\srclib\apr\include\apr_compat.h"\ - "..\..\..\srclib\apr\include\apr_dso.h"\ - "..\..\..\srclib\apr\include\apr_errno.h"\ - "..\..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\..\srclib\apr\include\apr_general.h"\ - "..\..\..\srclib\apr\include\apr_hash.h"\ - "..\..\..\srclib\apr\include\apr_lock.h"\ - "..\..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\..\srclib\apr\include\apr_pools.h"\ - "..\..\..\srclib\apr\include\apr_portable.h"\ - "..\..\..\srclib\apr\include\apr_strings.h"\ - "..\..\..\srclib\apr\include\apr_tables.h"\ - "..\..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\..\srclib\apr\include\apr_time.h"\ - "..\..\..\srclib\apr\include\apr_user.h"\ - "..\..\..\srclib\apr\include\apr_want.h"\ - ".\mod_dav.h"\ - -NODEP_CPP_UTIL_L=\ - "..\..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\util_lock.obj" : $(SOURCE) $(DEP_CPP_UTIL_L) "$(INTDIR)" - - -!IF "$(CFG)" == "mod_dav - Win32 Release" - -"libapr - Win32 Release" : - cd "..\../..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Release" - cd "..\..\modules\dav\main" - -"libapr - Win32 ReleaseCLEAN" : - cd "..\../..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\dav\main" - -!ELSEIF "$(CFG)" == "mod_dav - Win32 Debug" - -"libapr - Win32 Debug" : - cd "..\../..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Debug" - cd "..\..\modules\dav\main" - -"libapr - Win32 DebugCLEAN" : - cd "..\../..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\dav\main" - -!ENDIF - -!IF "$(CFG)" == "mod_dav - Win32 Release" - -"libaprutil - Win32 Release" : - cd "..\../..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"\ - - cd "..\..\modules\dav\main" - -"libaprutil - Win32 ReleaseCLEAN" : - cd "..\../..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libaprutil.mak"\ - CFG="libaprutil - Win32 Release" RECURSE=1 - cd "..\..\modules\dav\main" - -!ELSEIF "$(CFG)" == "mod_dav - Win32 Debug" - -"libaprutil - Win32 Debug" : - cd "..\../..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" - cd "..\..\modules\dav\main" - -"libaprutil - Win32 DebugCLEAN" : - cd "..\../..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libaprutil.mak"\ - CFG="libaprutil - Win32 Debug" RECURSE=1 - cd "..\..\modules\dav\main" - -!ENDIF - -!IF "$(CFG)" == "mod_dav - Win32 Release" - -"libhttpd - Win32 Release" : - cd "..\../.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Release" - cd ".\modules\dav\main" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "..\../.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Release"\ - RECURSE=1 - cd ".\modules\dav\main" - -!ELSEIF "$(CFG)" == "mod_dav - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "..\../.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Debug" - cd ".\modules\dav\main" - -"libhttpd - Win32 DebugCLEAN" : - cd "..\../.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\dav\main" - -!ENDIF - - -!ENDIF - diff --git a/modules/dav/main/props.c b/modules/dav/main/props.c deleted file mode 100644 index 2929a9a297..0000000000 --- a/modules/dav/main/props.c +++ /dev/null @@ -1,1590 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* -** DAV extension module for Apache 2.0.* -** - Property database handling (repository-independent) -** -** NOTES: -** -** PROPERTY DATABASE -** -** This version assumes that there is a per-resource database provider -** to record properties. The database provider decides how and where to -** store these databases. -** -** The DBM keys for the properties have the following form: -** -** namespace ":" propname -** -** For example: 5:author -** -** The namespace provides an integer index into the namespace table -** (see below). propname is simply the property name, without a namespace -** prefix. -** -** A special case exists for properties that had a prefix starting with -** "xml". The XML Specification reserves these for future use. mod_dav -** stores and retrieves them unchanged. The keys for these properties -** have the form: -** -** ":" propname -** -** The propname will contain the prefix and the property name. For -** example, a key might be ":xmlfoo:name" -** -** The ":name" style will also be used for properties that do not -** exist within a namespace. -** -** The DBM values consist of two null-terminated strings, appended -** together (the null-terms are retained and stored in the database). -** The first string is the xml:lang value for the property. An empty -** string signifies that a lang value was not in context for the value. -** The second string is the property value itself. -** -** -** NAMESPACE TABLE -** -** The namespace table is an array that lists each of the namespaces -** that are in use by the properties in the given propdb. Each entry -** in the array is a simple URI. -** -** For example: http://www.foo.bar/standards/props/ -** -** The prefix used for the property is stripped and the URI for it -** is entered into the namespace table. Also, any namespaces used -** within the property value will be entered into the table (and -** stripped from the child elements). -** -** The namespaces are stored in the DBM database under the "METADATA" key. -** -** -** STRIPPING NAMESPACES -** -** Within the property values, the namespace declarations (xmlns...) -** are stripped. Each element and attribute will have its prefix removed -** and a new prefix inserted. -** -** This must be done so that we can return multiple properties in a -** PROPFIND which may have (originally) used conflicting prefixes. For -** that case, we must bind all property value elements to new namespace -** values. -** -** This implies that clients must NOT be sensitive to the namespace -** prefix used for their properties. It WILL change when the properties -** are returned (we return them as "ns<index>", e.g. "ns5"). Also, the -** property value can contain ONLY XML elements and CDATA. PI and comment -** elements will be stripped. CDATA whitespace will be preserved, but -** whitespace within element tags will be altered. Attribute ordering -** may be altered. Element and CDATA ordering will be preserved. -** -** -** ATTRIBUTES ON PROPERTY NAME ELEMENTS -** -** When getting/setting properties, the XML used looks like: -** -** <prop> -** <propname1>value</propname1> -** <propname2>value</propname1> -** </prop> -** -** This implementation (mod_dav) DOES NOT save any attributes that are -** associated with the <propname1> element. The property value is deemed -** to be only the contents ("value" in the above example). -** -** We do store the xml:lang value (if any) that applies to the context -** of the <propname1> element. Whether the xml:lang attribute is on -** <propname1> itself, or from a higher level element, we will store it -** with the property value. -** -** -** VERSIONING -** -** The DBM db contains a key named "METADATA" that holds database-level -** information, such as the namespace table. The record also contains the -** db's version number as the very first 16-bit value. This first number -** is actually stored as two single bytes: the first byte is a "major" -** version number. The second byte is a "minor" number. -** -** If the major number is not what mod_dav expects, then the db is closed -** immediately and an error is returned. A minor number change is -** acceptable -- it is presumed that old/new dav_props.c can deal with -** the database format. For example, a newer dav_props might update the -** minor value and append information to the end of the metadata record -** (which would be ignored by previous versions). -** -** -** ISSUES: -** -** At the moment, for the dav_get_allprops() and dav_get_props() functions, -** we must return a set of xmlns: declarations for ALL known namespaces -** in the file. There isn't a way to filter this because we don't know -** which are going to be used or not. Examining property names is not -** sufficient because the property values could use entirely different -** namespaces. -** -** ==> we must devise a scheme where we can "garbage collect" the namespace -** entries from the property database. -*/ - -#include "apr.h" -#include "apr_strings.h" - -#define APR_WANT_STDIO -#define APR_WANT_BYTEFUNC -#include "apr_want.h" - -#include "mod_dav.h" - -#include "http_log.h" -#include "http_request.h" - -/* -** There is some rough support for writable DAV:getcontenttype and -** DAV:getcontentlanguage properties. If this #define is (1), then -** this support is disabled. -** -** We are disabling it because of a lack of support in GET and PUT -** operations. For GET, it would be "expensive" to look for a propdb, -** open it, and attempt to extract the Content-Type and Content-Language -** values for the response. -** (Handling the PUT would not be difficult, though) -*/ -#define DAV_DISABLE_WRITABLE_PROPS 1 - -#define DAV_GDBM_NS_KEY "METADATA" -#define DAV_GDBM_NS_KEY_LEN 8 - -#define DAV_EMPTY_VALUE "\0" /* TWO null terms */ - -/* the namespace URI was not found; no ID is available */ -#define AP_XML_NS_ERROR_NOT_FOUND (AP_XML_NS_ERROR_BASE) - -typedef struct { - unsigned char major; -#define DAV_DBVSN_MAJOR 4 - /* - ** V4 -- 0.9.9 .. - ** Prior versions could have keys or values with invalid - ** namespace prefixes as a result of the xmlns="" form not - ** resetting the default namespace to be "no namespace". The - ** namespace would be set to "" which is invalid; it should - ** be set to "no namespace". - ** - ** V3 -- 0.9.8 - ** Prior versions could have values with invalid namespace - ** prefixes due to an incorrect mapping of input to propdb - ** namespace indices. Version bumped to obsolete the old - ** values. - ** - ** V2 -- 0.9.7 - ** This introduced the xml:lang value into the property value's - ** record in the propdb. - ** - ** V1 -- .. 0.9.6 - ** Initial version. - */ - - - unsigned char minor; -#define DAV_DBVSN_MINOR 0 - - short ns_count; - -} dav_propdb_metadata; - -struct dav_propdb { - int version; /* *minor* version of this db */ - - apr_pool_t *p; /* the pool we should use */ - request_rec *r; /* the request record */ - - const dav_resource *resource; /* the target resource */ - - int deferred; /* open of db has been deferred */ - dav_db *db; /* underlying database containing props */ - - dav_buffer ns_table; /* table of namespace URIs */ - short ns_count; /* number of entries in table */ - int ns_table_dirty; /* ns_table was modified */ - - apr_array_header_t *ns_xlate; /* translation of an elem->ns to URI */ - int *ns_map; /* map elem->ns to propdb ns values */ - int incomplete_map; /* some mappings do not exist */ - - dav_lockdb *lockdb; /* the lock database */ - - dav_buffer wb_key; /* work buffer for dav_gdbm_key */ - dav_buffer wb_lock; /* work buffer for lockdiscovery property */ - - /* if we ever run a GET subreq, it will be stored here */ - request_rec *subreq; - - /* hooks we should use for processing (based on the target resource) */ - const dav_hooks_db *db_hooks; - -}; - -/* NOTE: dav_core_props[] and the following enum must stay in sync. */ -/* ### move these into a "core" liveprop provider? */ -static const char * const dav_core_props[] = -{ - "getcontenttype", - "getcontentlanguage", - "lockdiscovery", - "supportedlock", - - NULL /* sentinel */ -}; -enum { - DAV_PROPID_CORE_getcontenttype = DAV_PROPID_CORE, - DAV_PROPID_CORE_getcontentlanguage, - DAV_PROPID_CORE_lockdiscovery, - DAV_PROPID_CORE_supportedlock, - - DAV_PROPID_CORE_UNKNOWN -}; - -/* -** This structure is used to track information needed for a rollback. -** If a SET was performed and no prior value existed, then value.dptr -** will be NULL. -*/ -typedef struct dav_rollback_item { - dav_datum key; /* key for the item being saved */ - dav_datum value; /* value before set/replace/delete */ - - /* or use the following (choice selected by dav_prop_ctx.is_liveprop) */ - struct dav_liveprop_rollback *liveprop; /* liveprop rollback ctx */ - -} dav_rollback_item; - - -#if 0 -/* ### unused */ -static const char *dav_get_ns_table_uri(dav_propdb *propdb, int ns) -{ - const char *p = propdb->ns_table.buf + sizeof(dav_propdb_metadata); - - while (ns--) - p += strlen(p) + 1; - - return p; -} -#endif - -static int dav_find_liveprop_provider(dav_propdb *propdb, - const char *ns_uri, - const char *propname, - const dav_hooks_liveprop **provider) -{ - int propid; - - *provider = NULL; - - if (ns_uri == NULL) { - /* policy: liveprop providers cannot define no-namespace properties */ - return DAV_PROPID_CORE_UNKNOWN; - } - - /* check liveprop providers first, so they can define core properties */ - propid = dav_run_find_liveprop(propdb->resource, ns_uri, propname, - provider); - if (propid != 0) { - return propid; - } - - /* check for core property */ - if (strcmp(ns_uri, "DAV:") == 0) { - const char * const *p = dav_core_props; - - for (propid = DAV_PROPID_CORE; *p != NULL; ++p, ++propid) - if (strcmp(propname, *p) == 0) { - return propid; - } - } - - /* no provider for this property */ - return DAV_PROPID_CORE_UNKNOWN; -} - -static void dav_find_liveprop(dav_propdb *propdb, ap_xml_elem *elem) -{ - const char *ns_uri; - dav_elem_private *priv = elem->private; - const dav_hooks_liveprop *hooks; - - - if (elem->ns == AP_XML_NS_NONE) - ns_uri = NULL; - else if (elem->ns == AP_XML_NS_DAV_ID) - ns_uri = "DAV:"; - else - ns_uri = AP_XML_GET_URI_ITEM(propdb->ns_xlate, elem->ns); - - priv->propid = dav_find_liveprop_provider(propdb, ns_uri, elem->name, - &hooks); - - /* ### this test seems redundant... */ - if (priv->propid != DAV_PROPID_CORE_UNKNOWN) { - priv->provider = hooks; - } -} - -/* is the live property read/write? */ -static int dav_rw_liveprop(dav_propdb *propdb, dav_elem_private *priv) -{ - int propid = priv->propid; - - /* - ** Check the liveprop provider (if this is a provider-defined prop) - */ - if (priv->provider != NULL) { - return (*priv->provider->is_writable)(propdb->resource, propid); - } - - /* these are defined as read-only */ - if (propid == DAV_PROPID_CORE_lockdiscovery -#if DAV_DISABLE_WRITABLE_PROPS - || propid == DAV_PROPID_CORE_getcontenttype - || propid == DAV_PROPID_CORE_getcontentlanguage -#endif - || propid == DAV_PROPID_CORE_supportedlock - ) { - - return 0; - } - - /* these are defined as read/write */ - if (propid == DAV_PROPID_CORE_getcontenttype - || propid == DAV_PROPID_CORE_getcontentlanguage - || propid == DAV_PROPID_CORE_UNKNOWN) { - - return 1; - } - - /* - ** We don't recognize the property, so it must be dead (and writable) - */ - return 1; -} - -/* do a sub-request to fetch properties for the target resource's URI. */ -static void dav_do_prop_subreq(dav_propdb *propdb) -{ - /* perform a "GET" on the resource's URI (note that the resource - may not correspond to the current request!). */ - propdb->subreq = ap_sub_req_lookup_uri(propdb->resource->uri, propdb->r, - NULL); -} - -static dav_error * dav_insert_coreprop(dav_propdb *propdb, - int propid, const char *name, - dav_prop_insert what, - ap_text_header *phdr, - dav_prop_insert *inserted) -{ - const char *value = NULL; - dav_error *err; - - *inserted = DAV_PROP_INSERT_NOTDEF; - - /* fast-path the common case */ - if (propid == DAV_PROPID_CORE_UNKNOWN) - return NULL; - - switch (propid) { - - case DAV_PROPID_CORE_lockdiscovery: - if (propdb->lockdb != NULL) { - dav_lock *locks; - - if ((err = dav_lock_query(propdb->lockdb, propdb->resource, - &locks)) != NULL) { - return dav_push_error(propdb->p, err->status, 0, - "DAV:lockdiscovery could not be " - "determined due to a problem fetching " - "the locks for this resource.", - err); - } - - /* fast-path the no-locks case */ - if (locks == NULL) { - value = ""; - } - else { - /* - ** This may modify the buffer. value may point to - ** wb_lock.pbuf or a string constant. - */ - value = dav_lock_get_activelock(propdb->r, locks, - &propdb->wb_lock); - - /* make a copy to isolate it from changes to wb_lock */ - value = apr_pstrdup(propdb->p, propdb->wb_lock.buf); - } - } - break; - - case DAV_PROPID_CORE_supportedlock: - if (propdb->lockdb != NULL) { - value = (*propdb->lockdb->hooks->get_supportedlock)(propdb->resource); - } - break; - - case DAV_PROPID_CORE_getcontenttype: - if (propdb->subreq == NULL) { - dav_do_prop_subreq(propdb); - } - if (propdb->subreq->content_type != NULL) { - value = propdb->subreq->content_type; - } - break; - - case DAV_PROPID_CORE_getcontentlanguage: - { - const char *lang; - - if (propdb->subreq == NULL) { - dav_do_prop_subreq(propdb); - } - if ((lang = apr_table_get(propdb->subreq->headers_out, - "Content-Language")) != NULL) { - value = lang; - } - break; - } - - default: - /* fall through to interpret as a dead property */ - break; - } - - /* if something was supplied, then insert it */ - if (value != NULL) { - const char *s; - - if (what == DAV_PROP_INSERT_SUPPORTED) { - /* use D: prefix to refer to the DAV: namespace URI, - * and let the namespace attribute default to "DAV:" - */ - s = apr_psprintf(propdb->p, - "<D:supported-live-property D:name=\"%s\"/>" DEBUG_CR, - name); - } - else if (what == DAV_PROP_INSERT_VALUE && *value != '\0') { - /* use D: prefix to refer to the DAV: namespace URI */ - s = apr_psprintf(propdb->p, "<D:%s>%s</D:%s>" DEBUG_CR, - name, value, name); - } - else { - /* use D: prefix to refer to the DAV: namespace URI */ - s = apr_psprintf(propdb->p, "<D:%s/>" DEBUG_CR, name); - } - ap_text_append(propdb->p, phdr, s); - - *inserted = what; - } - - return NULL; -} - -static dav_error * dav_insert_liveprop(dav_propdb *propdb, - const ap_xml_elem *elem, - dav_prop_insert what, - ap_text_header *phdr, - dav_prop_insert *inserted) -{ - dav_elem_private *priv = elem->private; - - *inserted = DAV_PROP_INSERT_NOTDEF; - - if (priv->provider == NULL) { - /* this is a "core" property that we define */ - return dav_insert_coreprop(propdb, priv->propid, elem->name, - what, phdr, inserted); - } - - /* ask the provider (that defined this prop) to insert the prop */ - *inserted = (*priv->provider->insert_prop)(propdb->resource, priv->propid, - what, phdr); - - return NULL; -} - -static void dav_append_prop(dav_propdb *propdb, - const char *name, const char *value, - ap_text_header *phdr) -{ - const char *s; - const char *lang = value; - - /* skip past the xml:lang value */ - value += strlen(lang) + 1; - - if (*value == '\0') { - /* the property is an empty value */ - if (*name == ':') { - /* "no namespace" case */ - s = apr_psprintf(propdb->p, "<%s/>" DEBUG_CR, name+1); - } - else { - s = apr_psprintf(propdb->p, "<ns%s/>" DEBUG_CR, name); - } - } - else if (*lang != '\0') { - if (*name == ':') { - /* "no namespace" case */ - s = apr_psprintf(propdb->p, "<%s xml:lang=\"%s\">%s</%s>" DEBUG_CR, - name+1, lang, value, name+1); - } - else { - s = apr_psprintf(propdb->p, "<ns%s xml:lang=\"%s\">%s</ns%s>" DEBUG_CR, - name, lang, value, name); - } - } - else if (*name == ':') { - /* "no namespace" case */ - s = apr_psprintf(propdb->p, "<%s>%s</%s>" DEBUG_CR, name+1, value, name+1); - } - else { - s = apr_psprintf(propdb->p, "<ns%s>%s</ns%s>" DEBUG_CR, name, value, name); - } - ap_text_append(propdb->p, phdr, s); -} - -/* -** Prepare the ns_map variable in the propdb structure. This entails copying -** all URIs from the "input" namespace list (in propdb->ns_xlate) into the -** propdb's list of namespaces. As each URI is copied (or pre-existing -** URI looked up), the index mapping is stored into the ns_map variable. -** -** Note: we must copy all declared namespaces because we cannot easily -** determine which input namespaces were actually used within the property -** values that are being stored within the propdb. Theoretically, we can -** determine this at the point where we serialize the property values -** back into strings. This would require a bit more work, and will be -** left to future optimizations. -** -** ### we should always initialize the propdb namespace array with "DAV:" -** ### since we know it will be entered anyhow (by virtue of it always -** ### occurring in the ns_xlate array). That will allow us to use -** ### AP_XML_NS_DAV_ID for propdb ns values, too. -*/ -static void dav_prep_ns_map(dav_propdb *propdb, int add_ns) -{ - int i; - const char **puri; - const int orig_count = propdb->ns_count; - int *pmap; - int updating = 0; /* are we updating an existing ns_map? */ - - if (propdb->ns_map) { - if (add_ns && propdb->incomplete_map) { - /* we must revisit the map and insert new entries */ - updating = 1; - propdb->incomplete_map = 0; - } - else { - /* nothing to do: we have a proper ns_map */ - return; - } - } - else { - propdb->ns_map = apr_palloc(propdb->p, propdb->ns_xlate->nelts * sizeof(*propdb->ns_map)); - } - - pmap = propdb->ns_map; - - /* ### stupid O(n * orig_count) algorithm */ - for (i = propdb->ns_xlate->nelts, puri = (const char **)propdb->ns_xlate->elts; - i-- > 0; - ++puri, ++pmap) { - - const char *uri = *puri; - const size_t uri_len = strlen(uri); - - if (updating) { - /* updating an existing mapping... we can skip a lot of stuff */ - - if (*pmap != AP_XML_NS_ERROR_NOT_FOUND) { - /* This entry has been filled in, so we can skip it */ - continue; - } - } - else { - int j; - size_t len; - const char *p; - - /* - ** GIVEN: uri (a namespace URI from the request input) - ** - ** FIND: an equivalent URI in the propdb namespace table - */ - - /* only scan original entries (we may have added some in here) */ - for (p = propdb->ns_table.buf + sizeof(dav_propdb_metadata), - j = 0; - j < orig_count; - ++j, p += len + 1) { - - len = strlen(p); - - if (uri_len != len) - continue; - if (memcmp(uri, p, len) == 0) { - *pmap = j; - goto next_input_uri; - } - } - - if (!add_ns) { - *pmap = AP_XML_NS_ERROR_NOT_FOUND; - - /* - ** This flag indicates that we have an ns_map with missing - ** entries. If dav_prep_ns_map() is called with add_ns==1 AND - ** this flag is set, then we zip thru the array and add those - ** URIs (effectively updating the ns_map as if add_ns=1 was - ** passed when the initial prep was called). - */ - propdb->incomplete_map = 1; - - continue; - } - } - - /* - ** The input URI was not found in the propdb namespace table, and - ** we are supposed to add it. Append it to the table and store - ** the index into the ns_map. - */ - dav_check_bufsize(propdb->p, &propdb->ns_table, uri_len + 1); - memcpy(propdb->ns_table.buf + propdb->ns_table.cur_len, uri, uri_len + 1); - propdb->ns_table.cur_len += uri_len + 1; - - propdb->ns_table_dirty = 1; - - *pmap = propdb->ns_count++; - - next_input_uri: - ; - } -} - -/* find the "DAV:" namespace in our table and return its ID. */ -static int dav_find_dav_id(dav_propdb *propdb) -{ - const char *p = propdb->ns_table.buf + sizeof(dav_propdb_metadata); - int ns; - - for (ns = 0; ns < propdb->ns_count; ++ns) { - size_t len = strlen(p); - - if (len == 4 && memcmp(p, "DAV:", 5) == 0) - return ns; - p += len + 1; - } - - /* the "DAV:" namespace is not present */ - return -1; -} - -static void dav_insert_xmlns(apr_pool_t *p, const char *pre_prefix, int ns, - const char *ns_uri, ap_text_header *phdr) -{ - const char *s; - - s = apr_psprintf(p, " xmlns:%s%d=\"%s\"", pre_prefix, ns, ns_uri); - ap_text_append(p, phdr, s); -} - -/* return all known namespaces (in this propdb) */ -static void dav_get_propdb_xmlns(dav_propdb *propdb, ap_text_header *phdr) -{ - int i; - const char *p = propdb->ns_table.buf + sizeof(dav_propdb_metadata); - size_t len; - - /* note: ns_count == 0 when we have no propdb file */ - for (i = 0; i < propdb->ns_count; ++i, p += len + 1) { - - len = strlen(p); - - dav_insert_xmlns(propdb->p, "ns", i, p, phdr); - } -} - -/* add a namespace decl from one of the namespace tables */ -static void dav_add_marked_xmlns(dav_propdb *propdb, char *marks, int ns, - apr_array_header_t *ns_table, - const char *pre_prefix, - ap_text_header *phdr) -{ - if (marks[ns]) - return; - marks[ns] = 1; - - dav_insert_xmlns(propdb->p, - pre_prefix, ns, AP_XML_GET_URI_ITEM(ns_table, ns), - phdr); -} - -/* -** Internal function to build a key -** -** WARNING: returns a pointer to a "static" buffer holding the key. The -** value must be copied or no longer used if this function is -** called again. -*/ -static dav_datum dav_gdbm_key(dav_propdb *propdb, const ap_xml_elem *elem) -{ - int ns; - char nsbuf[20]; - size_t l_ns; - size_t l_name = strlen(elem->name); - dav_datum key = { 0 }; - - /* - * Convert namespace ID to a string. "no namespace" is an empty string, - * so the keys will have the form ":name". Otherwise, the keys will - * have the form "#:name". - */ - if (elem->ns == AP_XML_NS_NONE) { - nsbuf[0] = '\0'; - l_ns = 0; - } - else { - if (propdb->ns_map == NULL) { - /* - * Note that we prep the map and do NOT add namespaces. If that - * is required, then the caller should have called prep - * beforehand, passing the correct values. - */ - dav_prep_ns_map(propdb, 0); - } - - ns = propdb->ns_map[elem->ns]; - if (AP_XML_NS_IS_ERROR(ns)) - return key; /* zeroed */ - - l_ns = sprintf(nsbuf, "%d", ns); - } - - /* assemble: #:name */ - dav_set_bufsize(propdb->p, &propdb->wb_key, l_ns + 1 + l_name + 1); - memcpy(propdb->wb_key.buf, nsbuf, l_ns); - propdb->wb_key.buf[l_ns] = ':'; - memcpy(&propdb->wb_key.buf[l_ns + 1], elem->name, l_name + 1); - - /* build the database key */ - key.dsize = l_ns + 1 + l_name + 1; - key.dptr = propdb->wb_key.buf; - - return key; -} - -static dav_error *dav_really_open_db(dav_propdb *propdb, int ro) -{ - dav_error *err; - dav_datum key; - dav_datum value = { 0 }; - - /* we're trying to open the db; turn off the 'deferred' flag */ - propdb->deferred = 0; - - /* ask the DB provider to open the thing */ - err = (*propdb->db_hooks->open)(propdb->p, propdb->resource, ro, - &propdb->db); - if (err != NULL) { - return dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_PROP_OPENING, - "Could not open the property database.", - err); - } - - /* - ** NOTE: propdb->db could be NULL if we attempted to open a readonly - ** database that doesn't exist. If we require read/write - ** access, then a database was created and opened. - */ - - if (propdb->db != NULL) { - key.dptr = DAV_GDBM_NS_KEY; - key.dsize = DAV_GDBM_NS_KEY_LEN; - if ((err = (*propdb->db_hooks->fetch)(propdb->db, key, - &value)) != NULL) { - /* ### push a higher-level description? */ - return err; - } - } - if (value.dptr == NULL) { - dav_propdb_metadata m = { - DAV_DBVSN_MAJOR, DAV_DBVSN_MINOR, 0 - }; - - if (propdb->db != NULL) { - /* - * If there is no METADATA key, then the database may be - * from versions 0.9.0 .. 0.9.4 (which would be incompatible). - * These can be identified by the presence of an NS_TABLE entry. - */ - key.dptr = "NS_TABLE"; - key.dsize = 8; - if ((*propdb->db_hooks->exists)(propdb->db, key)) { - (*propdb->db_hooks->close)(propdb->db); - - /* call it a major version error */ - return dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_PROP_BAD_MAJOR, - "Prop database has the wrong major " - "version number and cannot be used."); - } - } - - /* initialize a new metadata structure */ - dav_set_bufsize(propdb->p, &propdb->ns_table, sizeof(m)); - memcpy(propdb->ns_table.buf, &m, sizeof(m)); - } - else { - dav_propdb_metadata m; - - dav_set_bufsize(propdb->p, &propdb->ns_table, value.dsize); - memcpy(propdb->ns_table.buf, value.dptr, value.dsize); - - memcpy(&m, value.dptr, sizeof(m)); - if (m.major != DAV_DBVSN_MAJOR) { - (*propdb->db_hooks->close)(propdb->db); - - return dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_PROP_BAD_MAJOR, - "Prop database has the wrong major " - "version number and cannot be used."); - } - propdb->version = m.minor; - propdb->ns_count = ntohs(m.ns_count); - - (*propdb->db_hooks->freedatum)(propdb->db, value); - } - - return NULL; -} - -dav_error *dav_open_propdb(request_rec *r, dav_lockdb *lockdb, - const dav_resource *resource, - int ro, - apr_array_header_t * ns_xlate, - dav_propdb **p_propdb) -{ - dav_propdb *propdb = apr_pcalloc(r->pool, sizeof(*propdb)); - - *p_propdb = NULL; - -#if DAV_DEBUG - if (resource->uri == NULL) { - return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "INTERNAL DESIGN ERROR: resource must define " - "its URI."); - } -#endif - - propdb->version = DAV_DBVSN_MINOR; - propdb->r = r; - propdb->p = r->pool; /* ### get rid of this */ - propdb->resource = resource; - propdb->ns_xlate = ns_xlate; - - propdb->db_hooks = DAV_GET_HOOKS_PROPDB(r); - - propdb->lockdb = lockdb; - - /* always defer actual open, to avoid expense of accessing db - * when only live properties are involved - */ - propdb->deferred = 1; - - /* ### what to do about closing the propdb on server failure? */ - - *p_propdb = propdb; - return NULL; -} - -void dav_close_propdb(dav_propdb *propdb) -{ - if (propdb->db == NULL) - return; - - if (propdb->ns_table_dirty) { - dav_propdb_metadata m; - dav_datum key; - dav_datum value; - dav_error *err; - - key.dptr = DAV_GDBM_NS_KEY; - key.dsize = DAV_GDBM_NS_KEY_LEN; - - value.dptr = propdb->ns_table.buf; - value.dsize = propdb->ns_table.cur_len; - - /* fill in the metadata that we store into the prop db. */ - m.major = DAV_DBVSN_MAJOR; - m.minor = propdb->version; /* ### keep current minor version? */ - m.ns_count = htons(propdb->ns_count); - - memcpy(propdb->ns_table.buf, &m, sizeof(m)); - - err = (*propdb->db_hooks->store)(propdb->db, key, value); - /* ### what to do with the error? */ - } - - (*propdb->db_hooks->close)(propdb->db); -} - -dav_get_props_result dav_get_allprops(dav_propdb *propdb, dav_prop_insert what) -{ - const dav_hooks_db *db_hooks = propdb->db_hooks; - ap_text_header hdr = { 0 }; - ap_text_header hdr_ns = { 0 }; - dav_get_props_result result = { 0 }; - int found_contenttype = 0; - int found_contentlang = 0; - dav_prop_insert unused_inserted; - - /* if not just getting supported live properties, - * scan all properties in the dead prop database - */ - if (what != DAV_PROP_INSERT_SUPPORTED) { - if (propdb->deferred) { - /* ### what to do with db open error? */ - (void) dav_really_open_db(propdb, 1 /*ro*/); - } - - /* generate all the namespaces that are in the propdb */ - dav_get_propdb_xmlns(propdb, &hdr_ns); - - /* initialize the result with some start tags... */ - ap_text_append(propdb->p, &hdr, - "<D:propstat>" DEBUG_CR - "<D:prop>" DEBUG_CR); - - /* if there ARE properties, then scan them */ - if (propdb->db != NULL) { - dav_datum key; - int dav_id = dav_find_dav_id(propdb); - - (void) (*db_hooks->firstkey)(propdb->db, &key); - while (key.dptr) { - dav_datum prevkey; - - /* any keys with leading capital letters should be skipped - (real keys start with a number or a colon) */ - if (*key.dptr >= 'A' && *key.dptr <= 'Z') - goto next_key; - - /* - ** We also look for <DAV:getcontenttype> and - ** <DAV:getcontentlanguage>. If they are not stored as dead - ** properties, then we need to perform a subrequest to get - ** their values (if any). - */ - if (dav_id != -1 - && *key.dptr != ':' - && dav_id == atoi(key.dptr)) { - - const char *colon; - - /* find the colon */ - if ( key.dptr[1] == ':' ) { - colon = key.dptr + 1; - } - else { - colon = strchr(key.dptr + 2, ':'); - } - - if (colon[1] == 'g') { - if (strcmp(colon + 1, "getcontenttype") == 0) { - found_contenttype = 1; - } - else if (strcmp(colon + 1, "getcontentlanguage") == 0) { - found_contentlang = 1; - } - } - } - - if (what == DAV_PROP_INSERT_VALUE) { - dav_datum value; - - (void) (*db_hooks->fetch)(propdb->db, key, &value); - if (value.dptr == NULL) { - /* ### anything better to do? */ - /* ### probably should enter a 500 error */ - goto next_key; - } - - /* put the prop name and value into the result */ - dav_append_prop(propdb, key.dptr, value.dptr, &hdr); - - (*db_hooks->freedatum)(propdb->db, value); - } - else { - /* simple, empty element if a value isn't needed */ - dav_append_prop(propdb, key.dptr, DAV_EMPTY_VALUE, &hdr); - } - - next_key: - prevkey = key; - (void) (*db_hooks->nextkey)(propdb->db, &key); - (*db_hooks->freedatum)(propdb->db, prevkey); - } - } - - /* add namespaces for all the liveprop providers */ - dav_add_all_liveprop_xmlns(propdb->p, &hdr_ns); - } - - /* ask the liveprop providers to insert their properties */ - dav_run_insert_all_liveprops(propdb->r, propdb->resource, what, &hdr); - - /* insert the standard properties */ - /* ### should be handling the return errors here */ - (void)dav_insert_coreprop(propdb, - DAV_PROPID_CORE_supportedlock, "supportedlock", - what, &hdr, &unused_inserted); - (void)dav_insert_coreprop(propdb, - DAV_PROPID_CORE_lockdiscovery, "lockdiscovery", - what, &hdr, &unused_inserted); - - /* if we didn't find these, then do the whole subreq thing. */ - if (!found_contenttype) { - /* ### should be handling the return error here */ - (void)dav_insert_coreprop(propdb, - DAV_PROPID_CORE_getcontenttype, - "getcontenttype", - what, &hdr, &unused_inserted); - } - if (!found_contentlang) { - /* ### should be handling the return error here */ - (void)dav_insert_coreprop(propdb, - DAV_PROPID_CORE_getcontentlanguage, - "getcontentlanguage", - what, &hdr, &unused_inserted); - } - - /* if not just reporting on supported live props, - * terminate the result */ - if (what != DAV_PROP_INSERT_SUPPORTED) { - ap_text_append(propdb->p, &hdr, - "</D:prop>" DEBUG_CR - "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR - "</D:propstat>" DEBUG_CR); - } - - result.propstats = hdr.first; - result.xmlns = hdr_ns.first; - return result; -} - -dav_get_props_result dav_get_props(dav_propdb *propdb, ap_xml_doc *doc) -{ - const dav_hooks_db *db_hooks = propdb->db_hooks; - ap_xml_elem *elem = dav_find_child(doc->root, "prop"); - ap_text_header hdr_good = { 0 }; - ap_text_header hdr_bad = { 0 }; - ap_text_header hdr_ns = { 0 }; - int have_good = 0; - int propdb_xmlns_done = 0; - dav_get_props_result result = { 0 }; - char *marks_input; - char *marks_liveprop; - - /* ### NOTE: we should pass in TWO buffers -- one for keys, one for - the marks */ - - /* we will ALWAYS provide a "good" result, even if it is EMPTY */ - ap_text_append(propdb->p, &hdr_good, - "<D:propstat>" DEBUG_CR - "<D:prop>" DEBUG_CR); - - /* ### the marks should be in a buffer! */ - /* allocate zeroed-memory for the marks. These marks indicate which - input namespaces we've generated into the output xmlns buffer */ - marks_input = apr_pcalloc(propdb->p, propdb->ns_xlate->nelts); - - /* same for the liveprops */ - marks_liveprop = apr_pcalloc(propdb->p, dav_get_liveprop_ns_count() + 1); - - for (elem = elem->first_child; elem; elem = elem->next) { - dav_datum key = { 0 }; - dav_datum value = { 0 }; - dav_elem_private *priv; - dav_error *err; - dav_prop_insert inserted; - int is_liveprop = 0; - - /* - ** First try live property providers; if they don't handle - ** the property, then try looking it up in the propdb. - */ - - if (elem->private == NULL) { - elem->private = apr_pcalloc(propdb->p, sizeof(*priv)); - } - priv = elem->private; - - /* cache the propid; dav_get_props() could be called many times */ - if (priv->propid == 0) - dav_find_liveprop(propdb, elem); - - if (priv->propid != DAV_PROPID_CORE_UNKNOWN) { - is_liveprop = 1; - - /* insert the property. returns 1 if an insertion was done. */ - if ((err = dav_insert_liveprop(propdb, elem, DAV_PROP_INSERT_VALUE, - &hdr_good, &inserted)) != NULL) { - /* ### need to propagate the error to the caller... */ - /* ### skip it for now, as if nothing was inserted */ - } - if (inserted == DAV_PROP_INSERT_VALUE) { - have_good = 1; - - /* - ** Add the liveprop's namespace URIs. Note that provider==NULL - ** for core properties. - */ - if (priv->provider != NULL) { - const char * const * scan_ns_uri; - - for (scan_ns_uri = priv->provider->namespace_uris; - *scan_ns_uri != NULL; - ++scan_ns_uri) { - int ns; - - ns = dav_get_liveprop_ns_index(*scan_ns_uri); - if (marks_liveprop[ns]) - continue; - marks_liveprop[ns] = 1; - - dav_insert_xmlns(propdb->p, "lp", ns, *scan_ns_uri, - &hdr_ns); - } - } - - continue; - } - else if (inserted == DAV_PROP_INSERT_NOTDEF) { - /* allow property to be handled as a dead property */ - is_liveprop = 0; - } - } - - /* - ** If not handled as a live property, look in the dead property - ** database. - */ - if (!is_liveprop) { - /* make sure propdb is really open */ - if (propdb->deferred) { - /* ### what to do with db open error? */ - (void) dav_really_open_db(propdb, 1 /*ro*/); - } - - /* if not done yet, - * generate all the namespaces that are in the propdb - */ - if (!propdb_xmlns_done) { - dav_get_propdb_xmlns(propdb, &hdr_ns); - propdb_xmlns_done = 1; - } - - /* - ** Note: the key may be NULL if we have no properties that are in - ** a namespace that matches the requested prop's namespace. - */ - key = dav_gdbm_key(propdb, elem); - - /* fetch IF we have a db and a key. otherwise, value is NULL */ - if (propdb->db != NULL && key.dptr != NULL) { - (void) (*db_hooks->fetch)(propdb->db, key, &value); - } - } - - if (value.dptr == NULL) { - /* not found. add a record to the "bad" propstats */ - - /* make sure we've started our "bad" propstat */ - if (hdr_bad.first == NULL) { - ap_text_append(propdb->p, &hdr_bad, - "<D:propstat>" DEBUG_CR - "<D:prop>" DEBUG_CR); - } - - /* note: key.dptr may be NULL if the propdb doesn't have an - equivalent namespace stored */ - if (key.dptr == NULL) { - const char *s; - - if (elem->ns == AP_XML_NS_NONE) { - /* - * elem has a prefix already (xml...:name) or the elem - * simply has no namespace. - */ - s = apr_psprintf(propdb->p, "<%s/>" DEBUG_CR, elem->name); - } - else { - /* ensure that an xmlns is generated for the - input namespace */ - dav_add_marked_xmlns(propdb, marks_input, elem->ns, - propdb->ns_xlate, "i", &hdr_ns); - s = apr_psprintf(propdb->p, "<i%d:%s/>" DEBUG_CR, - elem->ns, elem->name); - } - ap_text_append(propdb->p, &hdr_bad, s); - } - else { - /* add in the bad prop using our namespace decl */ - dav_append_prop(propdb, key.dptr, DAV_EMPTY_VALUE, &hdr_bad); - } - } - else { - /* found it. put the value into the "good" propstats */ - - have_good = 1; - - dav_append_prop(propdb, key.dptr, value.dptr, &hdr_good); - - (*db_hooks->freedatum)(propdb->db, value); - } - } - - ap_text_append(propdb->p, &hdr_good, - "</D:prop>" DEBUG_CR - "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR - "</D:propstat>" DEBUG_CR); - - /* default to start with the good */ - result.propstats = hdr_good.first; - - /* we may not have any "bad" results */ - if (hdr_bad.first != NULL) { - ap_text_append(propdb->p, &hdr_bad, - "</D:prop>" DEBUG_CR - "<D:status>HTTP/1.1 404 Not Found</D:status>" DEBUG_CR - "</D:propstat>" DEBUG_CR); - - /* if there are no good props, then just return the bad */ - if (!have_good) { - result.propstats = hdr_bad.first; - } - else { - /* hook the bad propstat to the end of the good one */ - hdr_good.last->next = hdr_bad.first; - } - } - - result.xmlns = hdr_ns.first; - return result; -} - -void dav_get_liveprop_supported(dav_propdb *propdb, - const char *ns_uri, - const char *propname, - ap_text_header *body) -{ - int propid; - const dav_hooks_liveprop *hooks; - - propid = dav_find_liveprop_provider(propdb, ns_uri, propname, &hooks); - - if (propid != DAV_PROPID_CORE_UNKNOWN) { - if (hooks == NULL) { - /* this is a "core" property that we define */ - dav_prop_insert unused_inserted; - dav_insert_coreprop(propdb, propid, propname, - DAV_PROP_INSERT_SUPPORTED, body, &unused_inserted); - } - else { - (*hooks->insert_prop)(propdb->resource, propid, - DAV_PROP_INSERT_SUPPORTED, body); - } - } -} - -void dav_prop_validate(dav_prop_ctx *ctx) -{ - dav_propdb *propdb = ctx->propdb; - ap_xml_elem *prop = ctx->prop; - dav_elem_private *priv; - - priv = ctx->prop->private = apr_pcalloc(propdb->p, sizeof(*priv)); - - /* - ** Check to see if this is a live property, and fill the fields - ** in the XML elem, as appropriate. - ** - ** Verify that the property is read/write. If not, then it cannot - ** be SET or DELETEd. - */ - if (priv->propid == 0) { - dav_find_liveprop(propdb, prop); - - /* it's a liveprop if a provider was found */ - /* ### actually the "core" props should really be liveprops, but - ### there is no "provider" for those and the r/w props are - ### treated as dead props anyhow */ - ctx->is_liveprop = priv->provider != NULL; - } - - if (!dav_rw_liveprop(propdb, priv)) { - ctx->err = dav_new_error(propdb->p, HTTP_CONFLICT, - DAV_ERR_PROP_READONLY, - "Property is read-only."); - return; - } - - if (ctx->is_liveprop) { - int defer_to_dead = 0; - - ctx->err = (*priv->provider->patch_validate)(propdb->resource, - prop, ctx->operation, - &ctx->liveprop_ctx, - &defer_to_dead); - if (ctx->err != NULL || !defer_to_dead) - return; - - /* clear is_liveprop -- act as a dead prop now */ - ctx->is_liveprop = 0; - } - - /* - ** The property is supposed to be stored into the dead-property - ** database. Make sure the thing is truly open (and writable). - */ - if (propdb->deferred - && (ctx->err = dav_really_open_db(propdb, 0 /* ro */)) != NULL) { - return; - } - - /* - ** There should be an open, writable database in here! - ** - ** Note: the database would be NULL if it was opened readonly and it - ** did not exist. - */ - if (propdb->db == NULL) { - ctx->err = dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_PROP_NO_DATABASE, - "Attempted to set/remove a property " - "without a valid, open, read/write " - "property database."); - return; - } - - if (ctx->operation == DAV_PROP_OP_SET) { - /* - ** Prep the element => propdb namespace index mapping, inserting - ** namespace URIs into the propdb that don't exist. - */ - dav_prep_ns_map(propdb, 1); - } - else if (ctx->operation == DAV_PROP_OP_DELETE) { - /* - ** There are no checks to perform here. If a property exists, then - ** we will delete it. If it does not exist, then it does not matter - ** (see S12.13.1). - ** - ** Note that if a property does not exist, that does not rule out - ** that a SET will occur during this PROPPATCH (thusly creating it). - */ - } -} - -void dav_prop_exec(dav_prop_ctx *ctx) -{ - dav_propdb *propdb = ctx->propdb; - dav_error *err = NULL; - dav_rollback_item *rollback; - dav_elem_private *priv = ctx->prop->private; - - rollback = apr_pcalloc(propdb->p, sizeof(*rollback)); - ctx->rollback = rollback; - - if (ctx->is_liveprop) { - err = (*priv->provider->patch_exec)(propdb->resource, - ctx->prop, ctx->operation, - ctx->liveprop_ctx, - &ctx->rollback->liveprop); - } - else { - dav_datum key; - - /* we're going to need the key for all operations */ - key = dav_gdbm_key(propdb, ctx->prop); - - /* save the old value so that we can do a rollback. */ - rollback->key = key; - if ((err = (*propdb->db_hooks->fetch)(propdb->db, key, - &rollback->value)) != NULL) - goto error; - - if (ctx->operation == DAV_PROP_OP_SET) { - - dav_datum value; - - /* Note: propdb->ns_map was set in dav_prop_validate() */ - - /* quote all the values in the element */ - ap_xml_quote_elem(propdb->p, ctx->prop); - - /* generate a text blob for the xml:lang plus the contents */ - ap_xml_to_text(propdb->p, ctx->prop, AP_XML_X2T_LANG_INNER, NULL, - propdb->ns_map, - (const char **)&value.dptr, &value.dsize); - - err = (*propdb->db_hooks->store)(propdb->db, key, value); - - /* - ** If an error occurred, then assume that we didn't change the - ** value. Remove the rollback item so that we don't try to set - ** its value during the rollback. - */ - } - else if (ctx->operation == DAV_PROP_OP_DELETE) { - - /* - ** Delete the property. Ignore errors -- the property is there, or - ** we are deleting it for a second time. - */ - /* ### but what about other errors? */ - (void) (*propdb->db_hooks->remove)(propdb->db, key); - } - } - - error: - /* push a more specific error here */ - if (err != NULL) { - /* - ** Use HTTP_INTERNAL_SERVER_ERROR because we shouldn't have seen - ** any errors at this point. - */ - ctx->err = dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_PROP_EXEC, - "Could not execute PROPPATCH.", err); - } -} - -void dav_prop_commit(dav_prop_ctx *ctx) -{ - dav_elem_private *priv = ctx->prop->private; - - /* - ** Note that a commit implies ctx->err is NULL. The caller should assume - ** a status of HTTP_OK for this case. - */ - - if (ctx->is_liveprop) { - (*priv->provider->patch_commit)(ctx->propdb->resource, - ctx->operation, - ctx->liveprop_ctx, - ctx->rollback->liveprop); - } -} - -void dav_prop_rollback(dav_prop_ctx *ctx) -{ - dav_error *err = NULL; - dav_elem_private *priv = ctx->prop->private; - - /* do nothing if there is no rollback information. */ - if (ctx->rollback == NULL) - return; - - /* - ** ### if we have an error, and a rollback occurs, then the namespace - ** ### mods should not happen at all. Basically, the namespace management - ** ### is simply a bitch. - */ - - if (ctx->is_liveprop) { - err = (*priv->provider->patch_rollback)(ctx->propdb->resource, - ctx->operation, - ctx->liveprop_ctx, - ctx->rollback->liveprop); - } - else if (ctx->rollback->value.dptr == NULL) { - /* don't fail if the thing isn't really there */ - /* ### but what about other errors? */ - (void) (*ctx->propdb->db_hooks->remove)(ctx->propdb->db, - ctx->rollback->key); - } - else { - err = (*ctx->propdb->db_hooks->store)(ctx->propdb->db, - ctx->rollback->key, - ctx->rollback->value); - } - - if (err != NULL) { - if (ctx->err == NULL) - ctx->err = err; - else { - dav_error *scan = err; - - /* hook previous errors at the end of the rollback error */ - while (scan->prev != NULL) - scan = scan->prev; - scan->prev = ctx->err; - ctx->err = err; - } - } -} diff --git a/modules/dav/main/providers.c b/modules/dav/main/providers.c deleted file mode 100644 index b0a18cf5f4..0000000000 --- a/modules/dav/main/providers.c +++ /dev/null @@ -1,84 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_pools.h" -#include "apr_hash.h" -#include "mod_dav.h" - - -static apr_hash_t *dav_repos_providers = NULL; - - -static apr_status_t dav_cleanup_providers(void *ctx) -{ - dav_repos_providers = NULL; - return APR_SUCCESS; -} - -DAV_DECLARE(void) dav_register_provider(apr_pool_t *p, const char *name, - const dav_provider *provider) -{ - if (dav_repos_providers == NULL) { - dav_repos_providers = apr_hash_make(p); - apr_pool_cleanup_register(p, NULL, dav_cleanup_providers, apr_pool_cleanup_null); - } - - /* just set it. no biggy if it was there before. */ - apr_hash_set(dav_repos_providers, name, APR_HASH_KEY_STRING, provider); -} - -const dav_provider * dav_lookup_provider(const char *name) -{ - return apr_hash_get(dav_repos_providers, name, APR_HASH_KEY_STRING); -} diff --git a/modules/dav/main/std_liveprop.c b/modules/dav/main/std_liveprop.c deleted file mode 100644 index e10a5b1b82..0000000000 --- a/modules/dav/main/std_liveprop.c +++ /dev/null @@ -1,229 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "httpd.h" -#include "util_xml.h" -#include "apr_strings.h" - -#include "mod_dav.h" - -/* forward-declare */ -static const dav_hooks_liveprop dav_core_hooks_liveprop; - -/* -** The namespace URIs that we use. There will only ever be "DAV:". -*/ -static const char * const dav_core_namespace_uris[] = -{ - "DAV:", - NULL /* sentinel */ -}; - -/* -** Define each of the core properties that this provider will handle. -** Note that all of them are in the DAV: namespace, which has a -** provider-local index of 0. -*/ -static const dav_liveprop_spec dav_core_props[] = -{ - { 0, "comment", DAV_PROPID_comment, 1 }, - { 0, "creator-displayname", DAV_PROPID_creator_displayname, 1 }, - { 0, "displayname", DAV_PROPID_displayname, 1 }, - { 0, "resourcetype", DAV_PROPID_resourcetype, 0 }, - { 0, "source", DAV_PROPID_source, 1 }, - - { 0 } /* sentinel */ -}; - -static const dav_liveprop_group dav_core_liveprop_group = -{ - dav_core_props, - dav_core_namespace_uris, - &dav_core_hooks_liveprop -}; - -static dav_prop_insert dav_core_insert_prop(const dav_resource *resource, - int propid, dav_prop_insert what, - ap_text_header *phdr) -{ - const char *value; - const char *s; - apr_pool_t *p = resource->pool; - const dav_liveprop_spec *info; - int global_ns; - - switch (propid) - { - case DAV_PROPID_resourcetype: - switch (resource->type) { - case DAV_RESOURCE_TYPE_VERSION: - if (resource->baselined) { - value = "<D:baseline/>"; - break; - } - /* fall through */ - case DAV_RESOURCE_TYPE_REGULAR: - case DAV_RESOURCE_TYPE_WORKING: - if (resource->collection) { - value = "<D:collection/>"; - } - else { - /* ### should we denote lock-null resources? */ - - value = ""; /* becomes: <D:resourcetype/> */ - } - break; - case DAV_RESOURCE_TYPE_HISTORY: - value = "<D:version-history/>"; - break; - case DAV_RESOURCE_TYPE_WORKSPACE: - value = "<D:collection/>"; - break; - case DAV_RESOURCE_TYPE_ACTIVITY: - value = "<D:activity/>"; - break; - - default: - /* ### bad juju */ - return DAV_PROP_INSERT_NOTDEF; - } - break; - - case DAV_PROPID_comment: - case DAV_PROPID_creator_displayname: - case DAV_PROPID_displayname: - case DAV_PROPID_source: - default: - /* - ** This property is known, but not defined as a liveprop. However, - ** it may be a dead property. - */ - return DAV_PROP_INSERT_NOTDEF; - } - - /* assert: value != NULL */ - - /* get the information and global NS index for the property */ - global_ns = dav_get_liveprop_info(propid, &dav_core_liveprop_group, &info); - - /* assert: info != NULL && info->name != NULL */ - - if (what == DAV_PROP_INSERT_SUPPORTED) { - s = apr_psprintf(p, - "<D:supported-live-property D:name=\"%s\" " - "D:namespace=\"%s\"/>" DEBUG_CR, - info->name, dav_core_namespace_uris[info->ns]); - } - else if (what == DAV_PROP_INSERT_VALUE && *value != '\0') { - s = apr_psprintf(p, "<lp%d:%s>%s</lp%d:%s>" DEBUG_CR, - global_ns, info->name, value, global_ns, info->name); - } - else { - s = apr_psprintf(p, "<lp%d:%s/>" DEBUG_CR, global_ns, info->name); - } - ap_text_append(p, phdr, s); - - /* we inserted what was asked for */ - return what; -} - -static int dav_core_is_writable(const dav_resource *resource, int propid) -{ - const dav_liveprop_spec *info; - - (void) dav_get_liveprop_info(propid, &dav_core_liveprop_group, &info); - return info->is_writable; -} - -static dav_error * dav_core_patch_validate(const dav_resource *resource, - const ap_xml_elem *elem, - int operation, void **context, - int *defer_to_dead) -{ - /* all of our writable props go in the dead prop database */ - *defer_to_dead = 1; - - return NULL; -} - -static const dav_hooks_liveprop dav_core_hooks_liveprop = { - dav_core_insert_prop, - dav_core_is_writable, - dav_core_namespace_uris, - dav_core_patch_validate, - NULL, /* patch_exec */ - NULL, /* patch_commit */ - NULL, /* patch_rollback */ -}; - -int dav_core_find_liveprop(const dav_resource *resource, - const char *ns_uri, const char *name, - const dav_hooks_liveprop **hooks) -{ - return dav_do_find_liveprop(ns_uri, name, &dav_core_liveprop_group, hooks); -} - -void dav_core_insert_all_liveprops(request_rec *r, - const dav_resource *resource, - dav_prop_insert what, ap_text_header *phdr) -{ - (void) dav_core_insert_prop(resource, DAV_PROPID_resourcetype, - what, phdr); -} - -void dav_core_register_uris(apr_pool_t *p) -{ - /* register the namespace URIs */ - dav_register_liveprop_group(p, &dav_core_liveprop_group); -} diff --git a/modules/dav/main/util.c b/modules/dav/main/util.c deleted file mode 100644 index 5a8d4728e0..0000000000 --- a/modules/dav/main/util.c +++ /dev/null @@ -1,1958 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* -** DAV extension module for Apache 2.0.* -** - various utilities, repository-independent -*/ - -#include "apr_strings.h" -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "mod_dav.h" - -#include "http_request.h" -#include "http_config.h" -#include "http_vhost.h" -#include "http_log.h" -#include "http_protocol.h" - -DAV_DECLARE(dav_error*) dav_new_error(apr_pool_t *p, int status, - int error_id, const char *desc) -{ - int save_errno = errno; - dav_error *err = apr_pcalloc(p, sizeof(*err)); - - /* DBG3("dav_new_error: %d %d %s", status, error_id, desc ? desc : "(no desc)"); */ - - err->status = status; - err->error_id = error_id; - err->desc = desc; - err->save_errno = save_errno; - - return err; -} - -DAV_DECLARE(dav_error*) dav_push_error(apr_pool_t *p, int status, - int error_id, const char *desc, - dav_error *prev) -{ - dav_error *err = apr_pcalloc(p, sizeof(*err)); - - err->status = status; - err->error_id = error_id; - err->desc = desc; - err->prev = prev; - - return err; -} - -DAV_DECLARE(void) dav_check_bufsize(apr_pool_t * p, dav_buffer *pbuf, - apr_size_t extra_needed) -{ - /* grow the buffer if necessary */ - if (pbuf->cur_len + extra_needed > pbuf->alloc_len) { - char *newbuf; - - pbuf->alloc_len += extra_needed + DAV_BUFFER_PAD; - newbuf = apr_palloc(p, pbuf->alloc_len); - memcpy(newbuf, pbuf->buf, pbuf->cur_len); - pbuf->buf = newbuf; - } -} - -DAV_DECLARE(void) dav_set_bufsize(apr_pool_t * p, dav_buffer *pbuf, - apr_size_t size) -{ - /* NOTE: this does not retain prior contents */ - - /* NOTE: this function is used to init the first pointer, too, since - the PAD will be larger than alloc_len (0) for zeroed structures */ - - /* grow if we don't have enough for the requested size plus padding */ - if (size + DAV_BUFFER_PAD > pbuf->alloc_len) { - /* set the new length; min of MINSIZE */ - pbuf->alloc_len = size + DAV_BUFFER_PAD; - if (pbuf->alloc_len < DAV_BUFFER_MINSIZE) - pbuf->alloc_len = DAV_BUFFER_MINSIZE; - - pbuf->buf = apr_palloc(p, pbuf->alloc_len); - } - pbuf->cur_len = size; -} - - -/* initialize a buffer and copy the specified (null-term'd) string into it */ -DAV_DECLARE(void) dav_buffer_init(apr_pool_t *p, dav_buffer *pbuf, - const char *str) -{ - dav_set_bufsize(p, pbuf, strlen(str)); - memcpy(pbuf->buf, str, pbuf->cur_len + 1); -} - -/* append a string to the end of the buffer, adjust length */ -DAV_DECLARE(void) dav_buffer_append(apr_pool_t *p, dav_buffer *pbuf, - const char *str) -{ - size_t len = strlen(str); - - dav_check_bufsize(p, pbuf, len + 1); - memcpy(pbuf->buf + pbuf->cur_len, str, len + 1); - pbuf->cur_len += len; -} - -/* place a string on the end of the buffer, do NOT adjust length */ -DAV_DECLARE(void) dav_buffer_place(apr_pool_t *p, dav_buffer *pbuf, - const char *str) -{ - size_t len = strlen(str); - - dav_check_bufsize(p, pbuf, len + 1); - memcpy(pbuf->buf + pbuf->cur_len, str, len + 1); -} - -/* place some memory on the end of a buffer; do NOT adjust length */ -DAV_DECLARE(void) dav_buffer_place_mem(apr_pool_t *p, dav_buffer *pbuf, - const void *mem, apr_size_t amt, - apr_size_t pad) -{ - dav_check_bufsize(p, pbuf, amt + pad); - memcpy(pbuf->buf + pbuf->cur_len, mem, amt); -} - -/* -** dav_lookup_uri() -** -** Extension for ap_sub_req_lookup_uri() which can't handle absolute -** URIs properly. -** -** If NULL is returned, then an error occurred with parsing the URI or -** the URI does not match the current server. -*/ -dav_lookup_result dav_lookup_uri(const char *uri, request_rec * r, - int must_be_absolute) -{ - dav_lookup_result result = { 0 }; - const char *scheme; - apr_port_t port; - uri_components comp; - char *new_file; - const char *domain; - - /* first thing to do is parse the URI into various components */ - if (ap_parse_uri_components(r->pool, uri, &comp) != HTTP_OK) { - result.err.status = HTTP_BAD_REQUEST; - result.err.desc = "Invalid syntax in Destination URI."; - return result; - } - - /* the URI must be an absoluteURI (WEBDAV S9.3) */ - if (comp.scheme == NULL && must_be_absolute) { - result.err.status = HTTP_BAD_REQUEST; - result.err.desc = "Destination URI must be an absolute URI."; - return result; - } - - /* the URI must not have a query (args) or a fragment */ - if (comp.query != NULL || comp.fragment != NULL) { - result.err.status = HTTP_BAD_REQUEST; - result.err.desc = - "Destination URI contains invalid components " - "(a query or a fragment)."; - return result; - } - - /* If the scheme or port was provided, then make sure that it matches - the scheme/port of this request. If the request must be absolute, - then require the (explicit/implicit) scheme/port be matching. - - ### hmm. if a port wasn't provided (does the parse return port==0?), - ### but we're on a non-standard port, then we won't detect that the - ### URI's port implies the wrong one. - */ - if (comp.scheme != NULL || comp.port != 0 || must_be_absolute) - { - /* ### not sure this works if the current request came in via https: */ - scheme = r->parsed_uri.scheme; - if (scheme == NULL) - scheme = ap_http_method(r); - - /* insert a port if the URI did not contain one */ - if (comp.port == 0) - comp.port = ap_default_port_for_scheme(comp.scheme); - - /* now, verify that the URI uses the same scheme as the current. - request. the port must match our port. - */ - apr_sockaddr_port_get(&port, r->connection->local_addr); - if (strcasecmp(comp.scheme, scheme) != 0 || - comp.port != port) { - result.err.status = HTTP_BAD_GATEWAY; - result.err.desc = apr_psprintf(r->pool, - "Destination URI refers to " - "different scheme or port " - "(%s://hostname:%d)" APR_EOL_STR - "(want: %s://hostname:%d)", - comp.scheme ? comp.scheme : scheme, - comp.port ? comp.port : port, - scheme, port); - return result; - } - } - - /* we have verified the scheme, port, and general structure */ - - /* - ** Hrm. IE5 will pass unqualified hostnames for both the - ** Host: and Destination: headers. This breaks the - ** http_vhost.c::matches_aliases function. - ** - ** For now, qualify unqualified comp.hostnames with - ** r->server->server_hostname. - ** - ** ### this is a big hack. Apache should provide a better way. - ** ### maybe the admin should list the unqualified hosts in a - ** ### <ServerAlias> block? - */ - if (comp.hostname != NULL - && strrchr(comp.hostname, '.') == NULL - && (domain = strchr(r->server->server_hostname, '.')) != NULL) { - comp.hostname = apr_pstrcat(r->pool, comp.hostname, domain, NULL); - } - - /* now, if a hostname was provided, then verify that it represents the - same server as the current connection. note that we just use our - port, since we've verified the URI matches ours */ - if (comp.hostname != NULL && - !ap_matches_request_vhost(r, comp.hostname, port)) { - result.err.status = HTTP_BAD_GATEWAY; - result.err.desc = "Destination URI refers to a different server."; - return result; - } - - /* we have verified that the requested URI denotes the same server as - the current request. Therefore, we can use ap_sub_req_lookup_uri() */ - - /* reconstruct a URI as just the path */ - new_file = ap_unparse_uri_components(r->pool, &comp, UNP_OMITSITEPART); - - /* - * Lookup the URI and return the sub-request. Note that we use the - * same HTTP method on the destination. This allows the destination - * to apply appropriate restrictions (e.g. readonly). - */ - result.rnew = ap_sub_req_method_uri(r->method, new_file, r, NULL); - - return result; -} - -/* --------------------------------------------------------------- -** -** XML UTILITY FUNCTIONS -*/ - -/* validate that the root element uses a given DAV: tagname (TRUE==valid) */ -int dav_validate_root(const ap_xml_doc *doc, const char *tagname) -{ - return doc->root && - doc->root->ns == AP_XML_NS_DAV_ID && - strcmp(doc->root->name, tagname) == 0; -} - -/* find and return the (unique) child with a given DAV: tagname */ -ap_xml_elem *dav_find_child(const ap_xml_elem *elem, const char *tagname) -{ - ap_xml_elem *child = elem->first_child; - - for (; child; child = child->next) - if (child->ns == AP_XML_NS_DAV_ID && !strcmp(child->name, tagname)) - return child; - return NULL; -} - -/* gather up all the CDATA into a single string */ -const char *dav_xml_get_cdata(const ap_xml_elem *elem, apr_pool_t *pool, - int strip_white) -{ - apr_size_t len = 0; - ap_text *scan; - const ap_xml_elem *child; - char *cdata; - char *s; - apr_size_t tlen; - const char *found_text = NULL; /* initialize to avoid gcc warning */ - int found_count = 0; - - for (scan = elem->first_cdata.first; scan != NULL; scan = scan->next) { - found_text = scan->text; - ++found_count; - len += strlen(found_text); - } - - for (child = elem->first_child; child != NULL; child = child->next) { - for (scan = child->following_cdata.first; - scan != NULL; - scan = scan->next) { - found_text = scan->text; - ++found_count; - len += strlen(found_text); - } - } - - /* some fast-path cases: - * 1) zero-length cdata - * 2) a single piece of cdata with no whitespace to strip - */ - if (len == 0) - return ""; - if (found_count == 1) { - if (!strip_white - || (!apr_isspace(*found_text) - && !apr_isspace(found_text[len - 1]))) - return found_text; - } - - cdata = s = apr_palloc(pool, len + 1); - - for (scan = elem->first_cdata.first; scan != NULL; scan = scan->next) { - tlen = strlen(scan->text); - memcpy(s, scan->text, tlen); - s += tlen; - } - - for (child = elem->first_child; child != NULL; child = child->next) { - for (scan = child->following_cdata.first; - scan != NULL; - scan = scan->next) { - tlen = strlen(scan->text); - memcpy(s, scan->text, tlen); - s += tlen; - } - } - - *s = '\0'; - - if (strip_white) { - /* trim leading whitespace */ - while (apr_isspace(*cdata)) /* assume: return false for '\0' */ - ++cdata; - - /* trim trailing whitespace */ - while (len-- > 0 && apr_isspace(cdata[len])) - continue; - cdata[len + 1] = '\0'; - } - - return cdata; -} - -/* --------------------------------------------------------------- -** -** Timeout header processing -** -*/ - -/* dav_get_timeout: If the Timeout: header exists, return a time_t - * when this lock is expected to expire. Otherwise, return - * a time_t of DAV_TIMEOUT_INFINITE. - * - * It's unclear if DAV clients are required to understand - * Seconds-xxx and Infinity time values. We assume that they do. - * In addition, for now, that's all we understand, too. - */ -time_t dav_get_timeout(request_rec *r) -{ - time_t now, expires = DAV_TIMEOUT_INFINITE; - - const char *timeout_const = apr_table_get(r->headers_in, "Timeout"); - const char *timeout = apr_pstrdup(r->pool, timeout_const), *val; - - if (timeout == NULL) - return DAV_TIMEOUT_INFINITE; - - /* Use the first thing we understand, or infinity if - * we don't understand anything. - */ - - while ((val = ap_getword_white(r->pool, &timeout)) && strlen(val)) { - if (!strncmp(val, "Infinite", 8)) { - return DAV_TIMEOUT_INFINITE; - } - - if (!strncmp(val, "Second-", 7)) { - val += 7; - /* ### We need to handle overflow better: - * ### timeout will be <= 2^32 - 1 - */ - expires = atol(val); - now = time(NULL); - return now + expires; - } - } - - return DAV_TIMEOUT_INFINITE; -} - -/* --------------------------------------------------------------- -** -** If Header processing -** -*/ - -/* add_if_resource returns a new if_header, linking it to next_ih. - */ -static dav_if_header *dav_add_if_resource(apr_pool_t *p, dav_if_header *next_ih, - const char *uri, size_t uri_len) -{ - dav_if_header *ih; - - if ((ih = apr_pcalloc(p, sizeof(*ih))) == NULL) - return NULL; - - ih->uri = uri; - ih->uri_len = uri_len; - ih->next = next_ih; - - return ih; -} - -/* add_if_state adds a condition to an if_header. - */ -static dav_error * dav_add_if_state(apr_pool_t *p, dav_if_header *ih, - const char *state_token, - dav_if_state_type t, int condition, - const dav_hooks_locks *locks_hooks) -{ - dav_if_state_list *new_sl; - - new_sl = apr_pcalloc(p, sizeof(*new_sl)); - - new_sl->condition = condition; - new_sl->type = t; - - if (t == dav_if_opaquelock) { - dav_error *err; - - if ((err = (*locks_hooks->parse_locktoken)(p, state_token, - &new_sl->locktoken)) != NULL) { - /* ### maybe add a higher-level description */ - return err; - } - } - else - new_sl->etag = state_token; - - new_sl->next = ih->state; - ih->state = new_sl; - - return NULL; -} - -/* fetch_next_token returns the substring from str+1 - * to the next occurence of char term, or \0, whichever - * occurs first. Leading whitespace is ignored. - */ -static char *dav_fetch_next_token(char **str, char term) -{ - char *sp; - char *token; - - token = *str + 1; - - while (*token && (*token == ' ' || *token == '\t')) - token++; - - if ((sp = strchr(token, term)) == NULL) - return NULL; - - *sp = '\0'; - *str = sp; - return token; -} - -/* dav_process_if_header: - * - * If NULL (no error) is returned, then **if_header points to the - * "If" productions structure (or NULL if "If" is not present). - * - * ### this part is bogus: - * If an error is encountered, the error is logged. Parent should - * return err->status. - */ -static dav_error * dav_process_if_header(request_rec *r, dav_if_header **p_ih) -{ - dav_error *err; - char *str; - char *list; - const char *state_token; - const char *uri = NULL; /* scope of current production; NULL=no-tag */ - size_t uri_len = 0; - dav_if_header *ih = NULL; - uri_components parsed_uri; - const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r); - enum {no_tagged, tagged, unknown} list_type = unknown; - int condition; - - *p_ih = NULL; - - if ((str = apr_pstrdup(r->pool, apr_table_get(r->headers_in, "If"))) == NULL) - return NULL; - - while (*str) { - switch(*str) { - case '<': - /* Tagged-list production - following states apply to this uri */ - if (list_type == no_tagged - || ((uri = dav_fetch_next_token(&str, '>')) == NULL)) { - return dav_new_error(r->pool, HTTP_BAD_REQUEST, - DAV_ERR_IF_TAGGED, - "Invalid If-header: unclosed \"<\" or " - "unexpected tagged-list production."); - } - - /* 2518 specifies this must be an absolute URI; just take the - * relative part for later comparison against r->uri */ - if (ap_parse_uri_components(r->pool, uri, &parsed_uri) != HTTP_OK) { - return dav_new_error(r->pool, HTTP_BAD_REQUEST, - DAV_ERR_IF_TAGGED, - "Invalid URI in tagged If-header."); - } - /* note that parsed_uri.path is allocated; we can trash it */ - - /* clean up the URI a bit */ - ap_getparents(parsed_uri.path); - uri_len = strlen(parsed_uri.path); - if (uri_len > 1 && parsed_uri.path[uri_len - 1] == '/') - parsed_uri.path[--uri_len] = '\0'; - - uri = parsed_uri.path; - list_type = tagged; - break; - - case '(': - /* List production */ - - /* If a uri has not been encountered, this is a No-Tagged-List */ - if (list_type == unknown) - list_type = no_tagged; - - if ((list = dav_fetch_next_token(&str, ')')) == NULL) { - return dav_new_error(r->pool, HTTP_BAD_REQUEST, - DAV_ERR_IF_UNCLOSED_PAREN, - "Invalid If-header: unclosed \"(\"."); - } - - if ((ih = dav_add_if_resource(r->pool, ih, uri, uri_len)) == NULL) { - /* ### dav_add_if_resource() should return an error for us! */ - return dav_new_error(r->pool, HTTP_BAD_REQUEST, - DAV_ERR_IF_PARSE, - "Internal server error parsing \"If:\" " - "header."); - } - - condition = DAV_IF_COND_NORMAL; - - while (*list) { - /* List is the entire production (in a uri scope) */ - - switch (*list) { - case '<': - if ((state_token = dav_fetch_next_token(&list, '>')) == NULL) { - /* ### add a description to this error */ - return dav_new_error(r->pool, HTTP_BAD_REQUEST, - DAV_ERR_IF_PARSE, NULL); - } - - if ((err = dav_add_if_state(r->pool, ih, state_token, dav_if_opaquelock, - condition, locks_hooks)) != NULL) { - /* ### maybe add a higher level description */ - return err; - } - condition = DAV_IF_COND_NORMAL; - break; - - case '[': - if ((state_token = dav_fetch_next_token(&list, ']')) == NULL) { - /* ### add a description to this error */ - return dav_new_error(r->pool, HTTP_BAD_REQUEST, - DAV_ERR_IF_PARSE, NULL); - } - - if ((err = dav_add_if_state(r->pool, ih, state_token, dav_if_etag, - condition, locks_hooks)) != NULL) { - /* ### maybe add a higher level description */ - return err; - } - condition = DAV_IF_COND_NORMAL; - break; - - case 'N': - if (list[1] == 'o' && list[2] == 't') { - if (condition != DAV_IF_COND_NORMAL) { - return dav_new_error(r->pool, HTTP_BAD_REQUEST, - DAV_ERR_IF_MULTIPLE_NOT, - "Invalid \"If:\" header: " - "Multiple \"not\" entries " - "for the same state."); - } - condition = DAV_IF_COND_NOT; - } - list += 2; - break; - - case ' ': - case '\t': - break; - - default: - return dav_new_error(r->pool, HTTP_BAD_REQUEST, - DAV_ERR_IF_UNK_CHAR, - apr_psprintf(r->pool, - "Invalid \"If:\" " - "header: Unexpected " - "character encountered " - "(0x%02x, '%c').", - *list, *list)); - } - - list++; - } - break; - - case ' ': - case '\t': - break; - - default: - return dav_new_error(r->pool, HTTP_BAD_REQUEST, - DAV_ERR_IF_UNK_CHAR, - apr_psprintf(r->pool, - "Invalid \"If:\" header: " - "Unexpected character " - "encountered (0x%02x, '%c').", - *str, *str)); - } - - str++; - } - - *p_ih = ih; - return NULL; -} - -static int dav_find_submitted_locktoken(const dav_if_header *if_header, - const dav_lock *lock_list, - const dav_hooks_locks *locks_hooks) -{ - for (; if_header != NULL; if_header = if_header->next) { - const dav_if_state_list *state_list; - - for (state_list = if_header->state; - state_list != NULL; - state_list = state_list->next) { - - if (state_list->type == dav_if_opaquelock) { - const dav_lock *lock; - - /* given state_list->locktoken, match it */ - - /* - ** The resource will have one or more lock tokens. We only - ** need to match one of them against any token in the - ** If: header. - ** - ** One token case: It is an exclusive or shared lock. Either - ** way, we must find it. - ** - ** N token case: They are shared locks. By policy, we need - ** to match only one. The resource's other - ** tokens may belong to somebody else (so we - ** shouldn't see them in the If: header anyway) - */ - for (lock = lock_list; lock != NULL; lock = lock->next) { - - if (!(*locks_hooks->compare_locktoken)(state_list->locktoken, lock->locktoken)) { - return 1; - } - } - } - } - } - - return 0; -} - -/* dav_validate_resource_state: - * Returns NULL if path/uri meets if-header and lock requirements - */ -static dav_error * dav_validate_resource_state(apr_pool_t *p, - const dav_resource *resource, - dav_lockdb *lockdb, - const dav_if_header *if_header, - int flags, - dav_buffer *pbuf, - request_rec *r) -{ - dav_error *err; - const char *uri; - const char *etag; - const dav_hooks_locks *locks_hooks = (lockdb ? lockdb->hooks : NULL); - const dav_if_header *ifhdr_scan; - dav_if_state_list *state_list; - dav_lock *lock_list; - dav_lock *lock; - int num_matched; - int num_that_apply; - int seen_locktoken; - apr_size_t uri_len; - const char *reason = NULL; - - /* DBG1("validate: <%s>", resource->uri); */ - - /* - ** The resource will have one of three states: - ** - ** 1) No locks. We have no special requirements that the user supply - ** specific locktokens. One of the state lists must match, and - ** we're done. - ** - ** 2) One exclusive lock. The locktoken must appear *anywhere* in the - ** If: header. Of course, asserting the token in a "Not" term will - ** quickly fail that state list :-). If the locktoken appears in - ** one of the state lists *and* one state list matches, then we're - ** done. - ** - ** 3) One or more shared locks. One of the locktokens must appear - ** *anywhere* in the If: header. If one of the locktokens appears, - ** and we match one state list, then we are done. - ** - ** The <seen_locktoken> variable determines whether we have seen one - ** of this resource's locktokens in the If: header. - */ - - /* - ** If this is a new lock request, <flags> will contain the requested - ** lock scope. Three rules apply: - ** - ** 1) Do not require a (shared) locktoken to be seen (when we are - ** applying another shared lock) - ** 2) If the scope is exclusive and we see any locks, fail. - ** 3) If the scope is shared and we see an exclusive lock, fail. - */ - - if (lockdb == NULL) { - /* we're in State 1. no locks. */ - lock_list = NULL; - } - else { - /* - ** ### hrm... we don't need to have these fully - ** ### resolved since we're only looking at the - ** ### locktokens... - ** - ** ### use get_locks w/ calltype=PARTIAL - */ - if ((err = dav_lock_query(lockdb, resource, &lock_list)) != NULL) { - return dav_push_error(p, - HTTP_INTERNAL_SERVER_ERROR, 0, - "The locks could not be queried for " - "verification against a possible \"If:\" " - "header.", - err); - } - - /* lock_list now determines whether we're in State 1, 2, or 3. */ - } - - /* - ** For a new, exclusive lock: if any locks exist, fail. - ** For a new, shared lock: if an exclusive lock exists, fail. - ** else, do not require a token to be seen. - */ - if (flags & DAV_LOCKSCOPE_EXCLUSIVE) { - if (lock_list != NULL) { - return dav_new_error(p, HTTP_LOCKED, 0, - "Existing lock(s) on the requested resource " - "prevent an exclusive lock."); - } - - /* - ** There are no locks, so we can pretend that we've already met - ** any requirement to find the resource's locks in an If: header. - */ - seen_locktoken = 1; - } - else if (flags & DAV_LOCKSCOPE_SHARED) { - /* - ** Strictly speaking, we don't need this loop. Either the first - ** (and only) lock will be EXCLUSIVE, or none of them will be. - */ - for (lock = lock_list; lock != NULL; lock = lock->next) { - if (lock->scope == DAV_LOCKSCOPE_EXCLUSIVE) { - return dav_new_error(p, HTTP_LOCKED, 0, - "The requested resource is already " - "locked exclusively."); - } - } - - /* - ** The locks on the resource (if any) are all shared. Set the - ** <seen_locktoken> flag to indicate that we do not need to find - ** the locks in an If: header. - */ - seen_locktoken = 1; - } - else { - /* - ** For methods other than LOCK: - ** - ** If we have no locks, then <seen_locktoken> can be set to true -- - ** pretending that we've already met the requirement of seeing one - ** of the resource's locks in the If: header. - ** - ** Otherwise, it must be cleared and we'll look for one. - */ - seen_locktoken = (lock_list == NULL); - } - - /* - ** If there is no If: header, then we can shortcut some logic: - ** - ** 1) if we do not need to find a locktoken in the (non-existent) If: - ** header, then we are successful. - ** - ** 2) if we must find a locktoken in the (non-existent) If: header, then - ** we fail. - */ - if (if_header == NULL) { - if (seen_locktoken) - return NULL; - - return dav_new_error(p, HTTP_LOCKED, 0, - "This resource is locked and an \"If:\" header " - "was not supplied to allow access to the " - "resource."); - } - /* the If: header is present */ - - /* - ** If a dummy header is present (because of a Lock-Token: header), then - ** we are required to find that token in this resource's set of locks. - ** If we have no locks, then we immediately fail. - ** - ** This is a 400 (Bad Request) since they should only submit a locktoken - ** that actually exists. - ** - ** Don't issue this response if we're talking about the parent resource. - ** It is okay for that resource to NOT have this locktoken. - ** (in fact, it certainly will not: a dummy_header only occurs for the - ** UNLOCK method, the parent is checked only for locknull resources, - ** and the parent certainly does not have the (locknull's) locktoken) - */ - if (lock_list == NULL && if_header->dummy_header) { - if (flags & DAV_VALIDATE_IS_PARENT) - return NULL; - return dav_new_error(p, HTTP_BAD_REQUEST, 0, - "The locktoken specified in the \"Lock-Token:\" " - "header is invalid because this resource has no " - "outstanding locks."); - } - - /* - ** Prepare the input URI. We want the URI to never have a trailing slash. - ** - ** When URIs are placed into the dav_if_header structure, they are - ** guaranteed to never have a trailing slash. If the URIs are equivalent, - ** then it doesn't matter if they both lack a trailing slash -- they're - ** still equivalent. - ** - ** Note: we could also ensure that a trailing slash is present on both - ** URIs, but the majority of URIs provided to us via a resource walk - ** will not contain that trailing slash. - */ - uri = resource->uri; - uri_len = strlen(uri); - if (uri[uri_len - 1] == '/') { - dav_set_bufsize(p, pbuf, uri_len); - memcpy(pbuf->buf, uri, uri_len); - pbuf->buf[--uri_len] = '\0'; - uri = pbuf->buf; - } - - /* get the resource's etag; we may need it during the checks */ - etag = (*resource->hooks->getetag)(resource); - - /* how many state_lists apply to this URI? */ - num_that_apply = 0; - - /* If there are if-headers, fail if this resource - * does not match at least one state_list. - */ - for (ifhdr_scan = if_header; - ifhdr_scan != NULL; - ifhdr_scan = ifhdr_scan->next) { - - /* DBG2("uri=<%s> if_uri=<%s>", uri, ifhdr_scan->uri ? ifhdr_scan->uri : "(no uri)"); */ - - if (ifhdr_scan->uri != NULL - && (uri_len != ifhdr_scan->uri_len - || memcmp(uri, ifhdr_scan->uri, uri_len) != 0)) { - /* - ** A tagged-list's URI doesn't match this resource's URI. - ** Skip to the next state_list to see if it will match. - */ - continue; - } - - /* this state_list applies to this resource */ - - /* - ** ### only one state_list should ever apply! a no-tag, or a tagged - ** ### where S9.4.2 states only one can match. - ** - ** ### revamp this code to loop thru ifhdr_scan until we find the - ** ### matching state_list. process it. stop. - */ - ++num_that_apply; - - /* To succeed, resource must match *all* of the states - * specified in the state_list. - */ - for (state_list = ifhdr_scan->state; - state_list != NULL; - state_list = state_list->next) { - - switch(state_list->type) { - case dav_if_etag: - { - int mismatch = strcmp(state_list->etag, etag); - - if (state_list->condition == DAV_IF_COND_NORMAL && mismatch) { - /* - ** The specified entity-tag does not match the - ** entity-tag on the resource. This state_list is - ** not going to match. Bust outta here. - */ - reason = - "an entity-tag was specified, but the resource's " - "actual ETag does not match."; - goto state_list_failed; - } - else if (state_list->condition == DAV_IF_COND_NOT - && !mismatch) { - /* - ** The specified entity-tag DOES match the - ** entity-tag on the resource. This state_list is - ** not going to match. Bust outta here. - */ - reason = - "an entity-tag was specified using the \"Not\" form, " - "but the resource's actual ETag matches the provided " - "entity-tag."; - goto state_list_failed; - } - break; - } - - case dav_if_opaquelock: - if (lockdb == NULL) { - if (state_list->condition == DAV_IF_COND_NOT) { - /* the locktoken is definitely not there! (success) */ - continue; - } - - /* condition == DAV_IF_COND_NORMAL */ - - /* - ** If no lockdb is provided, then validation fails for - ** this state_list (NORMAL means we were supposed to - ** find the token, which we obviously cannot do without - ** a lock database). - ** - ** Go and try the next state list. - */ - reason = - "a State-token was supplied, but a lock database " - "is not available for to provide the required lock."; - goto state_list_failed; - } - - /* Resource validation 'fails' if: - * ANY of the lock->locktokens match - * a NOT state_list->locktoken, - * OR - * NONE of the lock->locktokens match - * a NORMAL state_list->locktoken. - */ - num_matched = 0; - for (lock = lock_list; lock != NULL; lock = lock->next) { - - /* - DBG2("compare: rsrc=%s ifhdr=%s", - (*locks_hooks->format_locktoken)(p, lock->locktoken), - (*locks_hooks->format_locktoken)(p, state_list->locktoken)); - */ - - /* nothing to do if the locktokens do not match. */ - if ((*locks_hooks->compare_locktoken)(state_list->locktoken, lock->locktoken)) { - continue; - } - - /* - ** We have now matched up one of the resource's locktokens - ** to a locktoken in a State-token in the If: header. - ** Note this fact, so that we can pass the overall - ** requirement of seeing at least one of the resource's - ** locktokens. - */ - seen_locktoken = 1; - - if (state_list->condition == DAV_IF_COND_NOT) { - /* - ** This state requires that the specified locktoken - ** is NOT present on the resource. But we just found - ** it. There is no way this state-list can now - ** succeed, so go try another one. - */ - reason = - "a State-token was supplied, which used a " - "\"Not\" condition. The State-token was found " - "in the locks on this resource"; - goto state_list_failed; - } - - /* condition == DAV_IF_COND_NORMAL */ - - /* Validate auth_user: If an authenticated user created - ** the lock, only the same user may submit that locktoken - ** to manipulate a resource. - */ - if (lock->auth_user && - (!r->user || - strcmp(lock->auth_user, r->user))) { - const char *errmsg; - - errmsg = apr_pstrcat(p, "User \"", - r->user, - "\" submitted a locktoken created " - "by user \"", - lock->auth_user, "\".", NULL); - return dav_new_error(p, HTTP_UNAUTHORIZED, 0, errmsg); - } - - /* - ** We just matched a specified State-Token to one of the - ** resource's locktokens. - ** - ** Break out of the lock scan -- we only needed to find - ** one match (actually, there shouldn't be any other - ** matches in the lock list). - */ - num_matched = 1; - break; - } - - if (num_matched == 0 - && state_list->condition == DAV_IF_COND_NORMAL) { - /* - ** We had a NORMAL state, meaning that we should have - ** found the State-Token within the locks on this - ** resource. We didn't, so this state_list must fail. - */ - reason = - "a State-token was supplied, but it was not found " - "in the locks on this resource."; - goto state_list_failed; - } - - break; - - } /* switch */ - } /* foreach ( state_list ) */ - - /* - ** We've checked every state in this state_list and none of them - ** have failed. Since all of them succeeded, then we have a matching - ** state list and we may be done. - ** - ** The next requirement is that we have seen one of the resource's - ** locktokens (if any). If we have, then we can just exit. If we - ** haven't, then we need to keep looking. - */ - if (seen_locktoken) { - /* woo hoo! */ - return NULL; - } - - /* - ** Haven't seen one. Let's break out of the search and just look - ** for a matching locktoken. - */ - break; - - /* - ** This label is used when we detect that a state_list is not - ** going to match this resource. We bust out and try the next - ** state_list. - */ - state_list_failed: - ; - - } /* foreach ( ifhdr_scan ) */ - - /* - ** The above loop exits for one of two reasons: - ** 1) a state_list matched and seen_locktoken is false. - ** 2) all if_header structures were scanned, without (1) occurring - */ - - if (ifhdr_scan == NULL) { - /* - ** We finished the loop without finding any matching state lists. - */ - - /* - ** If none of the state_lists apply to this resource, then we - ** may have succeeded. Note that this scenario implies a - ** tagged-list with no matching state_lists. If the If: header - ** was a no-tag-list, then it would have applied to this resource. - ** - ** S9.4.2 states that when no state_lists apply, then the header - ** should be ignored. - ** - ** If we saw one of the resource's locktokens, then we're done. - ** If we did not see a locktoken, then we fail. - */ - if (num_that_apply == 0) { - if (seen_locktoken) - return NULL; - - /* - ** We may have aborted the scan before seeing the locktoken. - ** Rescan the If: header to see if we can find the locktoken - ** somewhere. - ** - ** Note that seen_locktoken == 0 implies lock_list != NULL - ** which implies locks_hooks != NULL. - */ - if (dav_find_submitted_locktoken(if_header, lock_list, - locks_hooks)) { - /* - ** We found a match! We're set... none of the If: header - ** assertions apply (implicit success), and the If: header - ** specified the locktoken somewhere. We're done. - */ - return NULL; - } - - return dav_new_error(p, HTTP_LOCKED, 0 /* error_id */, - "This resource is locked and the \"If:\" " - "header did not specify one of the " - "locktokens for this resource's lock(s)."); - } - /* else: one or more state_lists were applicable, but failed. */ - - /* - ** If the dummy_header did not match, then they specified an - ** incorrect token in the Lock-Token header. Forget whether the - ** If: statement matched or not... we'll tell them about the - ** bad Lock-Token first. That is considered a 400 (Bad Request). - */ - if (if_header->dummy_header) { - return dav_new_error(p, HTTP_BAD_REQUEST, 0, - "The locktoken specified in the " - "\"Lock-Token:\" header did not specify one " - "of this resource's locktoken(s)."); - } - - if (reason == NULL) { - return dav_new_error(p, HTTP_PRECONDITION_FAILED, 0, - "The preconditions specified by the \"If:\" " - "header did not match this resource."); - } - - return dav_new_error(p, HTTP_PRECONDITION_FAILED, 0, - apr_psprintf(p, - "The precondition(s) specified by " - "the \"If:\" header did not match " - "this resource. At least one " - "failure is because: %s", reason)); - } - - /* assert seen_locktoken == 0 */ - - /* - ** ifhdr_scan != NULL implies we found a matching state_list. - ** - ** Since we're still here, it also means that we have not yet found - ** one the resource's locktokens in the If: header. - ** - ** Scan all the if_headers and states looking for one of this - ** resource's locktokens. Note that we need to go back and scan them - ** all -- we may have aborted a scan with a failure before we saw a - ** matching token. - ** - ** Note that seen_locktoken == 0 implies lock_list != NULL which implies - ** locks_hooks != NULL. - */ - if (dav_find_submitted_locktoken(if_header, lock_list, locks_hooks)) { - /* - ** We found a match! We're set... we have a matching state list, - ** and the If: header specified the locktoken somewhere. We're done. - */ - return NULL; - } - - /* - ** We had a matching state list, but the user agent did not specify one - ** of this resource's locktokens. Tell them so. - ** - ** Note that we need to special-case the message on whether a "dummy" - ** header exists. If it exists, yet we didn't see a needed locktoken, - ** then that implies the dummy header (Lock-Token header) did NOT - ** specify one of this resource's locktokens. (this implies something - ** in the real If: header matched) - ** - ** We want to note the 400 (Bad Request) in favor of a 423 (Locked). - */ - if (if_header->dummy_header) { - return dav_new_error(p, HTTP_BAD_REQUEST, 0, - "The locktoken specified in the " - "\"Lock-Token:\" header did not specify one " - "of this resource's locktoken(s)."); - } - - return dav_new_error(p, HTTP_LOCKED, 1 /* error_id */, - "This resource is locked and the \"If:\" header " - "did not specify one of the " - "locktokens for this resource's lock(s)."); -} - -/* dav_validate_walker: Walker callback function to validate resource state */ -static dav_error * dav_validate_walker(dav_walk_resource *wres, int calltype) -{ - dav_walker_ctx *ctx = wres->walk_ctx; - dav_error *err; - - if ((err = dav_validate_resource_state(ctx->w.pool, wres->resource, - ctx->w.lockdb, - ctx->if_header, ctx->flags, - &ctx->work_buf, ctx->r)) == NULL) { - /* There was no error, so just bug out. */ - return NULL; - } - - /* - ** If we have a serious server error, or if the request itself failed, - ** then just return error (not a multistatus). - */ - if (ap_is_HTTP_SERVER_ERROR(err->status) - || (*wres->resource->hooks->is_same_resource)(wres->resource, - ctx->w.root)) { - /* ### maybe push a higher-level description? */ - return err; - } - - /* associate the error with the current URI */ - dav_add_response(wres, err->status, NULL); - - return NULL; -} - -/* -** dav_validate_request: Validate if-headers (and check for locks) on: -** (1) r->filename @ depth; -** (2) Parent of r->filename if check_parent == 1 -** -** The check of parent should be done when it is necessary to verify that -** the parent collection will accept a new member (ie current resource -** state is null). -** -** Return OK on successful validation. -** On error, return appropriate HTTP_* code, and log error. If a multi-stat -** error is necessary, response will point to it, else NULL. -*/ -dav_error * dav_validate_request(request_rec *r, dav_resource *resource, - int depth, dav_locktoken *locktoken, - dav_response **response, int flags, - dav_lockdb *lockdb) -{ - dav_error *err; - int result; - dav_if_header *if_header; - int lock_db_opened_locally = 0; - const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r); - const dav_hooks_repository *repos_hooks = resource->hooks; - dav_buffer work_buf = { 0 }; - dav_response *new_response; - -#if DAV_DEBUG - if (depth && response == NULL) { - /* - ** ### bleck. we can't return errors for other URIs unless we have - ** ### a "response" ptr. - */ - return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "DESIGN ERROR: dav_validate_request called " - "with depth>0, but no response ptr."); - } -#endif - - if (response != NULL) - *response = NULL; - - /* Do the standard checks for conditional requests using - * If-..-Since, If-Match etc */ - if ((result = ap_meets_conditions(r)) != OK) { - /* ### fix this up... how? */ - return dav_new_error(r->pool, result, 0, NULL); - } - - /* always parse (and later process) the If: header */ - if ((err = dav_process_if_header(r, &if_header)) != NULL) { - /* ### maybe add higher-level description */ - return err; - } - - /* If a locktoken was specified, create a dummy if_header with which - * to validate resources. In the interim, figure out why DAV uses - * locktokens in an if-header without a Lock-Token header to refresh - * locks, but a Lock-Token header without an if-header to remove them. - */ - if (locktoken != NULL) { - dav_if_header *ifhdr_new; - - ifhdr_new = apr_pcalloc(r->pool, sizeof(*ifhdr_new)); - ifhdr_new->uri = resource->uri; - ifhdr_new->uri_len = strlen(resource->uri); - ifhdr_new->dummy_header = 1; - - ifhdr_new->state = apr_pcalloc(r->pool, sizeof(*ifhdr_new->state)); - ifhdr_new->state->type = dav_if_opaquelock; - ifhdr_new->state->condition = DAV_IF_COND_NORMAL; - ifhdr_new->state->locktoken = locktoken; - - ifhdr_new->next = if_header; - if_header = ifhdr_new; - } - - /* - ** If necessary, open the lock database (read-only, lazily); - ** the validation process may need to retrieve or update lock info. - ** Otherwise, assume provided lockdb is valid and opened rw. - */ - if (lockdb == NULL) { - if (locks_hooks != NULL) { - if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) { - /* ### maybe insert higher-level comment */ - return err; - } - lock_db_opened_locally = 1; - } - } - - /* (1) Validate the specified resource, at the specified depth */ - if (resource->exists && depth > 0) { - dav_walker_ctx ctx = { { 0 } }; - dav_response *multi_status; - - ctx.w.walk_type = DAV_WALKTYPE_NORMAL; - ctx.w.func = dav_validate_walker; - ctx.w.walk_ctx = &ctx; - ctx.w.pool = r->pool; - ctx.w.root = resource; - - ctx.if_header = if_header; - ctx.r = r; - ctx.flags = flags; - - if (lockdb != NULL) { - ctx.w.lockdb = lockdb; - ctx.w.walk_type |= DAV_WALKTYPE_LOCKNULL; - } - - err = (*repos_hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status); - if (err == NULL) { - *response = multi_status;; - } - /* else: implies a 5xx status code occurred. */ - } - else { - err = dav_validate_resource_state(r->pool, resource, lockdb, - if_header, flags, &work_buf, r); - } - - /* (2) Validate the parent resource if requested */ - if (err == NULL && (flags & DAV_VALIDATE_PARENT)) { - dav_resource *parent_resource; - - err = (*repos_hooks->get_parent_resource)(resource, &parent_resource); - - if (err == NULL && parent_resource == NULL) { - err = dav_new_error(r->pool, HTTP_FORBIDDEN, 0, - "Cannot access parent of repository root."); - } - else if (err == NULL) { - err = dav_validate_resource_state(r->pool, parent_resource, lockdb, - if_header, - flags | DAV_VALIDATE_IS_PARENT, - &work_buf, r); - - /* - ** This error occurred on the parent resource. This implies that - ** we have to create a multistatus response (to report the error - ** against a URI other than the Request-URI). "Convert" this error - ** into a multistatus response. - */ - if (err != NULL) { - new_response = apr_pcalloc(r->pool, sizeof(*new_response)); - - new_response->href = parent_resource->uri; - new_response->status = err->status; - new_response->desc = - "A validation error has occurred on the parent resource, " - "preventing the operation on the resource specified by " - "the Request-URI."; - if (err->desc != NULL) { - new_response->desc = apr_pstrcat(r->pool, - new_response->desc, - " The error was: ", - err->desc, NULL); - } - - /* assert: DAV_VALIDATE_PARENT implies response != NULL */ - new_response->next = *response; - *response = new_response; - - err = NULL; - } - } - } - - if (lock_db_opened_locally) - (*locks_hooks->close_lockdb)(lockdb); - - /* - ** If we don't have a (serious) error, and we have multistatus responses, - ** then we need to construct an "error". This error will be the overall - ** status returned, and the multistatus responses will go into its body. - ** - ** For certain methods, the overall error will be a 424. The default is - ** to construct a standard 207 response. - */ - if (err == NULL && response != NULL && *response != NULL) { - ap_text *propstat = NULL; - - if ((flags & DAV_VALIDATE_USE_424) != 0) { - /* manufacture a 424 error to hold the multistatus response(s) */ - return dav_new_error(r->pool, HTTP_FAILED_DEPENDENCY, 0, - "An error occurred on another resource, " - "preventing the requested operation on " - "this resource."); - } - - /* - ** Whatever caused the error, the Request-URI should have a 424 - ** associated with it since we cannot complete the method. - ** - ** For a LOCK operation, insert an empty DAV:lockdiscovery property. - ** For other methods, return a simple 424. - */ - if ((flags & DAV_VALIDATE_ADD_LD) != 0) { - propstat = apr_pcalloc(r->pool, sizeof(*propstat)); - propstat->text = - "<D:propstat>" DEBUG_CR - "<D:prop><D:lockdiscovery/></D:prop>" DEBUG_CR - "<D:status>HTTP/1.1 424 Failed Dependency</D:status>" DEBUG_CR - "</D:propstat>" DEBUG_CR; - } - - /* create the 424 response */ - new_response = apr_pcalloc(r->pool, sizeof(*new_response)); - new_response->href = resource->uri; - new_response->status = HTTP_FAILED_DEPENDENCY; - new_response->propresult.propstats = propstat; - new_response->desc = - "An error occurred on another resource, preventing the " - "requested operation on this resource."; - - new_response->next = *response; - *response = new_response; - - /* manufacture a 207 error for the multistatus response(s) */ - return dav_new_error(r->pool, HTTP_MULTI_STATUS, 0, - "Error(s) occurred on resources during the " - "validation process."); - } - - return err; -} - -/* dav_get_locktoken_list: - * - * Sets ltl to a locktoken_list of all positive locktokens in header, - * else NULL if no If-header, or no positive locktokens. - */ -dav_error * dav_get_locktoken_list(request_rec *r, dav_locktoken_list **ltl) -{ - dav_error *err; - dav_if_header *if_header; - dav_if_state_list *if_state; - dav_locktoken_list *lock_token = NULL; - - *ltl = NULL; - - if ((err = dav_process_if_header(r, &if_header)) != NULL) { - /* ### add a higher-level description? */ - return err; - } - - while (if_header != NULL) { - if_state = if_header->state; /* Begining of the if_state linked list */ - while (if_state != NULL) { - if (if_state->condition == DAV_IF_COND_NORMAL - && if_state->type == dav_if_opaquelock) { - lock_token = apr_pcalloc(r->pool, sizeof(dav_locktoken_list)); - lock_token->locktoken = if_state->locktoken; - lock_token->next = *ltl; - *ltl = lock_token; - } - if_state = if_state->next; - } - if_header = if_header->next; - } - if (*ltl == NULL) { - /* No nodes added */ - return dav_new_error(r->pool, HTTP_BAD_REQUEST, DAV_ERR_IF_ABSENT, - "No locktokens were specified in the \"If:\" " - "header, so the refresh could not be performed."); - } - - return NULL; -} - -#if 0 /* not needed right now... */ - -static const char *strip_white(const char *s, apr_pool_t *pool) -{ - apr_size_t idx; - - /* trim leading whitespace */ - while (apr_isspace(*s)) /* assume: return false for '\0' */ - ++s; - - /* trim trailing whitespace */ - idx = strlen(s) - 1; - if (apr_isspace(s[idx])) { - char *s2 = apr_pstrdup(pool, s); - - while (apr_isspace(s2[idx]) && idx > 0) - --idx; - s2[idx + 1] = '\0'; - return s2; - } - - return s; -} -#endif - -#define DAV_LABEL_HDR "Label" - -/* dav_add_vary_header - * - * If there were any headers in the request which require a Vary header - * in the response, add it. - */ -void dav_add_vary_header(request_rec *in_req, - request_rec *out_req, - const dav_resource *resource) -{ - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(in_req); - - /* ### this is probably all wrong... I think there is a function in - ### the Apache API to add things to the Vary header. need to check */ - - /* Only versioning headers require a Vary response header, - * so only do this check if there is a versioning provider */ - if (vsn_hooks != NULL) { - const char *target = apr_table_get(in_req->headers_in, DAV_LABEL_HDR); - const char *vary = apr_table_get(out_req->headers_out, "Vary"); - - /* If Target-Selector specified, add it to the Vary header */ - if (target != NULL) { - if (vary == NULL) - vary = DAV_LABEL_HDR; - else - vary = apr_pstrcat(out_req->pool, vary, "," DAV_LABEL_HDR, - NULL); - - apr_table_setn(out_req->headers_out, "Vary", vary); - } - } -} - -/* dav_can_auto_checkout - * - * Determine whether auto-checkout is enabled for a resource. - * r - the request_rec - * resource - the resource - * auto_version - the value of the auto_versionable hook for the resource - * lockdb - pointer to lock database (opened if necessary) - * auto_checkout - set to 1 if auto-checkout enabled - */ -static dav_error * dav_can_auto_checkout( - request_rec *r, - dav_resource *resource, - dav_auto_version auto_version, - dav_lockdb **lockdb, - int *auto_checkout) -{ - dav_error *err; - dav_lock *lock_list; - - *auto_checkout = 0; - - if (auto_version == DAV_AUTO_VERSION_ALWAYS) { - *auto_checkout = 1; - } - else if (auto_version == DAV_AUTO_VERSION_LOCKED) { - if (*lockdb == NULL) { - const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r); - - if (locks_hooks == NULL) { - return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "Auto-checkout is only enabled for locked resources, " - "but there is no lock provider."); - } - - if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, lockdb)) != NULL) { - return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "Cannot open lock database to determine " - "auto-versioning behavior.", - err); - } - } - - if ((err = dav_lock_query(*lockdb, resource, &lock_list)) != NULL) { - return dav_push_error(r->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "The locks could not be queried for " - "determining auto-versioning behavior.", - err); - } - - if (lock_list != NULL) - *auto_checkout = 1; - } - - return NULL; -} - -/* see mod_dav.h for docco */ -dav_error *dav_auto_checkout( - request_rec *r, - dav_resource *resource, - int parent_only, - dav_auto_version_info *av_info) -{ - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); - dav_lockdb *lockdb = NULL; - dav_error *err = NULL; - - /* Initialize results */ - memset(av_info, 0, sizeof(*av_info)); - - /* if no versioning provider, just return */ - if (vsn_hooks == NULL) - return NULL; - - /* check parent resource if requested or if resource must be created */ - if (!resource->exists || parent_only) { - dav_resource *parent; - - if ((err = (*resource->hooks->get_parent_resource)(resource, - &parent)) != NULL) - goto done; - - if (parent == NULL || !parent->exists) { - err = dav_new_error(r->pool, HTTP_CONFLICT, 0, - apr_psprintf(r->pool, - "Missing one or more intermediate " - "collections. Cannot create resource %s.", - ap_escape_html(r->pool, resource->uri))); - goto done; - } - - av_info->parent_resource = parent; - - /* if parent versioned and not checked out, see if it can be */ - if (parent->versioned && !parent->working) { - int checkout_parent; - - if ((err = dav_can_auto_checkout(r, parent, - (*vsn_hooks->auto_versionable)(parent), - &lockdb, &checkout_parent)) - != NULL) { - goto done; - } - - if (!checkout_parent) { - err = dav_new_error(r->pool, HTTP_CONFLICT, 0, - "<DAV:cannot-modify-checked-in-parent>"); - goto done; - } - - /* Try to checkout the parent collection. - * Note that auto-versioning can only be applied to a version selector, - * so no separate working resource will be created. - */ - if ((err = (*vsn_hooks->checkout)(parent, 1 /*auto_checkout*/, - 0, 0, 0, NULL, NULL)) - != NULL) - { - err = dav_push_error(r->pool, HTTP_CONFLICT, 0, - apr_psprintf(r->pool, - "Unable to auto-checkout parent collection. " - "Cannot create resource %s.", - ap_escape_html(r->pool, resource->uri)), - err); - goto done; - } - - /* remember that parent was checked out */ - av_info->parent_checkedout = 1; - } - } - - /* if only checking parent, we're done */ - if (parent_only) - goto done; - - /* if creating a new resource, see if it should be version-controlled */ - if (!resource->exists - && (*vsn_hooks->auto_versionable)(resource) == DAV_AUTO_VERSION_ALWAYS) { - - if ((err = (*vsn_hooks->vsn_control)(resource, NULL)) != NULL) { - err = dav_push_error(r->pool, HTTP_CONFLICT, 0, - apr_psprintf(r->pool, - "Unable to create versioned resource %s.", - ap_escape_html(r->pool, resource->uri)), - err); - goto done; - } - - /* remember that resource was created */ - av_info->resource_versioned = 1; - } - - /* if resource is versioned, make sure it is checked out */ - if (resource->versioned && !resource->working) { - int checkout_resource; - - if ((err = dav_can_auto_checkout(r, resource, - (*vsn_hooks->auto_versionable)(resource), - &lockdb, &checkout_resource)) != NULL) { - goto done; - } - - if (!checkout_resource) { - err = dav_new_error(r->pool, HTTP_CONFLICT, 0, - "<DAV:cannot-modify-version-controlled-content>"); - goto done; - } - - /* Auto-versioning can only be applied to version selectors, so - * no separate working resource will be created. */ - if ((err = (*vsn_hooks->checkout)(resource, 1 /*auto_checkout*/, - 0, 0, 0, NULL, NULL)) - != NULL) - { - err = dav_push_error(r->pool, HTTP_CONFLICT, 0, - apr_psprintf(r->pool, - "Unable to checkout resource %s.", - ap_escape_html(r->pool, resource->uri)), - err); - goto done; - } - - /* remember that resource was checked out */ - av_info->resource_checkedout = 1; - } - -done: - - /* make sure lock database is closed */ - if (lockdb != NULL) - (*lockdb->hooks->close_lockdb)(lockdb); - - /* if an error occurred, undo any auto-versioning operations already done */ - if (err != NULL) { - dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, av_info); - return err; - } - - return NULL; -} - -/* see mod_dav.h for docco */ -dav_error *dav_auto_checkin( - request_rec *r, - dav_resource *resource, - int undo, - int unlock, - dav_auto_version_info *av_info) -{ - const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); - dav_error *err = NULL; - dav_auto_version auto_version; - - /* If no versioning provider, this is a no-op */ - if (vsn_hooks == NULL) - return NULL; - - /* If undoing auto-checkouts, then do uncheckouts */ - if (undo) { - if (resource != NULL) { - if (av_info->resource_checkedout) { - if ((err = (*vsn_hooks->uncheckout)(resource)) != NULL) { - return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(r->pool, - "Unable to undo auto-checkout " - "of resource %s.", - ap_escape_html(r->pool, resource->uri)), - err); - } - } - - if (av_info->resource_versioned) { - dav_response *response; - - /* ### should we do anything with the response? */ - if ((err = (*resource->hooks->remove_resource)(resource, - &response)) != NULL) { - return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(r->pool, - "Unable to undo auto-version-control " - "of resource %s.", - ap_escape_html(r->pool, resource->uri)), - err); - } - } - } - - if (av_info->parent_resource != NULL && av_info->parent_checkedout) { - if ((err = (*vsn_hooks->uncheckout)(av_info->parent_resource)) != NULL) { - return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(r->pool, - "Unable to undo auto-checkout " - "of parent collection %s.", - ap_escape_html(r->pool, av_info->parent_resource->uri)), - err); - } - } - - return NULL; - } - - /* If the resource was checked out, and auto-checkin is enabled, - * then check it in. - */ - if (resource != NULL && resource->working - && (unlock || av_info->resource_checkedout)) { - - auto_version = (*vsn_hooks->auto_versionable)(resource); - - if (auto_version == DAV_AUTO_VERSION_ALWAYS || - (unlock && (auto_version == DAV_AUTO_VERSION_LOCKED))) { - - if ((err = (*vsn_hooks->checkin)(resource, - 0 /*keep_checked_out*/, NULL)) - != NULL) { - return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(r->pool, - "Unable to auto-checkin resource %s.", - ap_escape_html(r->pool, resource->uri)), - err); - } - } - } - - /* If parent resource was checked out, and auto-checkin is enabled, - * then check it in. - */ - if (av_info->parent_resource != NULL && av_info->parent_resource->working - && (unlock || av_info->parent_checkedout)) { - - auto_version = (*vsn_hooks->auto_versionable)(av_info->parent_resource); - - if (auto_version == DAV_AUTO_VERSION_ALWAYS || - (unlock && (auto_version == DAV_AUTO_VERSION_LOCKED))) { - - if ((err = (*vsn_hooks->checkin)(av_info->parent_resource, - 0 /*keep_checked_out*/, NULL)) - != NULL) { - return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(r->pool, - "Unable to auto-checkin parent collection %s.", - ap_escape_html(r->pool, av_info->parent_resource->uri)), - err); - } - } - } - - return NULL; -} diff --git a/modules/dav/main/util_lock.c b/modules/dav/main/util_lock.c deleted file mode 100644 index ff59b58e4a..0000000000 --- a/modules/dav/main/util_lock.c +++ /dev/null @@ -1,826 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* -** DAV repository-independent lock functions -*/ - -#include "apr.h" -#include "apr_strings.h" - -#if APR_HAVE_STDIO_H -#include <stdio.h> /* for sprintf() */ -#endif - -#include "mod_dav.h" -#include "http_log.h" -#include "http_config.h" -#include "http_protocol.h" -#include "http_core.h" - - -/* --------------------------------------------------------------- -** -** Property-related lock functions -** -*/ - -/* -** dav_lock_get_activelock: Returns a <lockdiscovery> containing -** an activelock element for every item in the lock_discovery tree -*/ -const char *dav_lock_get_activelock(request_rec *r, dav_lock *lock, - dav_buffer *pbuf) -{ - dav_lock *lock_scan; - const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r); - int count = 0; - dav_buffer work_buf = { 0 }; - apr_pool_t *p = r->pool; - - /* If no locks or no lock provider, there are no locks */ - if (lock == NULL || hooks == NULL) { - /* - ** Since resourcediscovery is defined with (activelock)*, - ** <D:activelock/> shouldn't be necessary for an empty lock. - */ - return ""; - } - - /* - ** Note: it could be interesting to sum the lengths of the owners - ** and locktokens during this loop. However, the buffer - ** mechanism provides some rough padding so that we don't - ** really need to have an exact size. Further, constructing - ** locktoken strings could be relatively expensive. - */ - for (lock_scan = lock; lock_scan != NULL; lock_scan = lock_scan->next) - count++; - - /* if a buffer was not provided, then use an internal buffer */ - if (pbuf == NULL) - pbuf = &work_buf; - - /* reset the length before we start appending stuff */ - pbuf->cur_len = 0; - - /* prep the buffer with a "good" size */ - dav_check_bufsize(p, pbuf, count * 300); - - for (; lock != NULL; lock = lock->next) { - char tmp[100]; - -#if DAV_DEBUG - if (lock->rectype == DAV_LOCKREC_INDIRECT_PARTIAL) { - /* ### crap. design error */ - dav_buffer_append(p, pbuf, - "DESIGN ERROR: attempted to product an " - "activelock element from a partial, indirect " - "lock record. Creating an XML parsing error " - "to ease detection of this situation: <"); - } -#endif - - dav_buffer_append(p, pbuf, "<D:activelock>" DEBUG_CR "<D:locktype>"); - switch (lock->type) { - case DAV_LOCKTYPE_WRITE: - dav_buffer_append(p, pbuf, "<D:write/>"); - break; - default: - /* ### internal error. log something? */ - break; - } - dav_buffer_append(p, pbuf, "</D:locktype>" DEBUG_CR "<D:lockscope>"); - switch (lock->scope) { - case DAV_LOCKSCOPE_EXCLUSIVE: - dav_buffer_append(p, pbuf, "<D:exclusive/>"); - break; - case DAV_LOCKSCOPE_SHARED: - dav_buffer_append(p, pbuf, "<D:shared/>"); - break; - default: - /* ### internal error. log something? */ - break; - } - dav_buffer_append(p, pbuf, "</D:lockscope>" DEBUG_CR); - sprintf(tmp, "<D:depth>%s</D:depth>" DEBUG_CR, - lock->depth == DAV_INFINITY ? "infinity" : "0"); - dav_buffer_append(p, pbuf, tmp); - - if (lock->owner) { - /* - ** This contains a complete, self-contained <DAV:owner> element, - ** with namespace declarations and xml:lang handling. Just drop - ** it in. - */ - dav_buffer_append(p, pbuf, lock->owner); - } - - dav_buffer_append(p, pbuf, "<D:timeout>"); - if (lock->timeout == DAV_TIMEOUT_INFINITE) { - dav_buffer_append(p, pbuf, "Infinite"); - } - else { - time_t now = time(NULL); - sprintf(tmp, "Second-%lu", (long unsigned int)(lock->timeout - now)); - dav_buffer_append(p, pbuf, tmp); - } - - dav_buffer_append(p, pbuf, - "</D:timeout>" DEBUG_CR - "<D:locktoken>" DEBUG_CR - "<D:href>"); - dav_buffer_append(p, pbuf, - (*hooks->format_locktoken)(p, lock->locktoken)); - dav_buffer_append(p, pbuf, - "</D:href>" DEBUG_CR - "</D:locktoken>" DEBUG_CR - "</D:activelock>" DEBUG_CR); - } - - return pbuf->buf; -} - -/* -** dav_lock_parse_lockinfo: Validates the given xml_doc to contain a -** lockinfo XML element, then populates a dav_lock structure -** with its contents. -*/ -dav_error * dav_lock_parse_lockinfo(request_rec *r, - const dav_resource *resource, - dav_lockdb *lockdb, - const ap_xml_doc *doc, - dav_lock **lock_request) -{ - apr_pool_t *p = r->pool; - dav_error *err; - ap_xml_elem *child; - dav_lock *lock; - - if (!dav_validate_root(doc, "lockinfo")) { - return dav_new_error(p, HTTP_BAD_REQUEST, 0, - "The request body contains an unexpected " - "XML root element."); - } - - if ((err = (*lockdb->hooks->create_lock)(lockdb, resource, - &lock)) != NULL) { - return dav_push_error(p, err->status, 0, - "Could not parse the lockinfo due to an " - "internal problem creating a lock structure.", - err); - } - - lock->depth = dav_get_depth(r, DAV_INFINITY); - if (lock->depth == -1) { - return dav_new_error(p, HTTP_BAD_REQUEST, 0, - "An invalid Depth header was specified."); - } - lock->timeout = dav_get_timeout(r); - - /* Parse elements in the XML body */ - for (child = doc->root->first_child; child; child = child->next) { - if (strcmp(child->name, "locktype") == 0 - && child->first_child - && lock->type == DAV_LOCKTYPE_UNKNOWN) { - if (strcmp(child->first_child->name, "write") == 0) { - lock->type = DAV_LOCKTYPE_WRITE; - continue; - } - } - if (strcmp(child->name, "lockscope") == 0 - && child->first_child - && lock->scope == DAV_LOCKSCOPE_UNKNOWN) { - if (strcmp(child->first_child->name, "exclusive") == 0) - lock->scope = DAV_LOCKSCOPE_EXCLUSIVE; - else if (strcmp(child->first_child->name, "shared") == 0) - lock->scope = DAV_LOCKSCOPE_SHARED; - if (lock->scope != DAV_LOCKSCOPE_UNKNOWN) - continue; - } - - if (strcmp(child->name, "owner") == 0 && lock->owner == NULL) { - const char *text; - - /* quote all the values in the <DAV:owner> element */ - ap_xml_quote_elem(p, child); - - /* - ** Store a full <DAV:owner> element with namespace definitions - ** and an xml:lang definition, if applicable. - */ - ap_xml_to_text(p, child, AP_XML_X2T_FULL_NS_LANG, doc->namespaces, - NULL, &text, NULL); - lock->owner = text; - - continue; - } - - return dav_new_error(p, HTTP_PRECONDITION_FAILED, 0, - apr_psprintf(p, - "The server cannot satisfy the " - "LOCK request due to an unknown XML " - "element (\"%s\") within the " - "DAV:lockinfo element.", - child->name)); - } - - *lock_request = lock; - return NULL; -} - -/* --------------------------------------------------------------- -** -** General lock functions -** -*/ - -/* dav_lock_walker: Walker callback function to record indirect locks */ -static dav_error * dav_lock_walker(dav_walk_resource *wres, int calltype) -{ - dav_walker_ctx *ctx = wres->walk_ctx; - dav_error *err; - - /* We don't want to set indirects on the target */ - if ((*wres->resource->hooks->is_same_resource)(wres->resource, - ctx->w.root)) - return NULL; - - if ((err = (*ctx->w.lockdb->hooks->append_locks)(ctx->w.lockdb, - wres->resource, 1, - ctx->lock)) != NULL) { - if (ap_is_HTTP_SERVER_ERROR(err->status)) { - /* ### add a higher-level description? */ - return err; - } - - /* add to the multistatus response */ - dav_add_response(wres, err->status, NULL); - - /* - ** ### actually, this is probably wrong: we want to fail the whole - ** ### LOCK process if something goes bad. maybe the caller should - ** ### do a dav_unlock() (e.g. a rollback) if any errors occurred. - */ - } - - return NULL; -} - -/* -** dav_add_lock: Add a direct lock for resource, and indirect locks for -** all children, bounded by depth. -** ### assume request only contains one lock -*/ -dav_error * dav_add_lock(request_rec *r, const dav_resource *resource, - dav_lockdb *lockdb, dav_lock *lock, - dav_response **response) -{ - dav_error *err; - int depth = lock->depth; - - *response = NULL; - - /* Requested lock can be: - * Depth: 0 for null resource, existing resource, or existing collection - * Depth: Inf for existing collection - */ - - /* - ** 2518 9.2 says to ignore depth if target is not a collection (it has - ** no internal children); pretend the client gave the correct depth. - */ - if (!resource->collection) { - depth = 0; - } - - /* In all cases, first add direct entry in lockdb */ - - /* - ** Append the new (direct) lock to the resource's existing locks. - ** - ** Note: this also handles locknull resources - */ - if ((err = (*lockdb->hooks->append_locks)(lockdb, resource, 0, - lock)) != NULL) { - /* ### maybe add a higher-level description */ - return err; - } - - if (depth > 0) { - /* Walk existing collection and set indirect locks */ - dav_walker_ctx ctx = { { 0 } }; - dav_response *multi_status; - - ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_AUTH; - ctx.w.func = dav_lock_walker; - ctx.w.walk_ctx = &ctx; - ctx.w.pool = r->pool; - ctx.w.root = resource; - ctx.w.lockdb = lockdb; - - ctx.r = r; - ctx.lock = lock; - - err = (*resource->hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status); - if (err != NULL) { - /* implies a 5xx status code occurred. screw the multistatus */ - return err; - } - - if (multi_status != NULL) { - /* manufacture a 207 error for the multistatus response */ - *response = multi_status; - return dav_new_error(r->pool, HTTP_MULTI_STATUS, 0, - "Error(s) occurred on resources during the " - "addition of a depth lock."); - } - } - - return NULL; -} - -/* -** dav_lock_query: Opens the lock database. Returns a linked list of -** dav_lock structures for all direct locks on path. -*/ -DAV_DECLARE(dav_error*) dav_lock_query(dav_lockdb *lockdb, - const dav_resource *resource, - dav_lock **locks) -{ - /* If no lock database, return empty result */ - if (lockdb == NULL) { - *locks = NULL; - return NULL; - } - - /* ### insert a higher-level description? */ - return (*lockdb->hooks->get_locks)(lockdb, resource, - DAV_GETLOCKS_RESOLVED, - locks); -} - -/* dav_unlock_walker: Walker callback function to remove indirect locks */ -static dav_error * dav_unlock_walker(dav_walk_resource *wres, int calltype) -{ - dav_walker_ctx *ctx = wres->walk_ctx; - dav_error *err; - - /* Before removing the lock, do any auto-checkin required */ - if (wres->resource->working) { - /* ### get rid of this typecast */ - if ((err = dav_auto_checkin(ctx->r, (dav_resource *) wres->resource, - 0 /*undo*/, 1 /*unlock*/, NULL)) - != NULL) { - return err; - } - } - - if ((err = (*ctx->w.lockdb->hooks->remove_lock)(ctx->w.lockdb, - wres->resource, - ctx->locktoken)) != NULL) { - /* ### should we stop or return a multistatus? looks like STOP */ - /* ### add a higher-level description? */ - return err; - } - - return NULL; -} - -/* -** dav_get_direct_resource: -** -** Find a lock on the specified resource, then return the resource the -** lock was applied to (in other words, given a (possibly) indirect lock, -** return the direct lock's corresponding resource). -** -** If the lock is an indirect lock, this usually means traversing up the -** namespace [repository] hierarchy. Note that some lock providers may be -** able to return this information with a traversal. -*/ -static dav_error * dav_get_direct_resource(apr_pool_t *p, - dav_lockdb *lockdb, - const dav_locktoken *locktoken, - const dav_resource *resource, - const dav_resource **direct_resource) -{ - if (lockdb->hooks->lookup_resource != NULL) { - return (*lockdb->hooks->lookup_resource)(lockdb, locktoken, - resource, direct_resource); - } - - *direct_resource = NULL; - - /* Find the top of this lock- - * If r->filename's direct locks include locktoken, use r->filename. - * If r->filename's indirect locks include locktoken, retry r->filename/.. - * Else fail. - */ - while (resource != NULL) { - dav_error *err; - dav_lock *lock; - dav_resource *parent; - - /* - ** Find the lock specified by <locktoken> on <resource>. If it is - ** an indirect lock, then partial results are okay. We're just - ** trying to find the thing and know whether it is a direct or - ** an indirect lock. - */ - if ((err = (*lockdb->hooks->find_lock)(lockdb, resource, locktoken, - 1, &lock)) != NULL) { - /* ### add a higher-level desc? */ - return err; - } - - /* not found! that's an error. */ - if (lock == NULL) { - return dav_new_error(p, HTTP_BAD_REQUEST, 0, - "The specified locktoken does not correspond " - "to an existing lock on this resource."); - } - - if (lock->rectype == DAV_LOCKREC_DIRECT) { - /* we found the direct lock. return this resource. */ - - *direct_resource = resource; - return NULL; - } - - /* the lock was indirect. move up a level in the URL namespace */ - if ((err = (*resource->hooks->get_parent_resource)(resource, - &parent)) != NULL) { - /* ### add a higher-level desc? */ - return err; - } - resource = parent; - } - - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "The lock database is corrupt. A direct lock could " - "not be found for the corresponding indirect lock " - "on this resource."); -} - -/* -** dav_unlock: Removes all direct and indirect locks for r->filename, -** with given locktoken. If locktoken == null_locktoken, all locks -** are removed. If r->filename represents an indirect lock, -** we must unlock the appropriate direct lock. -** Returns OK or appropriate HTTP_* response and logs any errors. -** -** ### We've already crawled the tree to ensure everything was locked -** by us; there should be no need to incorporate a rollback. -*/ -int dav_unlock(request_rec *r, const dav_resource *resource, - const dav_locktoken *locktoken) -{ - int result; - dav_lockdb *lockdb; - const dav_resource *lock_resource = resource; - const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r); - const dav_hooks_repository *repos_hooks = resource->hooks; - dav_walker_ctx ctx = { { 0 } }; - dav_response *multi_status; - dav_error *err; - - /* If no locks provider, then there is nothing to unlock. */ - if (hooks == NULL) { - return OK; - } - - /* 2518 requires the entire lock to be removed if resource/locktoken - * point to an indirect lock. We need resource of the _direct_ - * lock in order to walk down the tree and remove the locks. So, - * If locktoken != null_locktoken, - * Walk up the resource hierarchy until we see a direct lock. - * Or, we could get the direct lock's db/key, pick out the URL - * and do a subrequest. I think walking up is faster and will work - * all the time. - * Else - * Just start removing all locks at and below resource. - */ - - if ((err = (*hooks->open_lockdb)(r, 0, 1, &lockdb)) != NULL) { - /* ### return err! maybe add a higher-level desc */ - /* ### map result to something nice; log an error */ - return HTTP_INTERNAL_SERVER_ERROR; - } - - if (locktoken != NULL - && (err = dav_get_direct_resource(r->pool, lockdb, - locktoken, resource, - &lock_resource)) != NULL) { - /* ### add a higher-level desc? */ - /* ### should return err! */ - return err->status; - } - - /* At this point, lock_resource/locktoken refers to a direct lock (key), ie - * the root of a depth > 0 lock, or locktoken is null. - */ - ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_LOCKNULL; - ctx.w.func = dav_unlock_walker; - ctx.w.walk_ctx = &ctx; - ctx.w.pool = r->pool; - ctx.w.root = lock_resource; - ctx.w.lockdb = lockdb; - - ctx.r = r; - ctx.locktoken = locktoken; - - err = (*repos_hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status); - - /* ### fix this! */ - /* ### do something with multi_status */ - result = err == NULL ? OK : err->status; - - (*hooks->close_lockdb)(lockdb); - - return result; -} - -/* dav_inherit_walker: Walker callback function to inherit locks */ -static dav_error * dav_inherit_walker(dav_walk_resource *wres, int calltype) -{ - dav_walker_ctx *ctx = wres->walk_ctx; - - if (ctx->skip_root - && (*wres->resource->hooks->is_same_resource)(wres->resource, - ctx->w.root)) { - return NULL; - } - - /* ### maybe add a higher-level desc */ - return (*ctx->w.lockdb->hooks->append_locks)(ctx->w.lockdb, - wres->resource, 1, - ctx->lock); -} - -/* -** dav_inherit_locks: When a resource or collection is added to a collection, -** locks on the collection should be inherited to the resource/collection. -** (MOVE, MKCOL, etc) Here we propagate any direct or indirect locks from -** parent of resource to resource and below. -*/ -static dav_error * dav_inherit_locks(request_rec *r, dav_lockdb *lockdb, - const dav_resource *resource, - int use_parent) -{ - dav_error *err; - const dav_resource *which_resource; - dav_lock *locks; - dav_lock *scan; - dav_lock *prev; - dav_walker_ctx ctx = { { 0 } }; - const dav_hooks_repository *repos_hooks = resource->hooks; - dav_response *multi_status; - - if (use_parent) { - dav_resource *parent; - if ((err = (*repos_hooks->get_parent_resource)(resource, - &parent)) != NULL) { - /* ### add a higher-level desc? */ - return err; - } - if (parent == NULL) { - /* ### map result to something nice; log an error */ - return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not fetch parent resource. Unable to " - "inherit locks from the parent and apply " - "them to this resource."); - } - which_resource = parent; - } - else { - which_resource = resource; - } - - if ((err = (*lockdb->hooks->get_locks)(lockdb, which_resource, - DAV_GETLOCKS_PARTIAL, - &locks)) != NULL) { - /* ### maybe add a higher-level desc */ - return err; - } - - if (locks == NULL) { - /* No locks to propagate, just return */ - return NULL; - } - - /* - ** (1) Copy all indirect locks from our parent; - ** (2) Create indirect locks for the depth infinity, direct locks - ** in our parent. - ** - ** The append_locks call in the walker callback will do the indirect - ** conversion, but we need to remove any direct locks that are NOT - ** depth "infinity". - */ - for (scan = locks, prev = NULL; - scan != NULL; - prev = scan, scan = scan->next) { - - if (scan->rectype == DAV_LOCKREC_DIRECT - && scan->depth != DAV_INFINITY) { - - if (prev == NULL) - locks = scan->next; - else - prev->next = scan->next; - } - } - - /* <locks> has all our new locks. Walk down and propagate them. */ - - ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_LOCKNULL; - ctx.w.func = dav_inherit_walker; - ctx.w.walk_ctx = &ctx; - ctx.w.pool = r->pool; - ctx.w.root = resource; - ctx.w.lockdb = lockdb; - - ctx.r = r; - ctx.lock = locks; - ctx.skip_root = !use_parent; - - /* ### do something with multi_status */ - return (*repos_hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status); -} - -/* --------------------------------------------------------------- -** -** Functions dealing with lock-null resources -** -*/ - -/* -** dav_get_resource_state: Returns the state of the resource -** r->filename: DAV_RESOURCE_NULL, DAV_RESOURCE_LOCK_NULL, -** or DAV_RESOURCE_EXIST. -** -** Returns DAV_RESOURCE_ERROR if an error occurs. -*/ -int dav_get_resource_state(request_rec *r, const dav_resource *resource) -{ - const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r); - - if (resource->exists) - return DAV_RESOURCE_EXISTS; - - if (hooks != NULL) { - dav_error *err; - dav_lockdb *lockdb; - int locks_present; - - /* - ** A locknull resource has the form: - ** - ** known-dir "/" locknull-file - ** - ** It would be nice to look into <resource> to verify this form, - ** but it does not have enough information for us. Instead, we - ** can look at the path_info. If the form does not match, then - ** there is no way we could have a locknull resource -- it must - ** be a plain, null resource. - ** - ** Apache sets r->filename to known-dir/unknown-file and r->path_info - ** to "" for the "proper" case. If anything is in path_info, then - ** it can't be a locknull resource. - ** - ** ### I bet this path_info hack doesn't work for repositories. - ** ### Need input from repository implementors! What kind of - ** ### restructure do we need? New provider APIs? - */ - if (r->path_info != NULL && *r->path_info != '\0') { - return DAV_RESOURCE_NULL; - } - - if ((err = (*hooks->open_lockdb)(r, 1, 1, &lockdb)) == NULL) { - /* note that we might see some expired locks... *shrug* */ - err = (*hooks->has_locks)(lockdb, resource, &locks_present); - (*hooks->close_lockdb)(lockdb); - } - - if (err != NULL) { - /* ### don't log an error. return err. add higher-level desc. */ - - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "Failed to query lock-null status for %s", - r->filename); - - return DAV_RESOURCE_ERROR; - } - - if (locks_present) - return DAV_RESOURCE_LOCK_NULL; - } - - return DAV_RESOURCE_NULL; -} - -dav_error * dav_notify_created(request_rec *r, - dav_lockdb *lockdb, - const dav_resource *resource, - int resource_state, - int depth) -{ - dav_error *err; - - if (resource_state == DAV_RESOURCE_LOCK_NULL) { - - /* - ** The resource is no longer a locknull resource. This will remove - ** the special marker. - ** - ** Note that a locknull resource has already inherited all of the - ** locks from the parent. We do not need to call dav_inherit_locks. - ** - ** NOTE: some lock providers record locks for locknull resources using - ** a different key than for regular resources. this will shift - ** the lock information between the two key types. - */ - (void)(*lockdb->hooks->remove_locknull_state)(lockdb, resource); - - /* - ** There are resources under this one, which are new. We must - ** propagate the locks down to the new resources. - */ - if (depth > 0 && - (err = dav_inherit_locks(r, lockdb, resource, 0)) != NULL) { - /* ### add a higher level desc? */ - return err; - } - } - else if (resource_state == DAV_RESOURCE_NULL) { - - /* ### should pass depth to dav_inherit_locks so that it can - ** ### optimize for the depth==0 case. - */ - - /* this resource should inherit locks from its parent */ - if ((err = dav_inherit_locks(r, lockdb, resource, 1)) != NULL) { - - err = dav_push_error(r->pool, err->status, 0, - "The resource was created successfully, but " - "there was a problem inheriting locks from " - "the parent resource.", - err); - return err; - } - } - /* else the resource already exists and its locks are correct. */ - - return NULL; -} diff --git a/modules/echo/.cvsignore b/modules/echo/.cvsignore deleted file mode 100644 index 65f0cc30cf..0000000000 --- a/modules/echo/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -.deps -.libs -*.la -modules.mk -Makefile -*.lo -*.slo -*.so -Debug -Release diff --git a/modules/echo/.indent.pro b/modules/echo/.indent.pro deleted file mode 100644 index a9fbe9f9a1..0000000000 --- a/modules/echo/.indent.pro +++ /dev/null @@ -1,54 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 --TBUFF --TFILE --TTRANS --TUINT4 --T_trans --Tallow_options_t --Tapache_sfio --Tarray_header --Tbool_int --Tbuf_area --Tbuff_struct --Tbuffy --Tcmd_how --Tcmd_parms --Tcommand_rec --Tcommand_struct --Tconn_rec --Tcore_dir_config --Tcore_server_config --Tdir_maker_func --Tevent --Tglobals_s --Thandler_func --Thandler_rec --Tjoblist_s --Tlisten_rec --Tmerger_func --Tmode_t --Tmodule --Tmodule_struct --Tmutex --Tn_long --Tother_child_rec --Toverrides_t --Tparent_score --Tpid_t --Tpiped_log --Tpool --Trequest_rec --Trequire_line --Trlim_t --Tscoreboard --Tsemaphore --Tserver_addr_rec --Tserver_rec --Tserver_rec_chain --Tshort_score --Ttable --Ttable_entry --Tthread --Tu_wide_int --Tvtime_t --Twide_int diff --git a/modules/echo/Makefile.in b/modules/echo/Makefile.in deleted file mode 100644 index 167b343d0d..0000000000 --- a/modules/echo/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ - -include $(top_srcdir)/build/special.mk - diff --git a/modules/echo/config.m4 b/modules/echo/config.m4 deleted file mode 100644 index 504a89c44a..0000000000 --- a/modules/echo/config.m4 +++ /dev/null @@ -1,11 +0,0 @@ -dnl modules enabled in this directory by default - -dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]]) - -APACHE_MODPATH_INIT(echo) - -APACHE_MODULE(echo, ECHO server, , , no) - -APR_ADDTO(LTFLAGS,-export-dynamic) - -APACHE_MODPATH_FINISH diff --git a/modules/echo/mod_echo.c b/modules/echo/mod_echo.c deleted file mode 100644 index f182123213..0000000000 --- a/modules/echo/mod_echo.c +++ /dev/null @@ -1,136 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "ap_config.h" -#include "ap_mmn.h" -#include "httpd.h" -#include "http_config.h" -#include "http_connection.h" - -AP_DECLARE_DATA module echo_module; - -typedef struct { - int bEnabled; -} EchoConfig; - -static void *create_echo_server_config(apr_pool_t *p, server_rec *s) -{ - EchoConfig *pConfig = apr_pcalloc(p, sizeof *pConfig); - - pConfig->bEnabled = 0; - - return pConfig; -} - -static const char *echo_on(cmd_parms *cmd, void *dummy, int arg) -{ - EchoConfig *pConfig = ap_get_module_config(cmd->server->module_config, - &echo_module); - pConfig->bEnabled = arg; - - return NULL; -} - -static int process_echo_connection(conn_rec *c) -{ - char buf[1024]; - EchoConfig *pConfig = ap_get_module_config(c->base_server->module_config, - &echo_module); - - if (!pConfig->bEnabled) { - return DECLINED; - } - - for ( ; ; ) { - apr_ssize_t r, w; - r = sizeof(buf); - apr_recv(c->client_socket, buf, &r); - if (r <= 0) { - break; - } - w = r; - apr_send(c->client_socket, buf, &w); - if (w != r) { - break; - } - } - return OK; -} - -static const command_rec echo_cmds[] = -{ - AP_INIT_FLAG("ProtocolEcho", echo_on, NULL, RSRC_CONF, - "Run an echo server on this host"), - { NULL } -}; - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_process_connection(process_echo_connection, NULL, NULL, - APR_HOOK_MIDDLE); -} - -AP_DECLARE_DATA module echo_module = { - STANDARD20_MODULE_STUFF, - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - create_echo_server_config, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - echo_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/experimental/.cvsignore b/modules/experimental/.cvsignore deleted file mode 100644 index 15cf55fd3f..0000000000 --- a/modules/experimental/.cvsignore +++ /dev/null @@ -1,11 +0,0 @@ -.deps -.libs -*.la -modules.mk -Makefile -*.lo -*.slo -*.so -Debug -Release -*.plg diff --git a/modules/experimental/.indent.pro b/modules/experimental/.indent.pro deleted file mode 100644 index a9fbe9f9a1..0000000000 --- a/modules/experimental/.indent.pro +++ /dev/null @@ -1,54 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 --TBUFF --TFILE --TTRANS --TUINT4 --T_trans --Tallow_options_t --Tapache_sfio --Tarray_header --Tbool_int --Tbuf_area --Tbuff_struct --Tbuffy --Tcmd_how --Tcmd_parms --Tcommand_rec --Tcommand_struct --Tconn_rec --Tcore_dir_config --Tcore_server_config --Tdir_maker_func --Tevent --Tglobals_s --Thandler_func --Thandler_rec --Tjoblist_s --Tlisten_rec --Tmerger_func --Tmode_t --Tmodule --Tmodule_struct --Tmutex --Tn_long --Tother_child_rec --Toverrides_t --Tparent_score --Tpid_t --Tpiped_log --Tpool --Trequest_rec --Trequire_line --Trlim_t --Tscoreboard --Tsemaphore --Tserver_addr_rec --Tserver_rec --Tserver_rec_chain --Tshort_score --Ttable --Ttable_entry --Tthread --Tu_wide_int --Tvtime_t --Twide_int diff --git a/modules/experimental/Makefile.in b/modules/experimental/Makefile.in deleted file mode 100644 index 7c5c149d85..0000000000 --- a/modules/experimental/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ -# a modules Makefile has no explicit targets -- they will be defined by -# whatever modules are enabled. just grab special.mk to deal with this. -include $(top_srcdir)/build/special.mk diff --git a/modules/experimental/README b/modules/experimental/README deleted file mode 100644 index 1d80fa5855..0000000000 --- a/modules/experimental/README +++ /dev/null @@ -1,41 +0,0 @@ -README for Apache 2.0 Example Module -[April, 1997, updated May 2000] - -The files in the src/modules/example directory under the Apache -distribution directory tree are provided as an example to those that -wish to write modules that use the Apache API. - -The main file is mod_example.c, which illustrates all the different -callback mechanisms and call syntaces. By no means does an add-on -module need to include routines for all of the callbacks - quite the -contrary! - -The example module is an actual working module. If you link it into -your server, enable the "example-handler" handler for a location, and then -browse to that location, you will see a display of some of the tracing -the example module did as the various callbacks were made. - -To include the example module in your server run `./configure ---enable-example` in the src directory before running `make`. - -To add another module of your own: - - A. mkdir src/modules/mymodule - B. cp src/modules/example/* src/modules/mymodule - C. Modify the files in the new directory - D. Build the server as above, with appropriate changes. - -To activate the example module, include a block similar to the -following in your httpd.conf file: - - <Location /example-info> - SetHandler example-handler - </Location> - -As an alternative, you can put the following into a .htaccess file and -then request the file "test.example" from that location: - - AddHandler example-handler .example - -After reloading/restarting your server, you should be able to browse -to this location and see the brief display mentioned earlier. diff --git a/modules/experimental/config.m4 b/modules/experimental/config.m4 deleted file mode 100644 index 975e9d8329..0000000000 --- a/modules/experimental/config.m4 +++ /dev/null @@ -1,14 +0,0 @@ - -APACHE_MODPATH_INIT(experimental) - -APACHE_MODULE(charset_lite, character set translation, , , no) -APACHE_MODULE(cache, dynamic file caching, , , no) -APACHE_MODULE(disk_cache, disk caching module, , , no) -APACHE_MODULE(ext_filter, external filter module, , , no) -APACHE_MODULE(case_filter, example uppercase conversion filter, , , no) -APACHE_MODULE(generic_hook_export, example hook exporter, , , no) -APACHE_MODULE(generic_hook_import, example hook importer, , , no) -APACHE_MODULE(optional_fn_import, example optional function importer, , , no) -APACHE_MODULE(optional_fn_export, example optional function exporter, , , no) - -APACHE_MODPATH_FINISH diff --git a/modules/experimental/mod_cache.c b/modules/experimental/mod_cache.c deleted file mode 100644 index 49871abe58..0000000000 --- a/modules/experimental/mod_cache.c +++ /dev/null @@ -1,124 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr_strings.h" -#include "ap_config.h" -#include "util_filter.h" -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_log.h" -#include "http_main.h" -#include "util_script.h" -#include "http_core.h" -#include "mod_cache.h" -#include "apr_hooks.h" - -module AP_DECLARE_DATA cache_module; - -APR_HOOK_STRUCT( - APR_HOOK_LINK(serve_cache) - APR_HOOK_LINK(store_cache) -) - -AP_IMPLEMENT_HOOK_RUN_FIRST(int,serve_cache,(request_rec *r),(r),DECLINED) -AP_IMPLEMENT_HOOK_RUN_FIRST(int,store_cache,(request_rec *r, apr_bucket_brigade *bb, void **cf), - (r, bb, cf),DECLINED) - -static int cache_handler(request_rec *r) -{ - /* I am sure there is common error checking that belongs in this function, - * but I'm not sure what it is. - */ - return ap_run_serve_cache(r); -} - -typedef struct cache_struct { - void *cf; -} cache_struct; - -static int cache_filter(ap_filter_t *f, apr_bucket_brigade *bb) -{ - cache_struct *ctx = f->ctx; - - if (ctx == NULL) { - f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx)); - } - - ap_run_store_cache(f->r, bb, &ctx->cf); - ap_pass_brigade(f->next, bb); - return APR_SUCCESS; -} - -static void cache_register_hook(apr_pool_t *p) -{ - ap_hook_handler(cache_handler, NULL, NULL, APR_HOOK_MIDDLE); - ap_register_output_filter("CACHE", cache_filter, AP_FTYPE_HTTP_HEADER); -} - -module AP_DECLARE_DATA cache_module = { - STANDARD20_MODULE_STUFF, - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - NULL, /* command apr_table_t */ - cache_register_hook /* register hooks */ -}; diff --git a/modules/experimental/mod_cache.h b/modules/experimental/mod_cache.h deleted file mode 100644 index 7f2cf9b0c1..0000000000 --- a/modules/experimental/mod_cache.h +++ /dev/null @@ -1,65 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr_buckets.h" -#include "apr_hooks.h" -#include "httpd.h" - -AP_DECLARE_HOOK(int,serve_cache,(request_rec *r)); -AP_DECLARE_HOOK(int,store_cache,(request_rec *r, apr_bucket_brigade *bb, void **cf)); - diff --git a/modules/experimental/mod_case_filter.c b/modules/experimental/mod_case_filter.c deleted file mode 100644 index bb59985ae4..0000000000 --- a/modules/experimental/mod_case_filter.c +++ /dev/null @@ -1,113 +0,0 @@ -// Ben messing around... - -#include "httpd.h" -#include "http_config.h" -#include "apr_general.h" -#include "util_filter.h" -#include "apr_buckets.h" -#include "http_request.h" - -static const char s_szCaseFilterName[]="CaseFilter"; -module case_filter_module; - -typedef struct - { - int bEnabled; - } CaseFilterConfig; - -static void *CaseFilterCreateServerConfig(apr_pool_t *p,server_rec *s) - { - CaseFilterConfig *pConfig=apr_pcalloc(p,sizeof *pConfig); - - pConfig->bEnabled=0; - - return pConfig; - } - -static void CaseFilterInsertFilter(request_rec *r) - { - CaseFilterConfig *pConfig=ap_get_module_config(r->server->module_config, - &case_filter_module); - - if(!pConfig->bEnabled) - return; - - ap_add_output_filter(s_szCaseFilterName,NULL,r,r->connection); - } - -static apr_status_t CaseFilterOutFilter(ap_filter_t *f, - apr_bucket_brigade *pbbIn) - { - apr_bucket *pbktIn; - apr_bucket_brigade *pbbOut; - - // XXX: is this the most appropriate pool? - pbbOut=apr_brigade_create(f->r->pool); - APR_BRIGADE_FOREACH(pbktIn,pbbIn) - { - const char *data; - apr_size_t len; - char *buf; - apr_size_t n; - apr_bucket *pbktOut; - - if(APR_BUCKET_IS_EOS(pbktIn)) - { - // XXX: why can't I reuse pbktIn??? - apr_bucket *pbktEOS=apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(pbbOut,pbktEOS); - break; - } - - // read - apr_bucket_read(pbktIn,&data,&len,APR_BLOCK_READ); - - // write - buf=apr_palloc(f->r->pool,len); - for(n=0 ; n < len ; ++n) - buf[n]=toupper(data[n]); - - // XXX: should we use a heap bucket instead? Or a transient (in - // which case we need a separate brigade for each bucket)? - pbktOut=apr_bucket_pool_create(buf,len,f->r->pool); - APR_BRIGADE_INSERT_TAIL(pbbOut,pbktOut); - } - - // XXX: is there any advantage to passing a brigade for each bucket? - return ap_pass_brigade(f->next,pbbOut); - } - -static const char *CaseFilterEnable(cmd_parms *cmd, void *dummy, int arg) - { - CaseFilterConfig *pConfig=ap_get_module_config(cmd->server->module_config, - &case_filter_module); - pConfig->bEnabled=arg; - - return NULL; - } - -static const command_rec CaseFilterCmds[] = - { - AP_INIT_FLAG("CaseFilter", CaseFilterEnable, NULL, RSRC_CONF, - "Run a case filter on this host"), - { NULL } - }; - -static void CaseFilterRegisterHooks(void) - { - ap_hook_insert_filter(CaseFilterInsertFilter,NULL,NULL,APR_HOOK_MIDDLE); - ap_register_output_filter(s_szCaseFilterName,CaseFilterOutFilter, - AP_FTYPE_CONTENT); - } - -module case_filter_module = -{ - STANDARD20_MODULE_STUFF, - NULL, - NULL, - CaseFilterCreateServerConfig, - NULL, - CaseFilterCmds, - NULL, - CaseFilterRegisterHooks -}; diff --git a/modules/experimental/mod_charset_lite.c b/modules/experimental/mod_charset_lite.c deleted file mode 100644 index 79830eed08..0000000000 --- a/modules/experimental/mod_charset_lite.c +++ /dev/null @@ -1,1142 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * simple hokey charset recoding configuration module - * - * See mod_ebcdic and mod_charset for more thought-out examples. This - * one is just so Jeff can learn how a module works and experiment with - * basic character set recoding configuration. - * - * !!!This is an extremely cheap ripoff of mod_charset.c from Russian Apache!!! - */ - -#include "httpd.h" -#include "http_config.h" -#define CORE_PRIVATE -#include "http_core.h" -#include "http_log.h" -#include "http_main.h" -#include "http_protocol.h" -#include "http_request.h" -#include "util_charset.h" -#include "apr_buckets.h" -#include "util_filter.h" -#include "apr_strings.h" -#include "apr_lib.h" -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#ifndef APACHE_XLATE -#error mod_charset_lite cannot work without APACHE_XLATE enabled -#endif - -#define OUTPUT_XLATE_BUF_SIZE (16*1024) /* size of translation buffer used on output */ -#define INPUT_XLATE_BUF_SIZE (8*1024) /* size of translation buffer used on input */ - -/* XXX this works around an issue with the heap bucket: apr_bucket_heap_create will - * copy only the first 4096 bytes - */ -#undef INPUT_XLATE_BUF_SIZE /* XXX */ -#define INPUT_XLATE_BUF_SIZE (4096) /* XXX must match DEFAULT_BUCKET_SIZE */ - -#define XLATE_MIN_BUFF_LEFT 128 /* flush once there is no more than this much - * space is left in the translation buffer - */ - -#define FATTEST_CHAR 8 /* we don't handle chars wider than this that straddle - * two buckets - */ - -/* extended error status codes; this is used in addition to an apr_status_t to - * track errors in the translation filter - */ -typedef enum { - EES_INIT = 0, /* no error info yet; value must be 0 for easy init */ - EES_LIMIT, /* built-in restriction encountered */ - EES_INCOMPLETE_CHAR, /* incomplete multi-byte char at end of content */ - EES_BUCKET_READ, - EES_DOWNSTREAM, /* something bad happened in a filter below xlate */ - EES_BAD_INPUT /* input data invalid */ -} ees_t; - -/* registered name of the output translation filter */ -#define XLATEOUT_FILTER_NAME "XLATEOUT" -/* registered name of input translation filter */ -#define XLATEIN_FILTER_NAME "XLATEIN" - -typedef struct charset_dir_t { - /** debug level; -1 means uninitialized, 0 means no debug */ - int debug; - const char *charset_source; /* source encoding */ - const char *charset_default; /* how to ship on wire */ - /** module does ap_add_*_filter()? */ - enum {IA_INIT, IA_IMPADD, IA_NOIMPADD} implicit_add; -} charset_dir_t; - -/* charset_filter_ctx_t is created for each filter instance; because the same - * filter code is used for translating in both directions, we need this context - * data to tell the filter which translation handle to use; it also can hold a - * character which was split between buckets - */ -typedef struct charset_filter_ctx_t { - apr_xlate_t *xlate; - charset_dir_t *dc; - ees_t ees; /* extended error status */ - apr_size_t saved; - char buf[FATTEST_CHAR]; /* we want to be able to build a complete char here */ - int ran; /* has filter instance run before? */ - int noop; /* should we pass brigades through unchanged? */ - char *tmp; /* buffer for input filtering */ - apr_bucket_brigade *bb; /* input buckets we couldn't finish translating */ -} charset_filter_ctx_t; - -/* charset_req_t is available via r->request_config if any translation is - * being performed - */ -typedef struct charset_req_t { - charset_dir_t *dc; - charset_filter_ctx_t *output_ctx, *input_ctx; -} charset_req_t; - -/* debug level definitions */ -#define DBGLVL_GORY 9 /* gory details */ -#define DBGLVL_FLOW 4 /* enough messages to see what happens on - * each request */ -#define DBGLVL_PMC 2 /* messages about possible misconfiguration */ - -module charset_lite_module; - -static void *create_charset_dir_conf(apr_pool_t *p,char *dummy) -{ - charset_dir_t *dc = (charset_dir_t *)apr_pcalloc(p,sizeof(charset_dir_t)); - - dc->debug = -1; - return dc; -} - -static void *merge_charset_dir_conf(apr_pool_t *p, void *basev, void *overridesv) -{ - charset_dir_t *a = (charset_dir_t *)apr_pcalloc (p, sizeof(charset_dir_t)); - charset_dir_t *base = (charset_dir_t *)basev, - *over = (charset_dir_t *)overridesv; - - /* If it is defined in the current container, use it. Otherwise, use the one - * from the enclosing container. - */ - - a->debug = - over->debug != -1 ? over->debug : base->debug; - a->charset_default = - over->charset_default ? over->charset_default : base->charset_default; - a->charset_source = - over->charset_source ? over->charset_source : base->charset_source; - a->implicit_add = - over->implicit_add != IA_INIT ? over->implicit_add : base->implicit_add; - return a; -} - -/* CharsetSourceEnc charset - */ -static const char *add_charset_source(cmd_parms *cmd, void *in_dc, - const char *name) -{ - charset_dir_t *dc = in_dc; - - dc->charset_source = name; - return NULL; -} - -/* CharsetDefault charset - */ -static const char *add_charset_default(cmd_parms *cmd, void *in_dc, - const char *name) -{ - charset_dir_t *dc = in_dc; - - dc->charset_default = name; - return NULL; -} - -/* CharsetOptions optionflag... - */ -static const char *add_charset_options(cmd_parms *cmd, void *in_dc, - const char *flag) -{ - charset_dir_t *dc = in_dc; - - if (!strcasecmp(flag, "ImplicitAdd")) { - dc->implicit_add = IA_IMPADD; - } - else if (!strcasecmp(flag, "NoImplicitAdd")) { - dc->implicit_add = IA_NOIMPADD; - } - else if (!strncasecmp(flag, "DebugLevel=", 11)) { - dc->debug = atoi(flag + 11); - } - else { - return apr_pstrcat(cmd->temp_pool, - "Invalid CharsetOptions option: ", - flag, - NULL); - } - - return NULL; -} - -/* find_code_page() is a fixup hook that decides if translation should be - * enabled; if so, it sets up request data for use by the filter registration - * hook so that it knows what to do - */ -static int find_code_page(request_rec *r) -{ - charset_dir_t *dc = ap_get_module_config(r->per_dir_config, - &charset_lite_module); - charset_req_t *reqinfo; - charset_filter_ctx_t *input_ctx, *output_ctx; - apr_status_t rv; - const char *mime_type; - - if (dc->debug >= DBGLVL_FLOW) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO, 0, r, - "uri: %s file: %s method: %d " - "imt: %s flags: %s%s%s %s->%s", - r->uri, r->filename, r->method_number, - r->content_type ? r->content_type : "(unknown)", - r->main ? "S" : "", /* S if subrequest */ - r->prev ? "R" : "", /* R if redirect */ - r->proxyreq ? "P" : "", /* P if proxy */ - dc->charset_source, dc->charset_default); - } - - /* If we don't have a full directory configuration, bail out. - */ - if (!dc->charset_source || !dc->charset_default) { - if (dc->debug >= DBGLVL_PMC) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, - "incomplete configuration: src %s, dst %s", - dc->charset_source ? dc->charset_source : "unspecified", - dc->charset_default ? dc->charset_default : "unspecified"); - } - return DECLINED; - } - - /* catch proxy requests */ - if (r->proxyreq) return DECLINED; - /* mod_rewrite indicators */ - if (!strncmp(r->filename, "redirect:", 9)) return DECLINED; - if (!strncmp(r->filename, "gone:", 5)) return DECLINED; - if (!strncmp(r->filename, "passthrough:", 12)) return DECLINED; - if (!strncmp(r->filename, "forbidden:", 10)) return DECLINED; - - mime_type = r->content_type ? r->content_type : ap_default_type(r); - - /* If mime type isn't text or message, bail out. - */ - -/* XXX When we handle translation of the request body, watch out here as - * 1.3 allowed additional mime types: multipart and - * application/x-www-form-urlencoded - */ - - if (strncasecmp(mime_type, "text/", 5) && -#if APR_CHARSET_EBCDIC - /* On an EBCDIC machine, be willing to translate mod_autoindex- - * generated output. Otherwise, it doesn't look too cool. - * - * XXX This isn't a perfect fix because this doesn't trigger us - * to convert from the charset of the source code to ASCII. The - * general solution seems to be to allow a generator to set an - * indicator in the r specifying that the body is coded in the - * implementation character set (i.e., the charset of the source - * code). This would get several different types of documents - * translated properly: mod_autoindex output, mod_status output, - * mod_info output, hard-coded error documents, etc. - */ - strcmp(mime_type, DIR_MAGIC_TYPE) && -#endif - strncasecmp(mime_type, "message/", 8)) { - if (dc->debug >= DBGLVL_GORY) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, - "mime type is %s; no translation selected", - mime_type); - } - return DECLINED; - } - - if (dc->debug >= DBGLVL_GORY) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, - "charset_source: %s charset_default: %s", - dc && dc->charset_source ? dc->charset_source : "(none)", - dc && dc->charset_default ? dc->charset_default : "(none)"); - } - - /* Get storage for the request data and the output filter context. - * We rarely need the input filter context, so allocate that separately. - */ - reqinfo = (charset_req_t *)apr_pcalloc(r->pool, - sizeof(charset_req_t) + - sizeof(charset_filter_ctx_t)); - output_ctx = (charset_filter_ctx_t *)(reqinfo + 1); - - reqinfo->dc = dc; - output_ctx->dc = dc; - ap_set_module_config(r->request_config, &charset_lite_module, reqinfo); - - reqinfo->output_ctx = output_ctx; - rv = apr_xlate_open(&output_ctx->xlate, - dc->charset_default, dc->charset_source, r->pool); - if (rv != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "can't open translation %s->%s", - dc->charset_source, dc->charset_default); - return HTTP_INTERNAL_SERVER_ERROR; - } - - switch (r->method_number) { - case M_PUT: - case M_POST: - /* Set up input translation. Note: A request body can be included - * with the OPTIONS method, but for now we don't set up translation - * of it. - */ - input_ctx = apr_pcalloc(r->pool, sizeof(charset_filter_ctx_t)); - input_ctx->bb = apr_brigade_create(r->pool); - input_ctx->tmp = apr_palloc(r->pool, INPUT_XLATE_BUF_SIZE); - input_ctx->dc = dc; - reqinfo->input_ctx = input_ctx; - rv = apr_xlate_open(&input_ctx->xlate, dc->charset_source, - dc->charset_default, r->pool); - if (rv != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "can't open translation %s->%s", - dc->charset_default, dc->charset_source); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - - return DECLINED; -} - -static int configured_on_input(request_rec *r, const char *filter_name) -{ - int i; - core_dir_config *conf = - (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - char **items = (char **)conf->input_filters->elts; - - for (i = 0; i < conf->input_filters->nelts; i++) { - if (!strcmp(items[i], filter_name)) - return 1; - } - return 0; -} - -static int configured_on_output(request_rec *r, const char *filter_name) -{ - int i; - core_dir_config *conf = - (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - char **items = (char **)conf->output_filters->elts; - - for (i = 0; i < conf->output_filters->nelts; i++) { - if (!strcmp(items[i], filter_name)) - return 1; - } - return 0; -} - -/* xlate_insert_filter() is a filter hook which decides whether or not - * to insert a translation filter for the current request. - */ -static void xlate_insert_filter(request_rec *r) -{ - /* Hey... don't be so quick to use reqinfo->dc here; reqinfo may be NULL */ - charset_req_t *reqinfo = ap_get_module_config(r->request_config, - &charset_lite_module); - charset_dir_t *dc = ap_get_module_config(r->per_dir_config, - &charset_lite_module); - - if (reqinfo) { - if (reqinfo->output_ctx && !configured_on_output(r, XLATEOUT_FILTER_NAME)) { - ap_add_output_filter(XLATEOUT_FILTER_NAME, reqinfo->output_ctx, r, - r->connection); - } - else if (dc->debug >= DBGLVL_FLOW) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, - "xlate output filter not added implicitly because %s", - !reqinfo->output_ctx ? - "no output configuration available" : - "SetOutputFilter was used to add the filter"); - } - - if (reqinfo->input_ctx && !configured_on_input(r, XLATEIN_FILTER_NAME)) { - ap_add_input_filter(XLATEIN_FILTER_NAME, reqinfo->input_ctx, r, - r->connection); - } - else if (dc->debug >= DBGLVL_FLOW) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, - "xlate input filter not added implicitly because %s", - !reqinfo->input_ctx ? - "no input configuration available" : - "SetInputFilter was used to add the filter"); - } - } -} - -/* stuff that sucks that I know of: - * - * bucket handling: - * why create an eos bucket when we see it come down the stream? just send the one - * passed as input... news flash: this will be fixed when xlate_out_filter() starts - * using the more generic xlate_brigade() - * - * translation mechanics: - * we don't handle characters that straddle more than two buckets; an error - * will be generated - */ - -/* send_downstream() is passed the translated data; it puts it in a single- - * bucket brigade and passes the brigade to the next filter - */ -static apr_status_t send_downstream(ap_filter_t *f, const char *tmp, apr_size_t len) -{ - apr_bucket_brigade *bb; - apr_bucket *b; - charset_filter_ctx_t *ctx = f->ctx; - apr_status_t rv; - - bb = apr_brigade_create(f->r->pool); - b = apr_bucket_transient_create(tmp, len); - APR_BRIGADE_INSERT_TAIL(bb, b); - rv = ap_pass_brigade(f->next, bb); - if (rv != APR_SUCCESS) { - ctx->ees = EES_DOWNSTREAM; - } - return rv; -} - -static apr_status_t send_eos(ap_filter_t *f) -{ - apr_bucket_brigade *bb; - apr_bucket *b; - charset_filter_ctx_t *ctx = f->ctx; - apr_status_t rv; - - bb = apr_brigade_create(f->r->pool); - b = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - rv = ap_pass_brigade(f->next, bb); - if (rv != APR_SUCCESS) { - ctx->ees = EES_DOWNSTREAM; - } - return rv; -} - -static apr_status_t set_aside_partial_char(charset_filter_ctx_t *ctx, - const char *partial, - apr_size_t partial_len) -{ - apr_status_t rv; - - if (sizeof(ctx->buf) > partial_len) { - ctx->saved = partial_len; - memcpy(ctx->buf, partial, partial_len); - rv = APR_SUCCESS; - } - else { - rv = APR_INCOMPLETE; - ctx->ees = EES_LIMIT; /* we don't handle chars this wide which straddle - * buckets - */ - } - return rv; -} - -static apr_status_t finish_partial_char(charset_filter_ctx_t *ctx, - /* input buffer: */ - const char **cur_str, - apr_size_t *cur_len, - /* output buffer: */ - char **out_str, - apr_size_t *out_len) -{ - apr_status_t rv; - apr_size_t tmp_input_len; - - /* Keep adding bytes from the input string to the saved string until we - * 1) finish the input char - * 2) get an error - * or 3) run out of bytes to add - */ - - do { - ctx->buf[ctx->saved] = **cur_str; - ++ctx->saved; - ++*cur_str; - --*cur_len; - tmp_input_len = ctx->saved; - rv = apr_xlate_conv_buffer(ctx->xlate, - ctx->buf, - &tmp_input_len, - *out_str, - out_len); - } while (rv == APR_INCOMPLETE && *cur_len); - - if (rv == APR_SUCCESS) { - ctx->saved = 0; - } - else { - ctx->ees = EES_LIMIT; /* code isn't smart enough to handle chars - * straddling more than two buckets - */ - } - - return rv; -} - -static void log_xlate_error(ap_filter_t *f, apr_status_t rv) -{ - charset_filter_ctx_t *ctx = f->ctx; - const char *msg; - char msgbuf[100]; - int cur; - int flags = APLOG_ERR; - - switch(ctx->ees) { - case EES_LIMIT: - flags |= APLOG_NOERRNO; - msg = "xlate filter - a built-in restriction was encountered"; - break; - case EES_BAD_INPUT: - flags |= APLOG_NOERRNO; - msg = "xlate filter - an input character was invalid"; - break; - case EES_BUCKET_READ: - msg = "xlate filter - bucket read routine failed"; - break; - case EES_INCOMPLETE_CHAR: - flags |= APLOG_NOERRNO; - strcpy(msgbuf, "xlate filter - incomplete char at end of input - "); - cur = 0; - while (cur < ctx->saved) { - apr_snprintf(msgbuf + strlen(msgbuf), sizeof(msgbuf) - strlen(msgbuf), - "%02X", (unsigned)ctx->buf[cur]); - ++cur; - } - msg = msgbuf; - break; - case EES_DOWNSTREAM: - msg = "xlate filter - an error occurred in a lower filter"; - break; - default: - msg = "xlate filter - returning error"; - } - ap_log_rerror(APLOG_MARK, flags, rv, f->r, - "%s", msg); -} - -/* chk_filter_chain() is called once per filter instance; it tries to - * determine if the current filter instance should be disabled because - * its translation is incompatible with the translation of an existing - * instance of the translate filter - * - * Example bad scenario: - * - * configured filter chain for the request: - * INCLUDES XLATEOUT(8859-1->UTS-16) - * configured filter chain for the subrequest: - * XLATEOUT(8859-1->UTS-16) - * - * When the subrequest is processed, the filter chain will be - * XLATEOUT(8859-1->UTS-16) XLATEOUT(8859-1->UTS-16) - * This makes no sense, so the instance of XLATEOUT added for the - * subrequest will be noop-ed. - * - * Example good scenario: - * - * configured filter chain for the request: - * INCLUDES XLATEOUT(8859-1->UTS-16) - * configured filter chain for the subrequest: - * XLATEOUT(IBM-1047->8859-1) - * - * When the subrequest is processed, the filter chain will be - * XLATEOUT(IBM-1047->8859-1) XLATEOUT(8859-1->UTS-16) - * This makes sense, so the instance of XLATEOUT added for the - * subrequest will be left alone and it will translate from - * IBM-1047->8859-1. - */ -static void chk_filter_chain(ap_filter_t *f) -{ - ap_filter_t *curf; - charset_filter_ctx_t *curctx, *last_xlate_ctx = NULL, - *ctx = f->ctx; - int debug = ctx->dc->debug; - int output = !strcmp(f->frec->name, XLATEOUT_FILTER_NAME); - - if (ctx->noop) { - return; - } - - /* walk the filter chain; see if it makes sense for our filter to - * do any translation - */ - curf = output ? f->r->output_filters : f->r->input_filters; - while (curf) { - if (!strcmp(curf->frec->name, f->frec->name) && - curf->ctx) { - curctx = (charset_filter_ctx_t *)curf->ctx; - if (!last_xlate_ctx) { - last_xlate_ctx = curctx; - } - else { - if (strcmp(last_xlate_ctx->dc->charset_default, - curctx->dc->charset_source)) { - /* incompatible translation - * if our filter instance is incompatible with an instance - * already in place, noop our instance - * Notes: - * . We are only willing to noop our own instance. - * . It is possible to noop another instance which has not - * yet run, but this is not currently implemented. - * Hopefully it will not be needed. - * . It is not possible to noop an instance which has - * already run. - */ - if (last_xlate_ctx == f->ctx) { - last_xlate_ctx->noop = 1; - if (debug >= DBGLVL_PMC) { - const char *symbol = output ? "->" : "<-"; - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, - 0, f->r, - "%s %s - disabling " - "translation %s%s%s; existing " - "translation %s%s%s", - f->r->uri ? "uri" : "file", - f->r->uri ? f->r->uri : f->r->filename, - last_xlate_ctx->dc->charset_source, - symbol, - last_xlate_ctx->dc->charset_default, - curctx->dc->charset_source, - symbol, - curctx->dc->charset_default); - } - } - else { - const char *symbol = output ? "->" : "<-"; - - ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, - 0, f->r, - "chk_filter_chain() - can't disable " - "translation %s%s%s; existing " - "translation %s%s%s", - last_xlate_ctx->dc->charset_source, - symbol, - last_xlate_ctx->dc->charset_default, - curctx->dc->charset_source, - symbol, - curctx->dc->charset_default); - } - break; - } - } - } - curf = curf->next; - } -} - -/* xlate_brigade() is used to filter request and response bodies - * - * we'll stop when one of the following occurs: - * . we run out of buckets - * . we run out of space in the output buffer - * . we hit an error - * - * inputs: - * bb: brigade to process - * buffer: storage to hold the translated characters - * buffer_size: size of buffer - * (and a few more uninteresting parms) - * - * outputs: - * return value: APR_SUCCESS or some error code - * bb: we've removed any buckets representing the - * translated characters; the eos bucket, if - * present, will be left in the brigade - * buffer: filled in with translated characters - * buffer_size: updated with the bytes remaining - * hit_eos: did we hit an EOS bucket? - */ -static apr_status_t xlate_brigade(charset_filter_ctx_t *ctx, - apr_bucket_brigade *bb, - char *buffer, - apr_size_t *buffer_avail, - int *hit_eos) -{ - apr_bucket *b, *consumed_bucket; - const char *bucket; - apr_size_t bytes_in_bucket; /* total bytes read from current bucket */ - apr_size_t bucket_avail; /* bytes left in current bucket */ - apr_status_t rv = APR_SUCCESS; - - *hit_eos = 0; - bucket_avail = 0; - consumed_bucket = NULL; - while (1) { - if (!bucket_avail) { /* no bytes left to process in the current bucket... */ - if (consumed_bucket) { - apr_bucket_delete(consumed_bucket); - consumed_bucket = NULL; - } - b = APR_BRIGADE_FIRST(bb); - if (b == APR_BRIGADE_SENTINEL(bb) || - APR_BUCKET_IS_EOS(b)) { - break; - } - rv = apr_bucket_read(b, &bucket, &bytes_in_bucket, APR_BLOCK_READ); - if (rv != APR_SUCCESS) { - ctx->ees = EES_BUCKET_READ; - break; - } - bucket_avail = bytes_in_bucket; - consumed_bucket = b; /* for axing when we're done reading it */ - } - if (bucket_avail) { - /* We've got data, so translate it. */ - if (ctx->saved) { - /* Rats... we need to finish a partial character from the previous - * bucket. - * - * Strangely, finish_partial_char() increments the input buffer - * pointer but does not increment the output buffer pointer. - */ - apr_size_t old_buffer_avail = *buffer_avail; - rv = finish_partial_char(ctx, - &bucket, &bucket_avail, - &buffer, buffer_avail); - buffer += old_buffer_avail - *buffer_avail; - } - else { - apr_size_t old_buffer_avail = *buffer_avail; - apr_size_t old_bucket_avail = bucket_avail; - rv = apr_xlate_conv_buffer(ctx->xlate, - bucket, &bucket_avail, - buffer, - buffer_avail); - buffer += old_buffer_avail - *buffer_avail; - bucket += old_bucket_avail - bucket_avail; - - if (rv == APR_INCOMPLETE) { /* partial character at end of input */ - /* We need to save the final byte(s) for next time; we can't - * convert it until we look at the next bucket. - */ - rv = set_aside_partial_char(ctx, bucket, bucket_avail); - bucket_avail = 0; - } - } - if (rv != APR_SUCCESS) { - /* bad input byte or partial char too big to store */ - break; - } - if (*buffer_avail < XLATE_MIN_BUFF_LEFT) { - /* if any data remains in the current bucket, split there */ - if (bucket_avail) { - apr_bucket_split(b, bytes_in_bucket - bucket_avail); - } - apr_bucket_delete(b); - break; - } - } - } - - if (!APR_BRIGADE_EMPTY(bb)) { - b = APR_BRIGADE_FIRST(bb); - if (APR_BUCKET_IS_EOS(b)) { - /* Leave the eos bucket in the brigade for reporting to - * subsequent filters. - */ - *hit_eos = 1; - if (ctx->saved) { - /* Oops... we have a partial char from the previous bucket - * that won't be completed because there's no more data. - */ - rv = APR_INCOMPLETE; - ctx->ees = EES_INCOMPLETE_CHAR; - } - } - } - - return rv; -} - -/* xlate_out_filter() handles (almost) arbitrary conversions from one charset - * to another... - * translation is determined in the fixup hook (find_code_page), which is - * where the filter's context data is set up... the context data gives us - * the translation handle - */ -static apr_status_t xlate_out_filter(ap_filter_t *f, apr_bucket_brigade *bb) -{ - charset_req_t *reqinfo = ap_get_module_config(f->r->request_config, - &charset_lite_module); - charset_dir_t *dc = ap_get_module_config(f->r->per_dir_config, - &charset_lite_module); - charset_filter_ctx_t *ctx = f->ctx; - apr_bucket *dptr, *consumed_bucket; - const char *cur_str; - apr_size_t cur_len, cur_avail; - char tmp[OUTPUT_XLATE_BUF_SIZE]; - apr_size_t space_avail; - int done; - apr_status_t rv = APR_SUCCESS; - - if (!ctx) { - /* this is SetOutputFilter path; grab the preallocated context, - * if any; note that if we decided not to do anything in an earlier - * handler, we won't even have a reqinfo - */ - if (reqinfo) { - ctx = f->ctx = reqinfo->output_ctx; - reqinfo->output_ctx = NULL; /* prevent SNAFU if user coded us twice - * in the filter chain; we can't have two - * instances using the same context - */ - } - if (!ctx) { /* no idea how to translate; don't do anything */ - ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(charset_filter_ctx_t)); - ctx->dc = dc; - ctx->noop = 1; - } - } - - if (dc->debug >= DBGLVL_GORY) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, f->r, - "xlate_out_filter() - " - "charset_source: %s charset_default: %s", - dc && dc->charset_source ? dc->charset_source : "(none)", - dc && dc->charset_default ? dc->charset_default : "(none)"); - } - - if (!ctx->ran) { /* filter never ran before */ - chk_filter_chain(f); - ctx->ran = 1; - } - - if (ctx->noop) { - return ap_pass_brigade(f->next, bb); - } - - dptr = APR_BRIGADE_FIRST(bb); - done = 0; - cur_len = 0; - space_avail = sizeof(tmp); - consumed_bucket = NULL; - while (!done) { - if (!cur_len) { /* no bytes left to process in the current bucket... */ - if (consumed_bucket) { - apr_bucket_delete(consumed_bucket); - consumed_bucket = NULL; - } - if (dptr == APR_BRIGADE_SENTINEL(bb)) { - done = 1; - break; - } - if (APR_BUCKET_IS_EOS(dptr)) { - done = 1; - cur_len = -1; /* XXX yuck, but that tells us to send - * eos down; when we minimize our bb construction - * we'll fix this crap */ - if (ctx->saved) { - /* Oops... we have a partial char from the previous bucket - * that won't be completed because there's no more data. - */ - rv = APR_INCOMPLETE; - ctx->ees = EES_INCOMPLETE_CHAR; - } - break; - } - rv = apr_bucket_read(dptr, &cur_str, &cur_len, APR_BLOCK_READ); - if (rv != APR_SUCCESS) { - done = 1; - ctx->ees = EES_BUCKET_READ; - break; - } - consumed_bucket = dptr; /* for axing when we're done reading it */ - dptr = APR_BUCKET_NEXT(dptr); /* get ready for when we access the - * next bucket */ - } - /* Try to fill up our tmp buffer with translated data. */ - cur_avail = cur_len; - - if (cur_len) { /* maybe we just hit the end of a pipe (len = 0) ? */ - if (ctx->saved) { - /* Rats... we need to finish a partial character from the previous - * bucket. - */ - char *tmp_tmp; - - tmp_tmp = tmp + sizeof(tmp) - space_avail; - rv = finish_partial_char(ctx, - &cur_str, &cur_len, - &tmp_tmp, &space_avail); - } - else { - rv = apr_xlate_conv_buffer(ctx->xlate, - cur_str, &cur_avail, - tmp + sizeof(tmp) - space_avail, &space_avail); - - /* Update input ptr and len after consuming some bytes */ - cur_str += cur_len - cur_avail; - cur_len = cur_avail; - - if (rv == APR_INCOMPLETE) { /* partial character at end of input */ - /* We need to save the final byte(s) for next time; we can't - * convert it until we look at the next bucket. - */ - rv = set_aside_partial_char(ctx, cur_str, cur_len); - cur_len = 0; - } - } - } - - if (rv != APR_SUCCESS) { - /* bad input byte or partial char too big to store */ - done = 1; - } - - if (space_avail < XLATE_MIN_BUFF_LEFT) { - /* It is time to flush, as there is not enough space left in the - * current output buffer to bother with converting more data. - */ - rv = send_downstream(f, tmp, sizeof(tmp) - space_avail); - if (rv != APR_SUCCESS) { - done = 1; - } - - /* tmp is now empty */ - space_avail = sizeof(tmp); - } - } - - if (rv == APR_SUCCESS) { - if (space_avail < sizeof(tmp)) { /* gotta write out what we converted */ - rv = send_downstream(f, tmp, sizeof(tmp) - space_avail); - } - } - if (rv == APR_SUCCESS) { - if (cur_len == -1) { - rv = send_eos(f); - } - } - else { - log_xlate_error(f, rv); - } - - return rv; -} - -static void transfer_brigade(apr_bucket_brigade *in, apr_bucket_brigade *out) -{ - apr_bucket *b; - - while (!APR_BRIGADE_EMPTY(in)) { - b = APR_BRIGADE_FIRST(in); - APR_BUCKET_REMOVE(b); - APR_BRIGADE_INSERT_TAIL(out, b); - } -} - -static int xlate_in_filter(ap_filter_t *f, apr_bucket_brigade *bb, - ap_input_mode_t mode, apr_size_t *readbytes) -{ - apr_status_t rv; - charset_req_t *reqinfo = ap_get_module_config(f->r->request_config, - &charset_lite_module); - charset_dir_t *dc = ap_get_module_config(f->r->per_dir_config, - &charset_lite_module); - charset_filter_ctx_t *ctx = f->ctx; - apr_size_t buffer_size; - int hit_eos; - - if (!ctx) { - /* this is SetInputFilter path; grab the preallocated context, - * if any; note that if we decided not to do anything in an earlier - * handler, we won't even have a reqinfo - */ - if (reqinfo) { - ctx = f->ctx = reqinfo->input_ctx; - reqinfo->input_ctx = NULL; /* prevent SNAFU if user coded us twice - * in the filter chain; we can't have two - * instances using the same context - */ - } - if (!ctx) { /* no idea how to translate; don't do anything */ - ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(charset_filter_ctx_t)); - ctx->dc = dc; - ctx->noop = 1; - } - } - - if (dc->debug >= DBGLVL_GORY) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, f->r, - "xlate_in_filter() - " - "charset_source: %s charset_default: %s", - dc && dc->charset_source ? dc->charset_source : "(none)", - dc && dc->charset_default ? dc->charset_default : "(none)"); - } - - if (!ctx->ran) { /* filter never ran before */ - chk_filter_chain(f); - ctx->ran = 1; - } - - if (ctx->noop) { - return ap_get_brigade(f->next, bb, mode, readbytes); - } - - if (APR_BRIGADE_EMPTY(ctx->bb)) { - if ((rv = ap_get_brigade(f->next, bb, mode, readbytes)) != APR_SUCCESS) { - return rv; - } - } - else { - transfer_brigade(ctx->bb, bb); /* first use the leftovers */ - } - - buffer_size = INPUT_XLATE_BUF_SIZE; - rv = xlate_brigade(ctx, bb, ctx->tmp, &buffer_size, &hit_eos); - if (rv == APR_SUCCESS) { - if (!hit_eos) { - /* move anything leftover into our context for next time; - * we don't currently "set aside" since the data came from - * down below, but I suspect that for long-term we need to - * do that - */ - transfer_brigade(bb, ctx->bb); - } - if (buffer_size < INPUT_XLATE_BUF_SIZE) { /* do we have output? */ - apr_bucket *e; - - e = apr_bucket_heap_create(ctx->tmp, - INPUT_XLATE_BUF_SIZE - buffer_size, 1, - NULL); - /* make sure we insert at the head, because there may be - * an eos bucket already there, and the eos bucket should - * come after the data - */ - APR_BRIGADE_INSERT_HEAD(bb, e); - } - else { - /* XXX need to get some more data... what if the last brigade - * we got had only the first byte of a multibyte char? we need - * to grab more data from the network instead of returning an - * empty brigade - */ - } - } - else { - log_xlate_error(f, rv); - } - - return rv; -} - -static const command_rec cmds[] = -{ - AP_INIT_TAKE1("CharsetSourceEnc", - add_charset_source, - NULL, - OR_FILEINFO, - "source (html,cgi,ssi) file charset"), - AP_INIT_TAKE1("CharsetDefault", - add_charset_default, - NULL, - OR_FILEINFO, - "name of default charset"), - AP_INIT_ITERATE("CharsetOptions", - add_charset_options, - NULL, - OR_FILEINFO, - "valid options: ImplicitAdd, NoImplicitAdd, DebugLevel=n"), - {NULL} -}; - -static void charset_register_hooks(apr_pool_t *p) -{ - ap_hook_fixups(find_code_page, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_insert_filter(xlate_insert_filter, NULL, NULL, APR_HOOK_MIDDLE); - ap_register_output_filter(XLATEOUT_FILTER_NAME, xlate_out_filter, - AP_FTYPE_CONTENT); - ap_register_input_filter(XLATEIN_FILTER_NAME, xlate_in_filter, - AP_FTYPE_CONTENT); -} - -module charset_lite_module = -{ - STANDARD20_MODULE_STUFF, - create_charset_dir_conf, - merge_charset_dir_conf, - NULL, - NULL, - cmds, - charset_register_hooks -}; - diff --git a/modules/experimental/mod_disk_cache.c b/modules/experimental/mod_disk_cache.c deleted file mode 100644 index cbd28bf04a..0000000000 --- a/modules/experimental/mod_disk_cache.c +++ /dev/null @@ -1,170 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "mod_cache.h" -#include "apr_file_io.h" -#include "apr_strings.h" -#include "http_config.h" -#include "http_log.h" -#include "util_filter.h" - -module MODULE_VAR_EXPORT disk_cache_module; - -static int disk_serve(request_rec *r) -{ - apr_bucket *e; - apr_bucket_brigade *bb = apr_brigade_create(r->pool); - const char *filename; - apr_file_t *fd = NULL; - apr_status_t rv; - ap_filter_t *f; - char str[256]; - apr_off_t offset = 0; - - filename = ap_server_root_relative(r->pool, - apr_pstrcat(r->pool, "proxy", r->uri, NULL)); - if ((rv = apr_file_open(&fd, filename, APR_READ, - APR_UREAD, r->connection->pool)) != APR_SUCCESS) { - return DECLINED; - } - - /* skip the cached headers. */ - do { - apr_file_gets(str, 256, fd); - offset += strlen(str); - } while (strcmp(str, CRLF)); - - /* If we are serving from the cache, we don't want to try to cache it - * again. - */ - for ((f = r->output_filters); (f = f->next);) { - if (!strcmp(f->frec->name, "CACHE")) { - ap_remove_output_filter(f); - } - } - - e = apr_bucket_file_create(fd, offset, r->finfo.size); - - APR_BRIGADE_INSERT_HEAD(bb, e); - e = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - - ap_pass_brigade(r->output_filters, bb); - return OK; -} - -typedef struct cache_struct { - const char *filename; - apr_file_t *fd; - int state; -} cache_struct; - -static int disk_cache(request_rec *r, apr_bucket_brigade *bb, void **cf) -{ - cache_struct *ctx = *cf; - apr_bucket *e; - - if (ctx == NULL) { - *cf = ctx = apr_pcalloc(r->pool, sizeof(*ctx)); - } - if (ctx->filename == NULL) { - apr_status_t rv; - apr_dir_make(ap_server_root_relative(r->pool, "proxy"), APR_UREAD | APR_UWRITE | APR_UEXECUTE | APR_GREAD | APR_GWRITE, r->pool); - - /* currently, we are using the uri as the cache key. This is - * probably wrong, but it is much better than a hard-coded filename. - */ - ctx->filename = ap_server_root_relative(r->pool, - apr_pstrcat(r->pool, "proxy", r->uri, NULL)); - if ((rv = apr_file_open(&ctx->fd, ctx->filename, - APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BUFFERED, - APR_UREAD | APR_UWRITE, r->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "Could not create cache file"); - *cf = NULL; - return DECLINED; - } - } - APR_BRIGADE_FOREACH(e, bb) { - const char *str; - apr_ssize_t length; - - apr_bucket_read(e, &str, &length, APR_BLOCK_READ); - apr_file_write(ctx->fd, str, &length); - } - if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) { - apr_file_close(ctx->fd); - } - return OK; -} - -static void disk_cache_register_hook(apr_pool_t *p) -{ - ap_hook_store_cache(disk_cache, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_serve_cache(disk_serve, NULL, NULL, APR_HOOK_MIDDLE); -} - -module MODULE_VAR_EXPORT disk_cache_module = { - STANDARD20_MODULE_STUFF, - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - NULL, /* command apr_table_t */ - disk_cache_register_hook /* register hooks */ -}; diff --git a/modules/experimental/mod_example.c b/modules/experimental/mod_example.c deleted file mode 100644 index 5d8de38777..0000000000 --- a/modules/experimental/mod_example.c +++ /dev/null @@ -1,1198 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * Apache example module. Provide demonstrations of how modules do things. - * - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_main.h" -#include "http_protocol.h" -#include "http_request.h" -#include "util_script.h" - -#include "apr_strings.h" - -#include <stdio.h> - -/*--------------------------------------------------------------------------*/ -/* */ -/* Data declarations. */ -/* */ -/* Here are the static cells and structure declarations private to our */ -/* module. */ -/* */ -/*--------------------------------------------------------------------------*/ - -/* - * Sample configuration record. Used for both per-directory and per-server - * configuration data. - * - * It's perfectly reasonable to have two different structures for the two - * different environments. The same command handlers will be called for - * both, though, so the handlers need to be able to tell them apart. One - * possibility is for both structures to start with an int which is zero for - * one and 1 for the other. - * - * Note that while the per-directory and per-server configuration records are - * available to most of the module handlers, they should be treated as - * READ-ONLY by all except the command and merge handlers. Sometimes handlers - * are handed a record that applies to the current location by implication or - * inheritance, and modifying it will change the rules for other locations. - */ -typedef struct excfg { - int cmode; /* Environment to which record applies (directory, - * server, or combination). - */ -#define CONFIG_MODE_SERVER 1 -#define CONFIG_MODE_DIRECTORY 2 -#define CONFIG_MODE_COMBO 3 /* Shouldn't ever happen. */ - int local; /* Boolean: "Example" directive declared here? */ - int congenital; /* Boolean: did we inherit an "Example"? */ - char *trace; /* Pointer to trace string. */ - char *loc; /* Location to which this record applies. */ -} excfg; - -/* - * Let's set up a module-local static cell to point to the accreting callback - * trace. As each API callback is made to us, we'll tack on the particulars - * to whatever we've already recorded. To avoid massive memory bloat as - * directories are walked again and again, we record the routine/environment - * the first time (non-request context only), and ignore subsequent calls for - * the same routine/environment. - */ -static const char *trace = NULL; -static apr_table_t *static_calls_made = NULL; - -/* - * To avoid leaking memory from pools other than the per-request one, we - * allocate a module-private pool, and then use a sub-pool of that which gets - * freed each time we modify the trace. That way previous layers of trace - * data don't get lost. - */ -static apr_pool_t *example_pool = NULL; -static apr_pool_t *example_subpool = NULL; - -/* - * Declare ourselves so the configuration routines can find and know us. - * We'll fill it in at the end of the module. - */ -module example_module; - -/*--------------------------------------------------------------------------*/ -/* */ -/* The following pseudo-prototype declarations illustrate the parameters */ -/* passed to command handlers for the different types of directive */ -/* syntax. If an argument was specified in the directive definition */ -/* (look for "command_rec" below), it's available to the command handler */ -/* via the (void *) info field in the cmd_parms argument passed to the */ -/* handler (cmd->info for the examples below). */ -/* */ -/*--------------------------------------------------------------------------*/ - -/* - * Command handler for a NO_ARGS directive. - * - * static const char *handle_NO_ARGS(cmd_parms *cmd, void *mconfig); - */ - -/* - * Command handler for a RAW_ARGS directive. The "args" argument is the text - * of the commandline following the directive itself. - * - * static const char *handle_RAW_ARGS(cmd_parms *cmd, void *mconfig, - * const char *args); - */ - -/* - * Command handler for a FLAG directive. The single parameter is passed in - * "bool", which is either zero or not for Off or On respectively. - * - * static const char *handle_FLAG(cmd_parms *cmd, void *mconfig, int bool); - */ - -/* - * Command handler for a TAKE1 directive. The single parameter is passed in - * "word1". - * - * static const char *handle_TAKE1(cmd_parms *cmd, void *mconfig, - * char *word1); - */ - -/* - * Command handler for a TAKE2 directive. TAKE2 commands must always have - * exactly two arguments. - * - * static const char *handle_TAKE2(cmd_parms *cmd, void *mconfig, - * char *word1, char *word2); - */ - -/* - * Command handler for a TAKE3 directive. Like TAKE2, these must have exactly - * three arguments, or the parser complains and doesn't bother calling us. - * - * static const char *handle_TAKE3(cmd_parms *cmd, void *mconfig, - * char *word1, char *word2, char *word3); - */ - -/* - * Command handler for a TAKE12 directive. These can take either one or two - * arguments. - * - word2 is a NULL pointer if no second argument was specified. - * - * static const char *handle_TAKE12(cmd_parms *cmd, void *mconfig, - * char *word1, char *word2); - */ - -/* - * Command handler for a TAKE123 directive. A TAKE123 directive can be given, - * as might be expected, one, two, or three arguments. - * - word2 is a NULL pointer if no second argument was specified. - * - word3 is a NULL pointer if no third argument was specified. - * - * static const char *handle_TAKE123(cmd_parms *cmd, void *mconfig, - * char *word1, char *word2, char *word3); - */ - -/* - * Command handler for a TAKE13 directive. Either one or three arguments are - * permitted - no two-parameters-only syntax is allowed. - * - word2 and word3 are NULL pointers if only one argument was specified. - * - * static const char *handle_TAKE13(cmd_parms *cmd, void *mconfig, - * char *word1, char *word2, char *word3); - */ - -/* - * Command handler for a TAKE23 directive. At least two and as many as three - * arguments must be specified. - * - word3 is a NULL pointer if no third argument was specified. - * - * static const char *handle_TAKE23(cmd_parms *cmd, void *mconfig, - * char *word1, char *word2, char *word3); - */ - -/* - * Command handler for a ITERATE directive. - * - Handler is called once for each of n arguments given to the directive. - * - word1 points to each argument in turn. - * - * static const char *handle_ITERATE(cmd_parms *cmd, void *mconfig, - * char *word1); - */ - -/* - * Command handler for a ITERATE2 directive. - * - Handler is called once for each of the second and subsequent arguments - * given to the directive. - * - word1 is the same for each call for a particular directive instance (the - * first argument). - * - word2 points to each of the second and subsequent arguments in turn. - * - * static const char *handle_ITERATE2(cmd_parms *cmd, void *mconfig, - * char *word1, char *word2); - */ - -/*--------------------------------------------------------------------------*/ -/* */ -/* These routines are strictly internal to this module, and support its */ -/* operation. They are not referenced by any external portion of the */ -/* server. */ -/* */ -/*--------------------------------------------------------------------------*/ - -/* - * Locate our directory configuration record for the current request. - */ -static excfg *our_dconfig(request_rec *r) -{ - - return (excfg *) ap_get_module_config(r->per_dir_config, &example_module); -} - -#if 0 -/* - * Locate our server configuration record for the specified server. - */ -static excfg *our_sconfig(server_rec *s) -{ - - return (excfg *) ap_get_module_config(s->module_config, &example_module); -} - -/* - * Likewise for our configuration record for the specified request. - */ -static excfg *our_rconfig(request_rec *r) -{ - - return (excfg *) ap_get_module_config(r->request_config, &example_module); -} -#endif - -/* - * This routine sets up some module-wide cells if they haven't been already. - */ -static void setup_module_cells(void) -{ - /* - * If we haven't already allocated our module-private pool, do so now. - */ - if (example_pool == NULL) { - apr_pool_create(&example_pool, NULL); - }; - /* - * Likewise for the apr_table_t of routine/environment pairs we visit outside of - * request context. - */ - if (static_calls_made == NULL) { - static_calls_made = apr_table_make(example_pool, 16); - }; -} - -/* - * This routine is used to add a trace of a callback to the list. We're - * passed the server record (if available), the request record (if available), - * a pointer to our private configuration record (if available) for the - * environment to which the callback is supposed to apply, and some text. We - * turn this into a textual representation and add it to the tail of the list. - * The list can be displayed by the example_handler() routine. - * - * If the call occurs within a request context (i.e., we're passed a request - * record), we put the trace into the request apr_pool_t and attach it to the - * request via the notes mechanism. Otherwise, the trace gets added - * to the static (non-request-specific) list. - * - * Note that the r->notes apr_table_t is only for storing strings; if you need to - * maintain per-request data of any other type, you need to use another - * mechanism. - */ - -#define TRACE_NOTE "example-trace" - -static void trace_add(server_rec *s, request_rec *r, excfg *mconfig, - const char *note) -{ - - const char *sofar; - char *addon; - char *where; - apr_pool_t *p; - const char *trace_copy; - - /* - * Make sure our pools and tables are set up - we need 'em. - */ - setup_module_cells(); - /* - * Now, if we're in request-context, we use the request pool. - */ - if (r != NULL) { - p = r->pool; - if ((trace_copy = apr_table_get(r->notes, TRACE_NOTE)) == NULL) { - trace_copy = ""; - } - } - else { - /* - * We're not in request context, so the trace gets attached to our - * module-wide pool. We do the create/destroy every time we're called - * in non-request context; this avoids leaking memory in some of - * the subsequent calls that allocate memory only once (such as the - * key formation below). - * - * Make a new sub-pool and copy any existing trace to it. Point the - * trace cell at the copied value. - */ - apr_pool_create(&p, example_pool); - if (trace != NULL) { - trace = apr_pstrdup(p, trace); - } - /* - * Now, if we have a sub-pool from before, nuke it and replace with - * the one we just allocated. - */ - if (example_subpool != NULL) { - apr_pool_destroy(example_subpool); - } - example_subpool = p; - trace_copy = trace; - } - /* - * If we weren't passed a configuration record, we can't figure out to - * what location this call applies. This only happens for co-routines - * that don't operate in a particular directory or server context. If we - * got a valid record, extract the location (directory or server) to which - * it applies. - */ - where = (mconfig != NULL) ? mconfig->loc : "nowhere"; - where = (where != NULL) ? where : ""; - /* - * Now, if we're not in request context, see if we've been called with - * this particular combination before. The apr_table_t is allocated in the - * module's private pool, which doesn't get destroyed. - */ - if (r == NULL) { - char *key; - - key = apr_pstrcat(p, note, ":", where, NULL); - if (apr_table_get(static_calls_made, key) != NULL) { - /* - * Been here, done this. - */ - return; - } - else { - /* - * First time for this combination of routine and environment - - * log it so we don't do it again. - */ - apr_table_set(static_calls_made, key, "been here"); - } - } - addon = apr_pstrcat(p, " <LI>\n", " <DL>\n", " <DT><SAMP>", - note, "</SAMP>\n", " </DT>\n", " <DD><SAMP>[", - where, "]</SAMP>\n", " </DD>\n", " </DL>\n", - " </LI>\n", NULL); - sofar = (trace_copy == NULL) ? "" : trace_copy; - trace_copy = apr_pstrcat(p, sofar, addon, NULL); - if (r != NULL) { - apr_table_set(r->notes, TRACE_NOTE, trace_copy); - } - else { - trace = trace_copy; - } - /* - * You *could* change the following if you wanted to see the calling - * sequence reported in the server's error_log, but beware - almost all of - * these co-routines are called for every single request, and the impact - * on the size (and readability) of the error_log is considerable. - */ -#define EXAMPLE_LOG_EACH 0 - if (EXAMPLE_LOG_EACH && (s != NULL)) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_example: %s", note); - } -} - -/*--------------------------------------------------------------------------*/ -/* We prototyped the various syntax for command handlers (routines that */ -/* are called when the configuration parser detects a directive declared */ -/* by our module) earlier. Now we actually declare a "real" routine that */ -/* will be invoked by the parser when our "real" directive is */ -/* encountered. */ -/* */ -/* If a command handler encounters a problem processing the directive, it */ -/* signals this fact by returning a non-NULL pointer to a string */ -/* describing the problem. */ -/* */ -/* The magic return value DECLINE_CMD is used to deal with directives */ -/* that might be declared by multiple modules. If the command handler */ -/* returns NULL, the directive was processed; if it returns DECLINE_CMD, */ -/* the next module (if any) that declares the directive is given a chance */ -/* at it. If it returns any other value, it's treated as the text of an */ -/* error message. */ -/*--------------------------------------------------------------------------*/ -/* - * Command handler for the NO_ARGS "Example" directive. All we do is mark the - * call in the trace log, and flag the applicability of the directive to the - * current location in that location's configuration record. - */ -static const char *cmd_example(cmd_parms *cmd, void *mconfig) -{ - - excfg *cfg = (excfg *) mconfig; - - /* - * "Example Wuz Here" - */ - cfg->local = 1; - trace_add(cmd->server, NULL, cfg, "cmd_example()"); - return NULL; -} - -/*--------------------------------------------------------------------------*/ -/* */ -/* Now we declare our content handlers, which are invoked when the server */ -/* encounters a document which our module is supposed to have a chance to */ -/* see. (See mod_mime's SetHandler and AddHandler directives, and the */ -/* mod_info and mod_status examples, for more details.) */ -/* */ -/* Since content handlers are dumping data directly into the connexion */ -/* (using the r*() routines, such as rputs() and rprintf()) without */ -/* intervention by other parts of the server, they need to make */ -/* sure any accumulated HTTP headers are sent first. This is done by */ -/* calling send_http_header(). Otherwise, no header will be sent at all, */ -/* and the output sent to the client will actually be HTTP-uncompliant. */ -/*--------------------------------------------------------------------------*/ -/* - * Sample content handler. All this does is display the call list that has - * been built up so far. - * - * The return value instructs the caller concerning what happened and what to - * do next: - * OK ("we did our thing") - * DECLINED ("this isn't something with which we want to get involved") - * HTTP_mumble ("an error status should be reported") - */ -static int example_handler(request_rec *r) -{ - - excfg *dcfg; - - dcfg = our_dconfig(r); - trace_add(r->server, r, dcfg, "example_handler()"); - /* - * We're about to start sending content, so we need to force the HTTP - * headers to be sent at this point. Otherwise, no headers will be sent - * at all. We can set any we like first, of course. **NOTE** Here's - * where you set the "Content-type" header, and you do so by putting it in - * r->content_type, *not* r->headers_out("Content-type"). If you don't - * set it, it will be filled in with the server's default type (typically - * "text/plain"). You *must* also ensure that r->content_type is lower - * case. - * - * We also need to start a timer so the server can know if the connexion - * is broken. - */ - r->content_type = "text/html"; - /* - * If we're only supposed to send header information (HEAD request), we're - * already there. - */ - if (r->header_only) { - return OK; - } - - /* - * Now send our actual output. Since we tagged this as being - * "text/html", we need to embed any HTML. - */ - ap_rputs(DOCTYPE_HTML_3_2, r); - ap_rputs("<HTML>\n", r); - ap_rputs(" <HEAD>\n", r); - ap_rputs(" <TITLE>mod_example Module Content-Handler Output\n", r); - ap_rputs(" </TITLE>\n", r); - ap_rputs(" </HEAD>\n", r); - ap_rputs(" <BODY>\n", r); - ap_rputs(" <H1><SAMP>mod_example</SAMP> Module Content-Handler Output\n", r); - ap_rputs(" </H1>\n", r); - ap_rputs(" <P>\n", r); - ap_rprintf(r, " Apache HTTP Server version: \"%s\"\n", - ap_get_server_version()); - ap_rputs(" <BR>\n", r); - ap_rprintf(r, " Server built: \"%s\"\n", ap_get_server_built()); - ap_rputs(" </P>\n", r);; - ap_rputs(" <P>\n", r); - ap_rputs(" The format for the callback trace is:\n", r); - ap_rputs(" </P>\n", r); - ap_rputs(" <DL>\n", r); - ap_rputs(" <DT><EM>n</EM>.<SAMP><routine-name>", r); - ap_rputs("(<routine-data>)</SAMP>\n", r); - ap_rputs(" </DT>\n", r); - ap_rputs(" <DD><SAMP>[<applies-to>]</SAMP>\n", r); - ap_rputs(" </DD>\n", r); - ap_rputs(" </DL>\n", r); - ap_rputs(" <P>\n", r); - ap_rputs(" The <SAMP><routine-data></SAMP> is supplied by\n", r); - ap_rputs(" the routine when it requests the trace,\n", r); - ap_rputs(" and the <SAMP><applies-to></SAMP> is extracted\n", r); - ap_rputs(" from the configuration record at the time of the trace.\n", r); - ap_rputs(" <STRONG>SVR()</STRONG> indicates a server environment\n", r); - ap_rputs(" (blank means the main or default server, otherwise it's\n", r); - ap_rputs(" the name of the VirtualHost); <STRONG>DIR()</STRONG>\n", r); - ap_rputs(" indicates a location in the URL or filesystem\n", r); - ap_rputs(" namespace.\n", r); - ap_rputs(" </P>\n", r); - ap_rprintf(r, " <H2>Static callbacks so far:</H2>\n <OL>\n%s </OL>\n", - trace); - ap_rputs(" <H2>Request-specific callbacks so far:</H2>\n", r); - ap_rprintf(r, " <OL>\n%s </OL>\n", apr_table_get(r->notes, TRACE_NOTE)); - ap_rputs(" <H2>Environment for <EM>this</EM> call:</H2>\n", r); - ap_rputs(" <UL>\n", r); - ap_rprintf(r, " <LI>Applies-to: <SAMP>%s</SAMP>\n </LI>\n", dcfg->loc); - ap_rprintf(r, " <LI>\"Example\" directive declared here: %s\n </LI>\n", - (dcfg->local ? "YES" : "NO")); - ap_rprintf(r, " <LI>\"Example\" inherited: %s\n </LI>\n", - (dcfg->congenital ? "YES" : "NO")); - ap_rputs(" </UL>\n", r); - ap_rputs(" </BODY>\n", r); - ap_rputs("</HTML>\n", r); - /* - * We're all done, so cancel the timeout we set. Since this is probably - * the end of the request we *could* assume this would be done during - * post-processing - but it's possible that another handler might be - * called and inherit our outstanding timer. Not good; to each its own. - */ - /* - * We did what we wanted to do, so tell the rest of the server we - * succeeded. - */ - return OK; -} - -/*--------------------------------------------------------------------------*/ -/* */ -/* Now let's declare routines for each of the callback phase in order. */ -/* (That's the order in which they're listed in the callback list, *not */ -/* the order in which the server calls them! See the command_rec */ -/* declaration near the bottom of this file.) Note that these may be */ -/* called for situations that don't relate primarily to our function - in */ -/* other words, the fixup handler shouldn't assume that the request has */ -/* to do with "example" stuff. */ -/* */ -/* With the exception of the content handler, all of our routines will be */ -/* called for each request, unless an earlier handler from another module */ -/* aborted the sequence. */ -/* */ -/* Handlers that are declared as "int" can return the following: */ -/* */ -/* OK Handler accepted the request and did its thing with it. */ -/* DECLINED Handler took no action. */ -/* HTTP_mumble Handler looked at request and found it wanting. */ -/* */ -/* What the server does after calling a module handler depends upon the */ -/* handler's return value. In all cases, if the handler returns */ -/* DECLINED, the server will continue to the next module with an handler */ -/* for the current phase. However, if the handler return a non-OK, */ -/* non-DECLINED status, the server aborts the request right there. If */ -/* the handler returns OK, the server's next action is phase-specific; */ -/* see the individual handler comments below for details. */ -/* */ -/*--------------------------------------------------------------------------*/ -/* - * This function is called during server initialisation. Any information - * that needs to be recorded must be in static cells, since there's no - * configuration record. - * - * There is no return value. - */ - -/* - * All our module initialiser does is add its trace to the log. - */ -static void example_init(apr_pool_t *p, apr_pool_t *ptemp, - apr_pool_t *plog, server_rec *s) -{ - - char *note; - char *sname = s->server_hostname; - - /* - * Set up any module cells that ought to be initialised. - */ - setup_module_cells(); - /* - * The arbitrary text we add to our trace entry indicates for which server - * we're being called. - */ - sname = (sname != NULL) ? sname : ""; - note = apr_pstrcat(p, "example_init(", sname, ")", NULL); - trace_add(s, NULL, NULL, note); -} - -/* - * This function is called when an heavy-weight process (such as a child) is - * being run down or destroyed. As with the child initialisation function, - * any information that needs to be recorded must be in static cells, since - * there's no configuration record. - * - * There is no return value. - */ - -/* - * All our process-death routine does is add its trace to the log. - */ -static apr_status_t example_child_exit(void *sv) -{ - server_rec *s = sv; - char *note; - char *sname = s->server_hostname; - - /* - * The arbitrary text we add to our trace entry indicates for which server - * we're being called. - */ - sname = (sname != NULL) ? sname : ""; - note = apr_pstrcat(s->process->pool, "example_child_exit(", sname, ")", NULL); - trace_add(s, NULL, NULL, note); - return APR_SUCCESS; -} - -/* - * This function is called during server initialisation when an heavy-weight - * process (such as a child) is being initialised. As with the - * module initialisation function, any information that needs to be recorded - * must be in static cells, since there's no configuration record. - * - * There is no return value. - */ - -/* - * All our process initialiser does is add its trace to the log. - */ -static void example_child_init(apr_pool_t *p, server_rec *s) -{ - - char *note; - char *sname = s->server_hostname; - - /* - * Set up any module cells that ought to be initialised. - */ - setup_module_cells(); - /* - * The arbitrary text we add to our trace entry indicates for which server - * we're being called. - */ - sname = (sname != NULL) ? sname : ""; - note = apr_pstrcat(p, "example_child_init(", sname, ")", NULL); - trace_add(s, NULL, NULL, note); - - apr_pool_cleanup_register(p, s, example_child_exit, example_child_exit); -} - -/* - * This function gets called to create a per-directory configuration - * record. This will be called for the "default" server environment, and for - * each directory for which the parser finds any of our directives applicable. - * If a directory doesn't have any of our directives involved (i.e., they - * aren't in the .htaccess file, or a <Location>, <Directory>, or related - * block), this routine will *not* be called - the configuration for the - * closest ancestor is used. - * - * The return value is a pointer to the created module-specific - * structure. - */ -static void *example_create_dir_config(apr_pool_t *p, char *dirspec) -{ - - excfg *cfg; - char *dname = dirspec; - - /* - * Allocate the space for our record from the pool supplied. - */ - cfg = (excfg *) apr_pcalloc(p, sizeof(excfg)); - /* - * Now fill in the defaults. If there are any `parent' configuration - * records, they'll get merged as part of a separate callback. - */ - cfg->local = 0; - cfg->congenital = 0; - cfg->cmode = CONFIG_MODE_DIRECTORY; - /* - * Finally, add our trace to the callback list. - */ - dname = (dname != NULL) ? dname : ""; - cfg->loc = apr_pstrcat(p, "DIR(", dname, ")", NULL); - trace_add(NULL, NULL, cfg, "example_create_dir_config()"); - return (void *) cfg; -} - -/* - * This function gets called to merge two per-directory configuration - * records. This is typically done to cope with things like .htaccess files - * or <Location> directives for directories that are beneath one for which a - * configuration record was already created. The routine has the - * responsibility of creating a new record and merging the contents of the - * other two into it appropriately. If the module doesn't declare a merge - * routine, the record for the closest ancestor location (that has one) is - * used exclusively. - * - * The routine MUST NOT modify any of its arguments! - * - * The return value is a pointer to the created module-specific structure - * containing the merged values. - */ -static void *example_merge_dir_config(apr_pool_t *p, void *parent_conf, - void *newloc_conf) -{ - - excfg *merged_config = (excfg *) apr_pcalloc(p, sizeof(excfg)); - excfg *pconf = (excfg *) parent_conf; - excfg *nconf = (excfg *) newloc_conf; - char *note; - - /* - * Some things get copied directly from the more-specific record, rather - * than getting merged. - */ - merged_config->local = nconf->local; - merged_config->loc = apr_pstrdup(p, nconf->loc); - /* - * Others, like the setting of the `congenital' flag, get ORed in. The - * setting of that particular flag, for instance, is TRUE if it was ever - * true anywhere in the upstream configuration. - */ - merged_config->congenital = (pconf->congenital | pconf->local); - /* - * If we're merging records for two different types of environment (server - * and directory), mark the new record appropriately. Otherwise, inherit - * the current value. - */ - merged_config->cmode = - (pconf->cmode == nconf->cmode) ? pconf->cmode : CONFIG_MODE_COMBO; - /* - * Now just record our being called in the trace list. Include the - * locations we were asked to merge. - */ - note = apr_pstrcat(p, "example_merge_dir_config(\"", pconf->loc, "\",\"", - nconf->loc, "\")", NULL); - trace_add(NULL, NULL, merged_config, note); - return (void *) merged_config; -} - -/* - * This function gets called to create a per-server configuration - * record. It will always be called for the "default" server. - * - * The return value is a pointer to the created module-specific - * structure. - */ -static void *example_create_server_config(apr_pool_t *p, server_rec *s) -{ - - excfg *cfg; - char *sname = s->server_hostname; - - /* - * As with the example_create_dir_config() reoutine, we allocate and fill - * in an empty record. - */ - cfg = (excfg *) apr_pcalloc(p, sizeof(excfg)); - cfg->local = 0; - cfg->congenital = 0; - cfg->cmode = CONFIG_MODE_SERVER; - /* - * Note that we were called in the trace list. - */ - sname = (sname != NULL) ? sname : ""; - cfg->loc = apr_pstrcat(p, "SVR(", sname, ")", NULL); - trace_add(s, NULL, cfg, "example_create_server_config()"); - return (void *) cfg; -} - -/* - * This function gets called to merge two per-server configuration - * records. This is typically done to cope with things like virtual hosts and - * the default server configuration The routine has the responsibility of - * creating a new record and merging the contents of the other two into it - * appropriately. If the module doesn't declare a merge routine, the more - * specific existing record is used exclusively. - * - * The routine MUST NOT modify any of its arguments! - * - * The return value is a pointer to the created module-specific structure - * containing the merged values. - */ -static void *example_merge_server_config(apr_pool_t *p, void *server1_conf, - void *server2_conf) -{ - - excfg *merged_config = (excfg *) apr_pcalloc(p, sizeof(excfg)); - excfg *s1conf = (excfg *) server1_conf; - excfg *s2conf = (excfg *) server2_conf; - char *note; - - /* - * Our inheritance rules are our own, and part of our module's semantics. - * Basically, just note whence we came. - */ - merged_config->cmode = - (s1conf->cmode == s2conf->cmode) ? s1conf->cmode : CONFIG_MODE_COMBO; - merged_config->local = s2conf->local; - merged_config->congenital = (s1conf->congenital | s1conf->local); - merged_config->loc = apr_pstrdup(p, s2conf->loc); - /* - * Trace our call, including what we were asked to merge. - */ - note = apr_pstrcat(p, "example_merge_server_config(\"", s1conf->loc, "\",\"", - s2conf->loc, "\")", NULL); - trace_add(NULL, NULL, merged_config, note); - return (void *) merged_config; -} - -/* - * This routine is called after the request has been read but before any other - * phases have been processed. This allows us to make decisions based upon - * the input header fields. - * - * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no - * further modules are called for this phase. - */ -static int example_post_read_request(request_rec *r) -{ - - excfg *cfg; - - cfg = our_dconfig(r); - /* - * We don't actually *do* anything here, except note the fact that we were - * called. - */ - trace_add(r->server, r, cfg, "example_post_read_request()"); - return DECLINED; -} - -/* - * This routine gives our module an opportunity to translate the URI into an - * actual filename. If we don't do anything special, the server's default - * rules (Alias directives and the like) will continue to be followed. - * - * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no - * further modules are called for this phase. - */ -static int example_translate_handler(request_rec *r) -{ - - excfg *cfg; - - cfg = our_dconfig(r); - /* - * We don't actually *do* anything here, except note the fact that we were - * called. - */ - trace_add(r->server, r, cfg, "example_translate_handler()"); - return DECLINED; -} - -/* - * This routine is called to check the authentication information sent with - * the request (such as looking up the user in a database and verifying that - * the [encrypted] password sent matches the one in the database). - * - * The return value is OK, DECLINED, or some HTTP_mumble error (typically - * HTTP_UNAUTHORIZED). If we return OK, no other modules are given a chance - * at the request during this phase. - */ -static int example_check_user_id(request_rec *r) -{ - - excfg *cfg; - - cfg = our_dconfig(r); - /* - * Don't do anything except log the call. - */ - trace_add(r->server, r, cfg, "example_check_user_id()"); - return DECLINED; -} - -/* - * This routine is called to check to see if the resource being requested - * requires authorisation. - * - * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no - * other modules are called during this phase. - * - * If *all* modules return DECLINED, the request is aborted with a server - * error. - */ -static int example_auth_checker(request_rec *r) -{ - - excfg *cfg; - - cfg = our_dconfig(r); - /* - * Log the call and return OK, or access will be denied (even though we - * didn't actually do anything). - */ - trace_add(r->server, r, cfg, "example_auth_checker()"); - return DECLINED; -} - -/* - * This routine is called to check for any module-specific restrictions placed - * upon the requested resource. (See the mod_access module for an example.) - * - * The return value is OK, DECLINED, or HTTP_mumble. All modules with an - * handler for this phase are called regardless of whether their predecessors - * return OK or DECLINED. The first one to return any other status, however, - * will abort the sequence (and the request) as usual. - */ -static int example_access_checker(request_rec *r) -{ - - excfg *cfg; - - cfg = our_dconfig(r); - trace_add(r->server, r, cfg, "example_access_checker()"); - return DECLINED; -} - -/* - * This routine is called to determine and/or set the various document type - * information bits, like Content-type (via r->content_type), language, et - * cetera. - * - * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no - * further modules are given a chance at the request for this phase. - */ -static int example_type_checker(request_rec *r) -{ - - excfg *cfg; - - cfg = our_dconfig(r); - /* - * Log the call, but don't do anything else - and report truthfully that - * we didn't do anything. - */ - trace_add(r->server, r, cfg, "example_type_checker()"); - return DECLINED; -} - -/* - * This routine is called to perform any module-specific fixing of header - * fields, et cetera. It is invoked just before any content-handler. - * - * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, the - * server will still call any remaining modules with an handler for this - * phase. - */ -static int example_fixer_upper(request_rec *r) -{ - - excfg *cfg; - - cfg = our_dconfig(r); - /* - * Log the call and exit. - */ - trace_add(r->server, r, cfg, "example_fixer_upper()"); - return OK; -} - -/* - * This routine is called to perform any module-specific logging activities - * over and above the normal server things. - * - * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, any - * remaining modules with an handler for this phase will still be called. - */ -static int example_logger(request_rec *r) -{ - - excfg *cfg; - - cfg = our_dconfig(r); - trace_add(r->server, r, cfg, "example_logger()"); - return DECLINED; -} - -/* - * This routine is called to give the module a chance to look at the request - * headers and take any appropriate specific actions early in the processing - * sequence. - * - * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, any - * remaining modules with handlers for this phase will still be called. - */ -static int example_header_parser(request_rec *r) -{ - - excfg *cfg; - - cfg = our_dconfig(r); - trace_add(r->server, r, cfg, "example_header_parser()"); - return DECLINED; -} - -/*--------------------------------------------------------------------------*/ -/* */ -/* Which functions are responsible for which hooks in the server. */ -/* */ -/*--------------------------------------------------------------------------*/ -/* - * Each function our module provides to handle a particular hook is - * specified here. The functions are registered using - * ap_hook_foo(name, predecessors, successors, position) - * where foo is the name of the hook. - * - * The args are as follows: - * name -> the name of the function to call. - * predecessors -> a list of modules whose calls to this hook must come - * before this module. - * successors -> a list of modules whose calls to this hook must come - * after this module. - * position -> The relative position of this module. One of APR_HOOK_FIRST, - * APR_HOOK_MIDDLE, or APR_HOOK_LAST. Most modules will use - * APR_HOOK_MIDDLE. If multiple modules use the same relative - * position, Apache will determine which to call first. - * If your module relies on another module to run first, - * or another module running after yours, use the - * predecessors and/or successors. - * - * The number in brackets indicates the order in which the routine is called - * during request processing. Note that not all routines are necessarily - * called (such as if a resource doesn't have access restrictions). - * The actual delivery of content to the browser [9] is not handled by - * a hook; see the handler declarations below. - */ -static void example_register_hooks(apr_pool_t *p) -{ - /* module initializer */ - ap_hook_post_config(example_init, - NULL, NULL, APR_HOOK_MIDDLE); - /* [1] post read_request handling */ - ap_hook_post_read_request(example_post_read_request, - NULL, NULL, APR_HOOK_MIDDLE); - /* [2] filename-to-URI translation */ - ap_hook_translate_name(example_translate_handler, - NULL, NULL, APR_HOOK_MIDDLE); - /* [3] header parser */ - ap_hook_header_parser(example_header_parser, - NULL, NULL, APR_HOOK_MIDDLE); - /* [4] check access by host address */ - ap_hook_access_checker(example_access_checker, - NULL, NULL, APR_HOOK_MIDDLE); - /* [5] check/validate user_id */ - ap_hook_check_user_id(example_check_user_id, - NULL, NULL, APR_HOOK_MIDDLE); - /* [6] check user_id is valid *here* */ - ap_hook_auth_checker(example_auth_checker, - NULL, NULL, APR_HOOK_MIDDLE); - /* [7] MIME type checker/setter */ - ap_hook_type_checker(example_type_checker, - NULL, NULL, APR_HOOK_MIDDLE); - /* [8] fixups */ - ap_hook_fixups(example_fixer_upper, - NULL, NULL, APR_HOOK_MIDDLE); - /* [9] is for the handlers; see below */ - - /* [10] logger */ - ap_hook_log_transaction(example_logger, - NULL, NULL, APR_HOOK_MIDDLE); - /* process initializer */ - ap_hook_child_init(example_child_init, - NULL, NULL, APR_HOOK_MIDDLE); -} - -/*--------------------------------------------------------------------------*/ -/* */ -/* All of the routines have been declared now. Here's the list of */ -/* directives specific to our module, and information about where they */ -/* may appear and how the command parser should pass them to us for */ -/* processing. Note that care must be taken to ensure that there are NO */ -/* collisions of directive names between modules. */ -/* */ -/*--------------------------------------------------------------------------*/ -/* - * List of directives specific to our module. - */ -static const command_rec example_cmds[] = -{ - AP_INIT_NO_ARGS( - "Example", /* directive name */ - cmd_example, /* config action routine */ - NULL, /* argument to include in call */ - OR_OPTIONS, /* where available */ - "Example directive - no arguments" /* directive description */ - ), - {NULL} -}; - -/*--------------------------------------------------------------------------*/ -/* */ -/* Now the list of content handlers available from this module. */ -/* */ -/*--------------------------------------------------------------------------*/ -/* - * List of content handlers our module supplies. Each handler is defined by - * two parts: a name by which it can be referenced (such as by - * {Add,Set}Handler), and the actual routine name. The list is terminated by - * a NULL block, since it can be of variable length. - * - * Note that content-handlers are invoked on a most-specific to least-specific - * basis; that is, a handler that is declared for "text/plain" will be - * invoked before one that was declared for "text / *". Note also that - * if a content-handler returns anything except DECLINED, no other - * content-handlers will be called. - */ -static const handler_rec example_handlers[] = -{ - {"example-handler", example_handler}, - {NULL} -}; - -/*--------------------------------------------------------------------------*/ -/* */ -/* Finally, the list of callback routines and data structures that provide */ -/* the static hooks into our module from the other parts of the server. */ -/* */ -/*--------------------------------------------------------------------------*/ -/* - * Module definition for configuration. If a particular callback is not - * needed, replace its routine name below with the word NULL. - */ -module example_module = -{ - STANDARD20_MODULE_STUFF, - example_create_dir_config, /* per-directory config creator */ - example_merge_dir_config, /* dir config merger */ - example_create_server_config, /* server config creator */ - example_merge_server_config, /* server config merger */ - example_cmds, /* command table */ - example_handlers, /* list of content delivery handlers */ - example_register_hooks, /* set up other request processing hooks */ -}; diff --git a/modules/experimental/mod_ext_filter.c b/modules/experimental/mod_ext_filter.c deleted file mode 100644 index 46b4b1e527..0000000000 --- a/modules/experimental/mod_ext_filter.c +++ /dev/null @@ -1,793 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_ext_filter allows Unix-style filters to filter http content. - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#define CORE_PRIVATE -#include "http_core.h" -#include "apr_buckets.h" -#include "util_filter.h" -#include "apr_strings.h" -#include "apr_hash.h" -#include "apr_lib.h" -#define APR_WANT_STRFUNC -#include "apr_want.h" - -typedef struct ef_server_t { - apr_pool_t *p; - apr_hash_t *h; -} ef_server_t; - -typedef struct ef_filter_t { - const char *name; - enum {INPUT_FILTER=1, OUTPUT_FILTER} mode; - const char *command; - int numArgs; - char *args[30]; - const char *intype; /* list of IMTs we process (well, just one for now) */ -#define INTYPE_ALL (char *)1 - const char *outtype; /* IMT of filtered output */ -#define OUTTYPE_UNCHANGED (char *)1 - int preserves_content_length; -} ef_filter_t; - -typedef struct ef_dir_t { - int debug; - int log_stderr; -} ef_dir_t; - -typedef struct ef_ctx_t { - apr_pool_t *p; - apr_proc_t *proc; - apr_procattr_t *procattr; - ef_dir_t *dc; - ef_filter_t *filter; - int noop; -#if APR_FILES_AS_SOCKETS - apr_pollfd_t *pollset; -#endif -} ef_ctx_t; - -module ext_filter_module; - -static apr_status_t ef_output_filter(ap_filter_t *, apr_bucket_brigade *); - -#define DBGLVL_SHOWOPTIONS 1 -#define DBGLVL_GORY 9 - -static void *create_ef_dir_conf(apr_pool_t *p, char *dummy) -{ - ef_dir_t *dc = (ef_dir_t *)apr_pcalloc(p, sizeof(ef_dir_t)); - - dc->debug = -1; - dc->log_stderr = -1; - - return dc; -} - -static void *create_ef_server_conf(apr_pool_t *p, server_rec *s) -{ - ef_server_t *conf; - - conf = (ef_server_t *)apr_pcalloc(p, sizeof(ef_server_t)); - conf->p = p; - conf->h = apr_hash_make(conf->p); - return conf; -} - -static void *merge_ef_dir_conf(apr_pool_t *p, void *basev, void *overridesv) -{ - ef_dir_t *a = (ef_dir_t *)apr_pcalloc (p, sizeof(ef_dir_t)); - ef_dir_t *base = (ef_dir_t *)basev, *over = (ef_dir_t *)overridesv; - - if (over->debug != -1) { /* if admin coded something... */ - a->debug = over->debug; - } - else { - a->debug = base->debug; - } - - if (over->log_stderr != -1) { /* if admin coded something... */ - a->log_stderr = over->log_stderr; - } - else { - a->log_stderr = base->log_stderr; - } - - return a; -} - -static const char *add_options(cmd_parms *cmd, void *in_dc, - const char *arg) -{ - ef_dir_t *dc = in_dc; - - if (!strncasecmp(arg, "DebugLevel=", 11)) { - dc->debug = atoi(arg + 11); - } - else if (!strcasecmp(arg, "LogStderr")) { - dc->log_stderr = 1; - } - else if (!strcasecmp(arg, "NoLogStderr")) { - dc->log_stderr = 0; - } - else { - return apr_pstrcat(cmd->temp_pool, - "Invalid ExtFilterOptions option: ", - arg, - NULL); - } - - return NULL; -} - -static const char *parse_cmd(apr_pool_t *p, const char **args, ef_filter_t *filter) -{ - if (**args == '"') { - const char *start = *args + 1; - char *parms; - - ++*args; /* move past leading " */ - while (**args && **args != '"') { - ++*args; - } - if (**args != '"') { - return "Expected cmd= delimiter"; - } - parms = apr_pstrndup(p, start, *args - start); - ++*args; /* move past trailing " */ - - /* parms now has the command-line to parse */ - while (filter->numArgs < 30 && - strlen(filter->args[filter->numArgs] = ap_getword_white_nc(p, &parms))) { - ++filter->numArgs; - } - if (filter->numArgs < 1) { - return "cmd= parse error"; - } - filter->args[filter->numArgs] = NULL; /* we stored "" in the while() loop */ - filter->command = filter->args[0]; - } - else - { - /* simple path */ - filter->args[0] = ap_getword_white(p, args); - if (!filter->args[0]) { - return "Invalid cmd= parameter"; - } - filter->numArgs = 1; - filter->command = filter->args[0]; - } - return NULL; -} - -static const char *define_filter(cmd_parms *cmd, void *dummy, const char *args) -{ - ef_server_t *conf = ap_get_module_config(cmd->server->module_config, - &ext_filter_module); - const char *token; - const char *name; - ef_filter_t *filter; - - name = ap_getword_white(cmd->pool, &args); - if (!name) { - return "Filter name not found"; - } - - if (apr_hash_get(conf->h, name, APR_HASH_KEY_STRING)) { - return apr_psprintf(cmd->pool, "ExtFilter %s is already defined", - name); - } - - filter = (ef_filter_t *)apr_pcalloc(conf->p, sizeof(ef_filter_t)); - filter->name = name; - filter->mode = OUTPUT_FILTER; - apr_hash_set(conf->h, name, APR_HASH_KEY_STRING, filter); - - while (*args) { - while (apr_isspace(*args)) { - ++args; - } - - /* Nasty parsing... I wish I could simply use ap_getword_white() - * here and then look at the token, but ap_getword_white() doesn't - * do the right thing when we have cmd="word word word" - */ - if (!strncasecmp(args, "preservescontentlength", 22)) { - token = ap_getword_white(cmd->pool, &args); - if (!strcasecmp(token, "preservescontentlength")) { - filter->preserves_content_length = 1; - } - else { - return apr_psprintf(cmd->pool, - "mangled argument `%s'", - token); - } - continue; - } - - if (!strncasecmp(args, "mode=", 5)) { - args += 5; - token = ap_getword_white(cmd->pool, &args); - if (!strcasecmp(token, "output")) { - filter->mode = OUTPUT_FILTER; - } - else if (!strcasecmp(token, "input")) { - filter->mode = INPUT_FILTER; - } - else { - return apr_psprintf(cmd->pool, "Invalid mode: `%s'", - token); - } - continue; - } - - if (!strncasecmp(args, "intype=", 7)) { - args += 7; - filter->intype = ap_getword_white(cmd->pool, &args); - continue; - } - - if (!strncasecmp(args, "outtype=", 8)) { - args += 8; - filter->outtype = ap_getword_white(cmd->pool, &args); - continue; - } - - if (!strncasecmp(args, "cmd=", 4)) { - args += 4; - if ((token = parse_cmd(cmd->pool, &args, filter))) { - return token; - } - continue; - } - - return apr_psprintf(cmd->pool, "Unexpected parameter: `%s'", - args); - } - - /* parsing is done... register the filter - */ - if (filter->mode == OUTPUT_FILTER) { - /* XXX need a way to ensure uniqueness among all filters */ - ap_register_output_filter(filter->name, ef_output_filter, AP_FTYPE_CONTENT); - } -#if 0 /* no input filters yet */ - else if (filter->mode == INPUT_FILTER) { - /* XXX need a way to ensure uniqueness among all filters */ - ap_register_input_filter(filter->name, ef_input_filter, AP_FTYPE_CONTENT); - } -#endif - else { - ap_assert(1 != 1); /* we set the field wrong somehow */ - } - - return NULL; -} - -static const command_rec cmds[] = -{ - AP_INIT_ITERATE("ExtFilterOptions", - add_options, - NULL, - ACCESS_CONF, /* same as SetInputFilter/SetOutputFilter */ - "valid options: DebugLevel=n, LogStderr, NoLogStderr"), - AP_INIT_RAW_ARGS("ExtFilterDefine", - define_filter, - NULL, - RSRC_CONF, - "Define an external filter"), - {NULL} -}; - -static apr_status_t set_resource_limits(request_rec *r, - apr_procattr_t *procattr) -{ -#if defined(RLIMIT_CPU) || defined(RLIMIT_NPROC) || \ - defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined (RLIMIT_AS) - core_dir_config *conf = - (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - apr_status_t rv; - -#ifdef RLIMIT_CPU - rv = apr_procattr_limit_set(procattr, APR_LIMIT_CPU, conf->limit_cpu); - ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */ -#endif -#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) - rv = apr_procattr_limit_set(procattr, APR_LIMIT_MEM, conf->limit_mem); - ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */ -#endif -#ifdef RLIMIT_NPROC - rv = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC, conf->limit_nproc); - ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */ -#endif - -#endif /* if at least one limit defined */ - - return APR_SUCCESS; -} - -static apr_status_t ef_close_file(void *vfile) -{ - return apr_file_close(vfile); -} - -/* init_ext_filter_process: get the external filter process going - * This is per-filter-instance (i.e., per-request) initialization. - */ -static apr_status_t init_ext_filter_process(ap_filter_t *f) -{ - ef_ctx_t *ctx = f->ctx; - apr_status_t rc; - ef_dir_t *dc = ctx->dc; - - ctx->proc = apr_pcalloc(ctx->p, sizeof(*ctx->proc)); - - rc = apr_procattr_create(&ctx->procattr, ctx->p); - ap_assert(rc == APR_SUCCESS); - - rc = apr_procattr_io_set(ctx->procattr, - APR_CHILD_BLOCK, - APR_CHILD_BLOCK, - APR_CHILD_BLOCK); - ap_assert(rc == APR_SUCCESS); - - rc = set_resource_limits(f->r, ctx->procattr); - ap_assert(rc == APR_SUCCESS); - - if (dc->log_stderr > 0) { - rc = apr_procattr_child_err_set(ctx->procattr, - f->r->server->error_log, /* stderr in child */ - NULL); - ap_assert(rc == APR_SUCCESS); - } - - rc = apr_proc_create(ctx->proc, - ctx->filter->command, - (const char * const *)ctx->filter->args, - NULL, /* environment */ - ctx->procattr, - ctx->p); - if (rc != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, f->r, - "couldn't create child process to run `%s'", - ctx->filter->command); - return rc; - } - - apr_pool_note_subprocess(ctx->p, ctx->proc, kill_after_timeout); - - /* We don't want the handle to the child's stdin inherited by any - * other processes created by httpd. Otherwise, when we close our - * handle, the child won't see EOF because another handle will still - * be open. - */ - - apr_pool_cleanup_register(ctx->p, ctx->proc->in, - apr_pool_cleanup_null, /* other mechanism */ - ef_close_file); - -#if APR_FILES_AS_SOCKETS - { - apr_socket_t *newsock; - - rc = apr_poll_setup(&ctx->pollset, 2, ctx->p); - ap_assert(rc == APR_SUCCESS); - rc = apr_socket_from_file(&newsock, ctx->proc->in); - ap_assert(rc == APR_SUCCESS); - rc = apr_poll_socket_add(ctx->pollset, newsock, APR_POLLOUT); - ap_assert(rc == APR_SUCCESS); - rc = apr_socket_from_file(&newsock, ctx->proc->out); - ap_assert(rc == APR_SUCCESS); - rc = apr_poll_socket_add(ctx->pollset, newsock, APR_POLLIN); - ap_assert(rc == APR_SUCCESS); - } -#endif - - return APR_SUCCESS; -} - -static const char *get_cfg_string(ef_dir_t *dc, ef_filter_t *filter, apr_pool_t *p) -{ - const char *debug_str = dc->debug == -1 ? - "DebugLevel=0" : apr_psprintf(p, "DebugLevel=%d", dc->debug); - const char *log_stderr_str = dc->log_stderr < 1 ? - "NoLogStderr" : "LogStderr"; - const char *preserve_content_length_str = filter->preserves_content_length ? - "PreservesContentLength" : "!PreserveContentLength"; - const char *intype_str = !filter->intype ? - "*/*" : filter->intype; - const char *outtype_str = !filter->outtype ? - "(unchanged)" : filter->outtype; - - return apr_psprintf(p, - "ExtFilterOptions %s %s %s ExtFilterInType %s " - "ExtFilterOuttype %s", - debug_str, log_stderr_str, preserve_content_length_str, - intype_str, outtype_str); -} - -static apr_status_t init_filter_instance(ap_filter_t *f) -{ - ef_ctx_t *ctx; - ef_dir_t *dc; - ef_server_t *sc; - apr_status_t rv; - - f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(ef_ctx_t)); - dc = ap_get_module_config(f->r->per_dir_config, - &ext_filter_module); - sc = ap_get_module_config(f->r->server->module_config, - &ext_filter_module); - ctx->dc = dc; - /* look for the user-defined filter */ - ctx->filter = apr_hash_get(sc->h, f->frec->name, APR_HASH_KEY_STRING); - if (!ctx->filter) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r, - "couldn't find definition of filter '%s'", - f->frec->name); - return APR_EINVAL; - } - ctx->p = f->r->pool; - if (ctx->filter->intype && - ctx->filter->intype != INTYPE_ALL && - strcasecmp(ctx->filter->intype, f->r->content_type)) { - /* wrong IMT for us; don't mess with the output */ - ctx->noop = 1; - } - else { - rv = init_ext_filter_process(f); - if (rv != APR_SUCCESS) { - return rv; - } - if (ctx->filter->outtype && - ctx->filter->outtype != OUTTYPE_UNCHANGED) { - f->r->content_type = ctx->filter->outtype; - } - if (ctx->filter->preserves_content_length != 1) { - /* nasty, but needed to avoid confusing the browser - */ - apr_table_unset(f->r->headers_out, "Content-Length"); - } - } - - if (dc->debug >= DBGLVL_SHOWOPTIONS) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, f->r, - "%sfiltering `%s' through `%s', cfg %s", - ctx->noop ? "skipping: " : "", - f->r->uri ? f->r->uri : f->r->filename, - ctx->filter->command, - get_cfg_string(dc, ctx->filter, f->r->pool)); - } - - return APR_SUCCESS; -} - -/* drain_available_output(): - * - * if any data is available from the filter, read it and pass it - * to the next filter - */ -static apr_status_t drain_available_output(ap_filter_t *f) -{ - ef_ctx_t *ctx = f->ctx; - ef_dir_t *dc = ctx->dc; - apr_size_t len; - char buf[4096]; - apr_status_t rv; - apr_bucket_brigade *bb; - apr_bucket *b; - - while (1) { - len = sizeof(buf); - rv = apr_file_read(ctx->proc->out, - buf, - &len); - if ((rv && !APR_STATUS_IS_EAGAIN(rv)) || - dc->debug >= DBGLVL_GORY) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, f->r, - "apr_file_read(child output), len %" APR_SIZE_T_FMT, - !rv ? len : -1); - } - if (rv != APR_SUCCESS) { - return rv; - } - bb = apr_brigade_create(f->r->pool); - b = apr_bucket_transient_create(buf, len); - APR_BRIGADE_INSERT_TAIL(bb, b); - if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, - "ap_pass_brigade()"); - return rv; - } - } - /* we should never get here; if we do, a bogus error message would be - * the least of our problems - */ - return APR_ANONYMOUS; -} - -static apr_status_t pass_data_to_filter(ap_filter_t *f, const char *data, - apr_ssize_t len) -{ - ef_ctx_t *ctx = f->ctx; - ef_dir_t *dc = ctx->dc; - apr_status_t rv; - apr_size_t bytes_written = 0; - apr_size_t tmplen; - - do { - tmplen = len - bytes_written; - rv = apr_file_write(ctx->proc->in, - (const char *)data + bytes_written, - &tmplen); - bytes_written += tmplen; - if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, - "apr_file_write(child input), len %" APR_SIZE_T_FMT, - tmplen); - return rv; - } - if (APR_STATUS_IS_EAGAIN(rv)) { - /* XXX handle blocking conditions here... if we block, we need - * to read data from the child process and pass it down to the - * next filter! - */ - rv = drain_available_output(f); - if (APR_STATUS_IS_EAGAIN(rv)) { -#if APR_FILES_AS_SOCKETS - int num_events; - - rv = apr_poll(ctx->pollset, - &num_events, - f->r->server->timeout * APR_USEC_PER_SEC); - if (rv || dc->debug >= DBGLVL_GORY) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, - rv, f->r, "apr_poll()"); - } - if (rv != APR_SUCCESS && !APR_STATUS_IS_EINTR(rv)) { - /* some error such as APR_TIMEUP */ - return rv; - } -#else /* APR_FILES_AS_SOCKETS */ - /* Yuck... I'd really like to wait until I can read - * or write, but instead I have to sleep and try again - */ - apr_sleep(100000); /* 100 milliseconds */ - if (dc->debug >= DBGLVL_GORY) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, - 0, f->r, "apr_sleep()"); - } -#endif /* APR_FILES_AS_SOCKETS */ - } - else if (rv != APR_SUCCESS) { - return rv; - } - } - } while (bytes_written < len); - return rv; -} - -static apr_status_t ef_output_filter(ap_filter_t *f, apr_bucket_brigade *bb) -{ - ef_ctx_t *ctx = f->ctx; - apr_bucket *b; - ef_dir_t *dc; - apr_size_t len; - const char *data; - apr_status_t rv; - char buf[4096]; - apr_bucket *eos = NULL; - - if (!ctx) { - if ((rv = init_filter_instance(f)) != APR_SUCCESS) { - return rv; - } - ctx = f->ctx; - } - if (ctx->noop) { - ap_remove_output_filter(f); - return ap_pass_brigade(f->next, bb); - } - dc = ctx->dc; - - APR_BRIGADE_FOREACH(b, bb) { - - if (APR_BUCKET_IS_EOS(b)) { - eos = b; - break; - } - - rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ); - if (rv != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "apr_bucket_read()"); - return rv; - } - - if (len > 0 && - (rv = pass_data_to_filter(f, data, len)) != APR_SUCCESS) { - return rv; - } - } - - apr_brigade_destroy(bb); - - /* XXX What we *really* need to do once we've hit eos is create a pipe bucket - * from the child output pipe and pass down the pipe bucket + eos. - */ - if (eos) { - /* close the child's stdin to signal that no more data is coming; - * that will cause the child to finish generating output - */ - if ((rv = apr_file_close(ctx->proc->in)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, - "apr_file_close(child input)"); - return rv; - } - /* since we've seen eos and closed the child's stdin, set the proper pipe - * timeout; we don't care if we don't return from apr_file_read() for a while... - */ - rv = apr_file_pipe_timeout_set(ctx->proc->out, - f->r->server->timeout * APR_USEC_PER_SEC); - if (rv) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, - "apr_file_pipe_timeout_set(child output)"); - return rv; - } - } - - do { - len = sizeof(buf); - rv = apr_file_read(ctx->proc->out, - buf, - &len); - if ((rv && !APR_STATUS_IS_EOF(rv) && !APR_STATUS_IS_EAGAIN(rv)) || - dc->debug >= DBGLVL_GORY) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, f->r, - "apr_file_read(child output), len %" APR_SIZE_T_FMT, - !rv ? len : -1); - } - if (APR_STATUS_IS_EAGAIN(rv)) { - if (eos) { - /* should not occur, because we have an APR timeout in place */ - AP_DEBUG_ASSERT(1 != 1); - } - return APR_SUCCESS; - } - - if (rv == APR_SUCCESS) { - bb = apr_brigade_create(f->r->pool); - b = apr_bucket_transient_create(buf, len); - APR_BRIGADE_INSERT_TAIL(bb, b); - if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, - "ap_pass_brigade(filtered buffer) failed"); - return rv; - } - } - } while (rv == APR_SUCCESS); - - if (!APR_STATUS_IS_EOF(rv)) { - return rv; - } - - if (eos) { - /* pass down eos */ - bb = apr_brigade_create(f->r->pool); - b = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, - "ap_pass_brigade(eos) failed"); - return rv; - } - } - - return APR_SUCCESS; -} - -#if 0 -static int ef_input_filter(ap_filter_t *f, apr_bucket_brigade *bb, - ap_input_mode_t mode, apr_size_t *readbytes) -{ - apr_status_t rv; - apr_bucket *b; - char *buf; - apr_ssize_t len; - char *zero; - - rv = ap_get_brigade(f->next, bb, mode, readbytes); - if (rv != APR_SUCCESS) { - return rv; - } - - APR_BRIGADE_FOREACH(b, bb) { - if (!APR_BUCKET_IS_EOS(b)) { - if ((rv = apr_bucket_read(b, (const char **)&buf, &len, APR_BLOCK_READ)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "apr_bucket_read() failed"); - return rv; - } - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "apr_bucket_read -> %d bytes", - len); - while ((zero = memchr(buf, '0', len))) { - *zero = 'a'; - } - } - else - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "got eos bucket"); - } - - return rv; -} -#endif - -module ext_filter_module = -{ - STANDARD20_MODULE_STUFF, - create_ef_dir_conf, - merge_ef_dir_conf, - create_ef_server_conf, - NULL, - cmds, -}; diff --git a/modules/experimental/mod_generic_hook_export.c b/modules/experimental/mod_generic_hook_export.c deleted file mode 100644 index 38ee86815d..0000000000 --- a/modules/experimental/mod_generic_hook_export.c +++ /dev/null @@ -1,82 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "httpd.h" -#include "http_config.h" -#include "mod_generic_hook_export.h" -#include "http_protocol.h" - -APR_IMPLEMENT_GENERIC_HOOK_RUN_ALL(ap,AP_MODULE,int,generic_hook_test,(const char *szStr), - (szStr),OK,DECLINED) - -static int ExportLogTransaction(request_rec *r) -{ - return ap_run_generic_hook_test(r->the_request); -} - -static void ExportRegisterHooks(apr_pool_t *p) -{ - ap_hook_log_transaction(ExportLogTransaction,NULL,NULL,APR_HOOK_MIDDLE); -} - -module generic_hook_export_module = -{ - STANDARD20_MODULE_STUFF, - NULL, - NULL, - NULL, - NULL, - NULL, - ExportRegisterHooks -}; diff --git a/modules/experimental/mod_generic_hook_export.dsp b/modules/experimental/mod_generic_hook_export.dsp deleted file mode 100644 index 711a041565..0000000000 --- a/modules/experimental/mod_generic_hook_export.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_generic_hook_export" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_generic_hook_export - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_generic_hook_export.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_generic_hook_export.mak" CFG="mod_generic_hook_export - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_generic_hook_export - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_generic_hook_export - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_generic_hook_export - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_generic_hook_export" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_generic_hook_export.so" /machine:I386 -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_generic_hook_export.so" /machine:I386 - -!ELSEIF "$(CFG)" == "mod_generic_hook_export - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_generic_hook_export" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_generic_hook_export.so" /machine:I386 -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map/debug /out:"Debug/mod_generic_hook_export.so" /machine:I386 - -!ENDIF - -# Begin Target - -# Name "mod_generic_hook_export - Win32 Release" -# Name "mod_generic_hook_export - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_generic_hook_export.c -# End Source File -# End Target -# End Project diff --git a/modules/experimental/mod_generic_hook_export.h b/modules/experimental/mod_generic_hook_export.h deleted file mode 100644 index a55d2f227c..0000000000 --- a/modules/experimental/mod_generic_hook_export.h +++ /dev/null @@ -1,62 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef MOD_GENERIC_HOOK_EXPORT_H -#define MOD_GENERIC_HOOK_EXPORT_H - -#include "apr_generic_hook.h" - -APR_DECLARE_EXTERNAL_HOOK(ap,AP_MODULE,int,generic_hook_test,(const char *)) - -#endif /* def MOD_GENERIC_HOOK_EXPORT_H */ diff --git a/modules/experimental/mod_generic_hook_import.c b/modules/experimental/mod_generic_hook_import.c deleted file mode 100644 index f46fa44df5..0000000000 --- a/modules/experimental/mod_generic_hook_import.c +++ /dev/null @@ -1,83 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "mod_generic_hook_export.h" - -static int ImportGenericHookTestHook(const char *szStr) -{ - ap_log_error(APLOG_MARK,APLOG_ERR,OK,NULL,"Generic hook test said: %s", - szStr); - - return OK; -} - -static void ImportRegisterHooks(apr_pool_t *p) -{ - APR_HOOK_GENERIC(ap,generic_hook_test,ImportGenericHookTestHook,NULL,NULL, - APR_HOOK_MIDDLE); -} - -module generic_hook_import_module= -{ - STANDARD20_MODULE_STUFF, - NULL, - NULL, - NULL, - NULL, - NULL, - ImportRegisterHooks -}; diff --git a/modules/experimental/mod_generic_hook_import.dsp b/modules/experimental/mod_generic_hook_import.dsp deleted file mode 100644 index 78068294ab..0000000000 --- a/modules/experimental/mod_generic_hook_import.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_generic_hook_import" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_generic_hook_import - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_generic_hook_import.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_generic_hook_import.mak" CFG="mod_generic_hook_import - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_generic_hook_import - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_generic_hook_import - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_generic_hook_import - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_generic_hook_import" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_generic_hook_import.so" /machine:I386 -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_generic_hook_import.so" /machine:I386 - -!ELSEIF "$(CFG)" == "mod_generic_hook_import - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_generic_hook_import" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_generic_hook_import.so" /machine:I386 -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map/debug /out:"Debug/mod_generic_hook_import.so" /machine:I386 - -!ENDIF - -# Begin Target - -# Name "mod_generic_hook_import - Win32 Release" -# Name "mod_generic_hook_import - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_generic_hook_import.c -# End Source File -# End Target -# End Project diff --git a/modules/experimental/mod_optional_fn_export.c b/modules/experimental/mod_optional_fn_export.c deleted file mode 100644 index b214a36621..0000000000 --- a/modules/experimental/mod_optional_fn_export.c +++ /dev/null @@ -1,86 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "mod_optional_fn_export.h" - -/* The alert will note a strange mirror-image style resemblance to - * mod_generic_hook_import.c. Yes, I _did_ mean import. Think about it. - */ - -static int TestOptionalFn(const char *szStr) -{ - ap_log_error(APLOG_MARK,APLOG_ERR,OK,NULL, - "Optional function test said: %s",szStr); - - return OK; -} - -static void ExportRegisterHooks(apr_pool_t *p) -{ - APR_REGISTER_OPTIONAL_FN(TestOptionalFn); -} - -module optional_fn_export_module= -{ - STANDARD20_MODULE_STUFF, - NULL, - NULL, - NULL, - NULL, - NULL, - ExportRegisterHooks -}; diff --git a/modules/experimental/mod_optional_fn_export.h b/modules/experimental/mod_optional_fn_export.h deleted file mode 100644 index a1950f373b..0000000000 --- a/modules/experimental/mod_optional_fn_export.h +++ /dev/null @@ -1,3 +0,0 @@ -#include "apr_optional.h" - -APR_DECLARE_OPTIONAL_FN(int,TestOptionalFn,(const char *)); diff --git a/modules/experimental/mod_optional_fn_import.c b/modules/experimental/mod_optional_fn_import.c deleted file mode 100644 index 3be3b6be6d..0000000000 --- a/modules/experimental/mod_optional_fn_import.c +++ /dev/null @@ -1,93 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "httpd.h" -#include "http_config.h" -#include "mod_optional_fn_export.h" -#include "http_protocol.h" - -/* The alert will note a strange mirror-image style resemblance to - * mod_generic_hook_export.c. Yes, I _did_ mean export. Think about it. - */ - -static APR_OPTIONAL_FN_TYPE(TestOptionalFn) *pfn; - -static int ImportLogTransaction(request_rec *r) -{ - if(pfn) - return pfn(r->the_request); - return DECLINED; -} - -static void ImportFnRetrieve(void) -{ - pfn=APR_RETRIEVE_OPTIONAL_FN(TestOptionalFn); -} - -static void ImportRegisterHooks(apr_pool_t *p) -{ - ap_hook_log_transaction(ImportLogTransaction,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_optional_fn_retrieve(ImportFnRetrieve,NULL,NULL,APR_HOOK_MIDDLE); -} - -module optional_fn_import_module = -{ - STANDARD20_MODULE_STUFF, - NULL, - NULL, - NULL, - NULL, - NULL, - ImportRegisterHooks -}; diff --git a/modules/filters/.cvsignore b/modules/filters/.cvsignore deleted file mode 100644 index 65f0cc30cf..0000000000 --- a/modules/filters/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -.deps -.libs -*.la -modules.mk -Makefile -*.lo -*.slo -*.so -Debug -Release diff --git a/modules/filters/.indent.pro b/modules/filters/.indent.pro deleted file mode 100644 index a9fbe9f9a1..0000000000 --- a/modules/filters/.indent.pro +++ /dev/null @@ -1,54 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 --TBUFF --TFILE --TTRANS --TUINT4 --T_trans --Tallow_options_t --Tapache_sfio --Tarray_header --Tbool_int --Tbuf_area --Tbuff_struct --Tbuffy --Tcmd_how --Tcmd_parms --Tcommand_rec --Tcommand_struct --Tconn_rec --Tcore_dir_config --Tcore_server_config --Tdir_maker_func --Tevent --Tglobals_s --Thandler_func --Thandler_rec --Tjoblist_s --Tlisten_rec --Tmerger_func --Tmode_t --Tmodule --Tmodule_struct --Tmutex --Tn_long --Tother_child_rec --Toverrides_t --Tparent_score --Tpid_t --Tpiped_log --Tpool --Trequest_rec --Trequire_line --Trlim_t --Tscoreboard --Tsemaphore --Tserver_addr_rec --Tserver_rec --Tserver_rec_chain --Tshort_score --Ttable --Ttable_entry --Tthread --Tu_wide_int --Tvtime_t --Twide_int diff --git a/modules/filters/Makefile.in b/modules/filters/Makefile.in deleted file mode 100644 index 167b343d0d..0000000000 --- a/modules/filters/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ - -include $(top_srcdir)/build/special.mk - diff --git a/modules/filters/config.m4 b/modules/filters/config.m4 deleted file mode 100644 index 10fc0231ef..0000000000 --- a/modules/filters/config.m4 +++ /dev/null @@ -1,11 +0,0 @@ -dnl modules enabled in this directory by default - -dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]]) - -APACHE_MODPATH_INIT(filters) - -APACHE_MODULE(include, Server Side Includes, , , yes) - -APR_ADDTO(LTFLAGS,-export-dynamic) - -APACHE_MODPATH_FINISH diff --git a/modules/filters/mod_include.c b/modules/filters/mod_include.c deleted file mode 100644 index ff3a1af295..0000000000 --- a/modules/filters/mod_include.c +++ /dev/null @@ -1,2854 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_include.c: Handles the server-parsed HTML documents - * - * Original by Rob McCool; substantial fixups by David Robinson; - * incorporated into the Apache module framework by rst. - * - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_thread_proc.h" -#include "apr_hash.h" -#include "apr_user.h" -#include "apr_lib.h" -#include "apr_optional.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#define CORE_PRIVATE - -#include "ap_config.h" -#include "util_filter.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_request.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_log.h" -#include "http_main.h" -#include "util_script.h" -#include "http_core.h" -#include "mod_include.h" -#include "util_ebcdic.h" - -module AP_MODULE_DECLARE_DATA include_module; -static apr_hash_t *include_hash; -static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *ssi_pfn_register; - -#define BYTE_COUNT_THRESHOLD AP_MIN_BYTES_TO_WRITE - -/* ------------------------ Environment function -------------------------- */ - -/* XXX: could use ap_table_overlap here */ -static void add_include_vars(request_rec *r, char *timefmt) -{ - char *pwname; - apr_table_t *e = r->subprocess_env; - char *t; - apr_time_t date = r->request_time; - - apr_table_setn(e, "DATE_LOCAL", ap_ht_time(r->pool, date, timefmt, 0)); - apr_table_setn(e, "DATE_GMT", ap_ht_time(r->pool, date, timefmt, 1)); - apr_table_setn(e, "LAST_MODIFIED", - ap_ht_time(r->pool, r->finfo.mtime, timefmt, 0)); - apr_table_setn(e, "DOCUMENT_URI", r->uri); - apr_table_setn(e, "DOCUMENT_PATH_INFO", r->path_info); - if (apr_get_username(&pwname, r->finfo.user, r->pool) == APR_SUCCESS) { - apr_table_setn(e, "USER_NAME", pwname); - } - else { - apr_table_setn(e, "USER_NAME", "<unknown>"); - } - if ((t = strrchr(r->filename, '/'))) { - apr_table_setn(e, "DOCUMENT_NAME", ++t); - } - else { - apr_table_setn(e, "DOCUMENT_NAME", r->uri); - } - if (r->args) { - char *arg_copy = apr_pstrdup(r->pool, r->args); - - ap_unescape_url(arg_copy); - apr_table_setn(e, "QUERY_STRING_UNESCAPED", - ap_escape_shell_cmd(r->pool, arg_copy)); - } -} - - - -/* --------------------------- Parser functions --------------------------- */ - -/* This function returns either a pointer to the split bucket containing the - * first byte of the BEGINNING_SEQUENCE (after finding a complete match) or it - * returns NULL if no match found. - */ -static apr_bucket *find_start_sequence(apr_bucket *dptr, include_ctx_t *ctx, - apr_bucket_brigade *bb, int *do_cleanup) -{ - apr_size_t len; - const char *c; - const char *buf; - const char *str = STARTING_SEQUENCE; - apr_bucket *tmp_bkt; - apr_size_t start_index; - - *do_cleanup = 0; - - do { - if (APR_BUCKET_IS_EOS(dptr)) { - break; - } - apr_bucket_read(dptr, &buf, &len, APR_BLOCK_READ); - /* XXX handle retcodes */ - if (len == 0) { /* end of pipe? */ - break; - } - c = buf; - while (c - buf != len) { - if (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD) { - apr_bucket *start_bucket; - - if (ctx->head_start_index > 0) { - start_index = ctx->head_start_index; - start_bucket = ctx->head_start_bucket; - } - else { - start_index = (c - buf); - start_bucket = dptr; - } - apr_bucket_split(start_bucket, start_index); - tmp_bkt = APR_BUCKET_NEXT(start_bucket); - if (ctx->head_start_index > 0) { - ctx->head_start_index = 0; - ctx->head_start_bucket = tmp_bkt; - } - - return tmp_bkt; - } - - if (*c == str[ctx->parse_pos]) { - if (ctx->state == PRE_HEAD) { - ctx->state = PARSE_HEAD; - ctx->head_start_bucket = dptr; - ctx->head_start_index = c - buf; - } - ctx->parse_pos++; - } - else { - if (str[ctx->parse_pos] == '\0') { - /* We want to split the bucket at the '<'. */ - ctx->bytes_parsed++; - ctx->state = PARSE_DIRECTIVE; - ctx->tag_length = 0; - ctx->parse_pos = 0; - ctx->tag_start_bucket = dptr; - ctx->tag_start_index = c - buf; - if (ctx->head_start_index > 0) { - start_index = (c - buf) - ctx->head_start_index; - apr_bucket_split(ctx->head_start_bucket, ctx->head_start_index); - tmp_bkt = APR_BUCKET_NEXT(ctx->head_start_bucket); - if (dptr == ctx->head_start_bucket) { - ctx->tag_start_bucket = tmp_bkt; - ctx->tag_start_index = start_index; - } - ctx->head_start_bucket = tmp_bkt; - ctx->head_start_index = 0; - } - return ctx->head_start_bucket; - } - else if (ctx->parse_pos != 0) { - /* The reason for this, is that we need to make sure - * that we catch cases like <<!--#. This makes the - * second check after the original check fails. - * If parse_pos was already 0 then we already checked this. - */ - *do_cleanup = 1; - if (*c == str[0]) { - ctx->parse_pos = 1; - ctx->state = PARSE_HEAD; - ctx->head_start_bucket = dptr; - ctx->head_start_index = c - buf; - } - else { - ctx->parse_pos = 0; - ctx->state = PRE_HEAD; - ctx->head_start_bucket = NULL; - ctx->head_start_index = 0; - } - } - } - c++; - ctx->bytes_parsed++; - } - dptr = APR_BUCKET_NEXT(dptr); - } while (dptr != APR_BRIGADE_SENTINEL(bb)); - return NULL; -} - -static apr_bucket *find_end_sequence(apr_bucket *dptr, include_ctx_t *ctx, apr_bucket_brigade *bb) -{ - apr_size_t len; - const char *c; - const char *buf; - const char *str = ENDING_SEQUENCE; - - do { - if (APR_BUCKET_IS_EOS(dptr)) { - break; - } - apr_bucket_read(dptr, &buf, &len, APR_BLOCK_READ); - /* XXX handle retcodes */ - if (len == 0) { /* end of pipe? */ - break; - } - if (dptr == ctx->tag_start_bucket) { - c = buf + ctx->tag_start_index; - } - else { - c = buf; - } - while (c - buf != len) { - if (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD) { - return dptr; - } - - if (*c == str[ctx->parse_pos]) { - if (ctx->state != PARSE_TAIL) { - ctx->state = PARSE_TAIL; - ctx->tail_start_bucket = dptr; - ctx->tail_start_index = c - buf; - } - ctx->parse_pos++; - } - else { - if (ctx->state == PARSE_DIRECTIVE) { - if (ctx->tag_length == 0) { - if (!apr_isspace(*c)) { - ctx->tag_start_bucket = dptr; - ctx->tag_start_index = c - buf; - ctx->tag_length = 1; - ctx->directive_length = 1; - } - } - else { - if (!apr_isspace(*c)) { - ctx->directive_length++; - } - else { - ctx->state = PARSE_TAG; - } - ctx->tag_length++; - } - } - else if (ctx->state == PARSE_TAG) { - ctx->tag_length++; - } - else { - if (str[ctx->parse_pos] == '\0') { - apr_bucket *tmp_buck = dptr; - - /* We want to split the bucket at the '>'. The - * end of the END_SEQUENCE is in the current bucket. - * The beginning might be in a previous bucket. - */ - ctx->bytes_parsed++; - ctx->state = PARSED; - if ((c - buf) > 0) { - apr_bucket_split(dptr, c - buf); - tmp_buck = APR_BUCKET_NEXT(dptr); - } - return (tmp_buck); - } - else if (ctx->parse_pos != 0) { - /* The reason for this, is that we need to make sure - * that we catch cases like --->. This makes the - * second check after the original check fails. - * If parse_pos was already 0 then we already checked this. - */ - ctx->tag_length += ctx->parse_pos; - - if (*c == str[0]) { - ctx->state = PARSE_TAIL; - ctx->tail_start_bucket = dptr; - ctx->tail_start_index = c - buf; - ctx->tag_length += ctx->parse_pos; - ctx->parse_pos = 1; - } - else { - if (ctx->tag_length > ctx->directive_length) { - ctx->state = PARSE_TAG; - } - else { - ctx->state = PARSE_DIRECTIVE; - ctx->directive_length += ctx->parse_pos; - } - ctx->tail_start_bucket = NULL; - ctx->tail_start_index = 0; - ctx->tag_length += ctx->parse_pos; - ctx->parse_pos = 0; - } - } - } - } - c++; - ctx->bytes_parsed++; - } - dptr = APR_BUCKET_NEXT(dptr); - } while (dptr != APR_BRIGADE_SENTINEL(bb)); - return NULL; -} - -/* This function culls through the buckets that have been set aside in the - * ssi_tag_brigade and copies just the directive part of the SSI tag (none - * of the start and end delimiter bytes are copied). - */ -static apr_status_t get_combined_directive (include_ctx_t *ctx, - request_rec *r, - apr_bucket_brigade *bb, - char *tmp_buf, int tmp_buf_size) -{ - int done = 0; - apr_bucket *dptr; - const char *tmp_from; - apr_size_t tmp_from_len; - - /* If the tag length is longer than the tmp buffer, allocate space. */ - if (ctx->tag_length > tmp_buf_size-1) { - if ((ctx->combined_tag = apr_pcalloc(r->pool, ctx->tag_length + 1)) == NULL) { - return (APR_ENOMEM); - } - } /* Else, just use the temp buffer. */ - else { - ctx->combined_tag = tmp_buf; - } - - /* Prime the pump. Start at the beginning of the tag... */ - dptr = ctx->tag_start_bucket; - apr_bucket_read (dptr, &tmp_from, &tmp_from_len, 0); /* Read the bucket... */ - - /* Adjust the pointer to start at the tag within the bucket... */ - if (dptr == ctx->tail_start_bucket) { - tmp_from_len -= (tmp_from_len - ctx->tail_start_index); - } - tmp_from = &tmp_from[ctx->tag_start_index]; - tmp_from_len -= ctx->tag_start_index; - ctx->curr_tag_pos = ctx->combined_tag; - - /* Loop through the buckets from the tag_start_bucket until before - * the tail_start_bucket copying the contents into the buffer. - */ - do { - memcpy (ctx->curr_tag_pos, tmp_from, tmp_from_len); - ctx->curr_tag_pos += tmp_from_len; - - if (dptr == ctx->tail_start_bucket) { - done = 1; - } - else { - dptr = APR_BUCKET_NEXT (dptr); - apr_bucket_read (dptr, &tmp_from, &tmp_from_len, 0); - /* Adjust the count to stop at the beginning of the tail. */ - if (dptr == ctx->tail_start_bucket) { - tmp_from_len -= (tmp_from_len - ctx->tail_start_index); - } - } - } while ((!done) && - ((ctx->curr_tag_pos - ctx->combined_tag) < ctx->tag_length)); - - ctx->combined_tag[ctx->tag_length] = '\0'; - ctx->curr_tag_pos = ctx->combined_tag; - - return (APR_SUCCESS); -} - -/* - * decodes a string containing html entities or numeric character references. - * 's' is overwritten with the decoded string. - * If 's' is syntatically incorrect, then the followed fixups will be made: - * unknown entities will be left undecoded; - * references to unused numeric characters will be deleted. - * In particular, � will not be decoded, but will be deleted. - * - * drtr - */ - -/* maximum length of any ISO-LATIN-1 HTML entity name. */ -#define MAXENTLEN (6) - -/* The following is a shrinking transformation, therefore safe. */ - -static void decodehtml(char *s) -{ - int val, i, j; - char *p = s; - const char *ents; - static const char * const entlist[MAXENTLEN + 1] = - { - NULL, /* 0 */ - NULL, /* 1 */ - "lt\074gt\076", /* 2 */ - "amp\046ETH\320eth\360", /* 3 */ - "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml\353\ -iuml\357ouml\366uuml\374yuml\377", /* 4 */ - "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc\333\ -THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352icirc\356ocirc\364\ -ucirc\373thorn\376", /* 5 */ - "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311\ -Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde\325Oslash\330\ -Ugrave\331Uacute\332Yacute\335agrave\340aacute\341atilde\343ccedil\347\ -egrave\350eacute\351igrave\354iacute\355ntilde\361ograve\362oacute\363\ -otilde\365oslash\370ugrave\371uacute\372yacute\375" /* 6 */ - }; - - for (; *s != '\0'; s++, p++) { - if (*s != '&') { - *p = *s; - continue; - } - /* find end of entity */ - for (i = 1; s[i] != ';' && s[i] != '\0'; i++) { - continue; - } - - if (s[i] == '\0') { /* treat as normal data */ - *p = *s; - continue; - } - - /* is it numeric ? */ - if (s[1] == '#') { - for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) { - val = val * 10 + s[j] - '0'; - } - s += i; - if (j < i || val <= 8 || (val >= 11 && val <= 31) || - (val >= 127 && val <= 160) || val >= 256) { - p--; /* no data to output */ - } - else { - *p = RAW_ASCII_CHAR(val); - } - } - else { - j = i - 1; - if (j > MAXENTLEN || entlist[j] == NULL) { - /* wrong length */ - *p = '&'; - continue; /* skip it */ - } - for (ents = entlist[j]; *ents != '\0'; ents += i) { - if (strncmp(s + 1, ents, j) == 0) { - break; - } - } - - if (*ents == '\0') { - *p = '&'; /* unknown */ - } - else { - *p = RAW_ASCII_CHAR(((const unsigned char *) ents)[j]); - s += i; - } - } - } - - *p = '\0'; -} - -/* - * Extract the next tag name and value. - * If there are no more tags, set the tag name to NULL. - * The tag value is html decoded if dodecode is non-zero. - * The tag value may be NULL if there is no tag value.. - * format: - * [WS]<Tag>[WS]=[WS]['|"]<Value>['|"|WS] - */ - -#define SKIP_TAG_WHITESPACE(ptr) while ((*ptr != '\0') && (apr_isspace (*ptr))) ptr++ - -static void ap_ssi_get_tag_and_value(include_ctx_t *ctx, char **tag, - char **tag_val, int dodecode) -{ - char *c = ctx->curr_tag_pos; - int shift_val = 0; - char term = '\0'; - - *tag_val = NULL; - SKIP_TAG_WHITESPACE(c); - *tag = c; /* First non-whitespace character (could be NULL). */ - - while ((*c != '\0') && (*c != '=') && (!apr_isspace(*c))) { - *c = apr_tolower(*c); /* find end of tag, lowercasing as we go... */ - c++; - } - - if ((*c == '\0') || (**tag == '=')) { - if ((**tag == '\0') || (**tag == '=')) { - *tag = NULL; - } - ctx->curr_tag_pos = c; - return; /* We have found the end of the buffer. */ - } /* We might have a tag, but definitely no value. */ - - if (*c == '=') { - *c++ = '\0'; /* Overwrite the '=' with a terminating byte after tag. */ - } - else { /* Try skipping WS to find the '='. */ - *c++ = '\0'; /* Terminate the tag... */ - SKIP_TAG_WHITESPACE(c); - - if (*c != '=') { /* There needs to be an equal sign if there's a value. */ - ctx->curr_tag_pos = c; - return; /* There apparently was no value. */ - } - else { - c++; /* Skip the equals sign. */ - } - } - - SKIP_TAG_WHITESPACE(c); - if (*c == '"' || *c == '\'') { /* Allow quoted values for space inclusion. */ - term = *c++; /* NOTE: This does not pass the quotes on return. */ - } - - *tag_val = c; - while ((*c != '\0') && - (((term != '\0') && (*c != term)) || - ((term == '\0') && (!apr_isspace(*c))))) { - if (*c == '\\') { /* Accept \" and \' as valid char in string. */ - c++; - if (*c == term) { /* Overwrite the "\" during the embedded */ - shift_val++; /* escape sequence of '\"' or "\'". Shift */ - } /* bytes from here to next delimiter. */ - if (shift_val > 0) { - *(c-shift_val) = *c; - } - } - - c++; - if (shift_val > 0) { - *(c-shift_val) = *c; - } - } - - *c++ = '\0'; /* Overwrites delimiter (term or WS) with NULL. */ - ctx->curr_tag_pos = c; - if (dodecode) { - decodehtml(*tag_val); - } - - return; -} - - -/* - * Do variable substitution on strings - */ -static void ap_ssi_parse_string(request_rec *r, const char *in, char *out, - size_t length, int leave_name) -{ - char ch; - char *next = out; - char *end_out; - - /* leave room for nul terminator */ - end_out = out + length - 1; - - while ((ch = *in++) != '\0') { - switch (ch) { - case '\\': - if (next == end_out) { - /* truncated */ - *next = '\0'; - return; - } - if (*in == '$') { - *next++ = *in++; - } - else { - *next++ = ch; - } - break; - case '$': - { - const char *start_of_var_name; - char *end_of_var_name; /* end of var name + 1 */ - const char *expansion, *temp_end, *val; - char tmp_store; - size_t l; - - /* guess that the expansion won't happen */ - expansion = in - 1; - if (*in == '{') { - ++in; - start_of_var_name = in; - in = ap_strchr_c(in, '}'); - if (in == NULL) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, - 0, r, "Missing '}' on variable \"%s\"", - expansion); - *next = '\0'; - return; - } - temp_end = in; - end_of_var_name = (char *)temp_end; - ++in; - } - else { - start_of_var_name = in; - while (apr_isalnum(*in) || *in == '_') { - ++in; - } - temp_end = in; - end_of_var_name = (char *)temp_end; - } - /* what a pain, too bad there's no table_getn where you can - * pass a non-nul terminated string */ - l = end_of_var_name - start_of_var_name; - if (l != 0) { - tmp_store = *end_of_var_name; - *end_of_var_name = '\0'; - val = apr_table_get(r->subprocess_env, start_of_var_name); - *end_of_var_name = tmp_store; - - if (val) { - expansion = val; - l = strlen(expansion); - } - else if (leave_name) { - l = in - expansion; - } - else { - break; /* no expansion to be done */ - } - } - else { - /* zero-length variable name causes just the $ to be copied */ - l = 1; - } - l = ((int)l > end_out - next) ? (end_out - next) : l; - memcpy(next, expansion, l); - next += l; - break; - } - default: - if (next == end_out) { - /* truncated */ - *next = '\0'; - return; - } - *next++ = ch; - break; - } - } - *next = '\0'; - return; -} - -/* --------------------------- Action handlers ---------------------------- */ - -/* ensure that path is relative, and does not contain ".." elements - * ensentially ensure that it does not match the regex: - * (^/|(^|/)\.\.(/|$)) - * XXX: Needs to become apr_is_path_relative() test - */ -static int is_only_below(const char *path) -{ -#ifdef HAVE_DRIVE_LETTERS - if (path[1] == ':') - return 0; -#endif -#ifdef NETWARE - if (strchr(path, ':') - return 0; -#endif - if (path[0] == '/') { - return 0; - } - while (*path) { - int dots = 0; - while (path[dots] == '.') - ++dots; -#if defined(WIN32) - /* If the name is canonical this is redundant - * but in security, redundancy is worthwhile. - * Does OS2 belong here (accepts ... for ..)? - */ - if (dots > 1 && (!path[dots] || path[dots] == '/')) - return 0; -#else - if (dots == 2 && (!path[dots] || path[dots] == '/')) - return 0; -#endif - path += dots; - while (*path && *(path++) != '/') - ++path; - } - return 1; -} - -static int handle_include(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - char *tag = NULL; - char *tag_val = NULL; - apr_bucket *tmp_buck; - char parsed_string[MAX_STRING_LEN]; - - *inserted_head = NULL; - if (ctx->flags & FLAG_PRINTING) { - while (1) { - ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1); - if (tag_val == NULL) { - if (tag == NULL) { - return (0); - } - else { - return (1); - } - } - if (!strcmp(tag, "file") || !strcmp(tag, "virtual")) { - request_rec *rr = NULL; - char *error_fmt = NULL; - - ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0); - if (tag[0] == 'f') { - /* be safe; only files in this directory or below allowed */ - if (!is_only_below(parsed_string)) { - error_fmt = "unable to include file \"%s\" " - "in parsed file %s"; - } - else { - rr = ap_sub_req_lookup_file(parsed_string, r, f->next); - } - } - else { - rr = ap_sub_req_lookup_uri(parsed_string, r, f->next); - } - - if (!error_fmt && rr->status != HTTP_OK) { - error_fmt = "unable to include \"%s\" in parsed file %s"; - } - - if (!error_fmt && (ctx->flags & FLAG_NO_EXEC) && rr->content_type - && (strncmp(rr->content_type, "text/", 5))) { - error_fmt = "unable to include potential exec \"%s\" " - "in parsed file %s"; - } - if (error_fmt == NULL) { - /* try to avoid recursive includes. We do this by walking - * up the r->main list of subrequests, and at each level - * walking back through any internal redirects. At each - * step, we compare the filenames and the URIs. - * - * The filename comparison catches a recursive include - * with an ever-changing URL, eg. - * <!--#include virtual= - * "$REQUEST_URI/$QUERY_STRING?$QUERY_STRING/x"--> - * which, although they would eventually be caught because - * we have a limit on the length of files, etc., can - * recurse for a while. - * - * The URI comparison catches the case where the filename - * is changed while processing the request, so the - * current name is never the same as any previous one. - * This can happen with "DocumentRoot /foo" when you - * request "/" on the server and it includes "/". - * This only applies to modules such as mod_dir that - * (somewhat improperly) mess with r->filename outside - * of a filename translation phase. - */ - int founddupe = 0; - request_rec *p; - for (p = r; p != NULL && !founddupe; p = p->main) { - request_rec *q; - for (q = p; q != NULL; q = q->prev) { - if ( (strcmp(q->filename, rr->filename) == 0) || - (strcmp(q->uri, rr->uri) == 0) ){ - founddupe = 1; - break; - } - } - } - - if (p != NULL) { - error_fmt = "Recursive include of \"%s\" " - "in parsed file %s"; - } - } - - /* See the Kludge in send_parsed_file for why */ - /* Basically, it puts a bread crumb in here, then looks */ - /* for the crumb later to see if its been here. */ - if (rr) - ap_set_module_config(rr->request_config, &include_module, r); - - if (!error_fmt) { - SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next); - - if (ap_run_sub_req(rr)) { - error_fmt = "unable to include \"%s\" in parsed file %s"; - } - } - if (error_fmt) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, - 0, r, error_fmt, tag_val, r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - - /* destroy the sub request if it's not a nested include (crumb) */ - if (rr != NULL - && ap_get_module_config(rr->request_config, &include_module) - != NESTED_INCLUDE_MAGIC) { - ap_destroy_sub_req(rr); - } - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "unknown parameter \"%s\" to tag include in %s", - tag, r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - } - } - return 0; -} - - -static int handle_echo(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - char *tag = NULL; - char *tag_val = NULL; - const char *echo_text = NULL; - apr_bucket *tmp_buck; - apr_size_t e_len, e_wrt; - enum {E_NONE, E_URL, E_ENTITY} encode; - - encode = E_ENTITY; - - *inserted_head = NULL; - if (ctx->flags & FLAG_PRINTING) { - while (1) { - ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1); - if (tag_val == NULL) { - if (tag != NULL) { - return 1; - } - else { - return 0; - } - } - if (!strcmp(tag, "var")) { - const char *val = apr_table_get(r->subprocess_env, tag_val); - - if (val) { - switch(encode) { - case E_NONE: echo_text = val; break; - case E_URL: echo_text = ap_escape_uri(r->pool, val); break; - case E_ENTITY: echo_text = ap_escape_html(r->pool, val); break; - } - - e_len = strlen(echo_text); - tmp_buck = apr_bucket_heap_create(echo_text, e_len, 1, &e_wrt); - } - else { - tmp_buck = apr_bucket_immortal_create("(none)", sizeof("none")); - } - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck); - if (*inserted_head == NULL) { - *inserted_head = tmp_buck; - } - } - else if (!strcmp(tag, "encoding")) { - if (!strcasecmp(tag_val, "none")) encode = E_NONE; - else if (!strcasecmp(tag_val, "url")) encode = E_URL; - else if (!strcasecmp(tag_val, "entity")) encode = E_ENTITY; - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "unknown value \"%s\" to parameter \"encoding\" of " - "tag echo in %s", tag_val, r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "unknown parameter \"%s\" in tag echo of %s", - tag, r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - - } - } - return 0; -} - -/* error and tf must point to a string with room for at - * least MAX_STRING_LEN characters - */ -static int handle_config(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - char *tag = NULL; - char *tag_val = NULL; - char parsed_string[MAX_STRING_LEN]; - apr_table_t *env = r->subprocess_env; - - *inserted_head = NULL; - if (ctx->flags & FLAG_PRINTING) { - while (1) { - ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 0); - if (tag_val == NULL) { - if (tag == NULL) { - return 0; /* Reached the end of the string. */ - } - else { - return 1; /* tags must have values. */ - } - } - if (!strcmp(tag, "errmsg")) { - ap_ssi_parse_string(r, tag_val, ctx->error_str, MAX_STRING_LEN, 0); - ctx->error_length = strlen(ctx->error_str); - } - else if (!strcmp(tag, "timefmt")) { - apr_time_t date = r->request_time; - - ap_ssi_parse_string(r, tag_val, ctx->time_str, MAX_STRING_LEN, 0); - apr_table_setn(env, "DATE_LOCAL", ap_ht_time(r->pool, date, ctx->time_str, 0)); - apr_table_setn(env, "DATE_GMT", ap_ht_time(r->pool, date, ctx->time_str, 1)); - apr_table_setn(env, "LAST_MODIFIED", - ap_ht_time(r->pool, r->finfo.mtime, ctx->time_str, 0)); - } - else if (!strcmp(tag, "sizefmt")) { - ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0); - decodehtml(parsed_string); - if (!strcmp(parsed_string, "bytes")) { - ctx->flags |= FLAG_SIZE_IN_BYTES; - } - else if (!strcmp(parsed_string, "abbrev")) { - ctx->flags &= FLAG_SIZE_ABBREV; - } - } - else { - apr_bucket *tmp_buck; - - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "unknown parameter \"%s\" to tag config in %s", - tag, r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - } - } - return 0; -} - - -static int find_file(request_rec *r, const char *directive, const char *tag, - char *tag_val, apr_finfo_t *finfo) -{ - char *to_send = tag_val; - request_rec *rr = NULL; - int ret=0; - char *error_fmt = NULL; - apr_status_t rv = APR_SUCCESS; - - if (!strcmp(tag, "file")) { - /* be safe; only files in this directory or below allowed */ - if (!is_only_below(tag_val)) { - error_fmt = "unable to access file \"%s\" " - "in parsed file %s"; - } - else { - ap_getparents(tag_val); /* get rid of any nasties */ - - /* note: it is okay to pass NULL for the "next filter" since - we never attempt to "run" this sub request. */ - rr = ap_sub_req_lookup_file(tag_val, r, NULL); - - if (rr->status == HTTP_OK && rr->finfo.filetype != 0) { - to_send = rr->filename; - if ((rv = apr_stat(finfo, to_send, APR_FINFO_GPROT - | APR_FINFO_MIN, rr->pool)) != APR_SUCCESS - && rv != APR_INCOMPLETE) { - error_fmt = "unable to get information about \"%s\" " - "in parsed file %s"; - } - } - else { - error_fmt = "unable to lookup information about \"%s\" " - "in parsed file %s"; - } - } - - if (error_fmt) { - ret = -1; - ap_log_rerror(APLOG_MARK, APLOG_ERR | (rv ? 0 : APLOG_NOERRNO), - rv, r, error_fmt, to_send, r->filename); - } - - if (rr) ap_destroy_sub_req(rr); - - return ret; - } - else if (!strcmp(tag, "virtual")) { - /* note: it is okay to pass NULL for the "next filter" since - we never attempt to "run" this sub request. */ - rr = ap_sub_req_lookup_uri(tag_val, r, NULL); - - if (rr->status == HTTP_OK && rr->finfo.filetype != 0) { - memcpy((char *) finfo, (const char *) &rr->finfo, - sizeof(rr->finfo)); - ap_destroy_sub_req(rr); - return 0; - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "unable to get information about \"%s\" " - "in parsed file %s", - tag_val, r->filename); - ap_destroy_sub_req(rr); - return -1; - } - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "unknown parameter \"%s\" to tag %s in %s", - tag, directive, r->filename); - return -1; - } -} - -#define NEG_SIGN " -" -#define ZERO_K " 0k" -#define ONE_K " 1k" - -static void generate_size(apr_ssize_t size, char *buff, apr_size_t buff_size) -{ - /* XXX: this -1 thing is a gross hack */ - if (size == (apr_ssize_t)-1) { - memcpy (buff, NEG_SIGN, sizeof(NEG_SIGN)+1); - } - else if (!size) { - memcpy (buff, ZERO_K, sizeof(ZERO_K)+1); - } - else if (size < 1024) { - memcpy (buff, ONE_K, sizeof(ONE_K)+1); - } - else if (size < 1048576) { - apr_snprintf(buff, buff_size, "%4" APR_SSIZE_T_FMT "k", (size + 512) / 1024); - } - else if (size < 103809024) { - apr_snprintf(buff, buff_size, "%4.1fM", size / 1048576.0); - } - else { - apr_snprintf(buff, buff_size, "%4" APR_SSIZE_T_FMT "M", (size + 524288) / 1048576); - } -} - -static int handle_fsize(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - char *tag = NULL; - char *tag_val = NULL; - apr_finfo_t finfo; - apr_size_t s_len, s_wrt; - apr_bucket *tmp_buck; - char parsed_string[MAX_STRING_LEN]; - - *inserted_head = NULL; - if (ctx->flags & FLAG_PRINTING) { - while (1) { - ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1); - if (tag_val == NULL) { - if (tag == NULL) { - return 0; - } - else { - return 1; - } - } - else { - ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0); - if (!find_file(r, "fsize", tag, parsed_string, &finfo)) { - char buff[50]; - - if (!(ctx->flags & FLAG_SIZE_IN_BYTES)) { - generate_size(finfo.size, buff, sizeof(buff)); - s_len = strlen (buff); - } - else { - int l, x, pos = 0; - char tmp_buff[50]; - - apr_snprintf(tmp_buff, sizeof(tmp_buff), "%" APR_OFF_T_FMT, finfo.size); - l = strlen(tmp_buff); /* grrr */ - for (x = 0; x < l; x++) { - if (x && (!((l - x) % 3))) { - buff[pos++] = ','; - } - buff[pos++] = tmp_buff[x]; - } - buff[pos] = '\0'; - s_len = pos; - } - - tmp_buck = apr_bucket_heap_create(buff, s_len, 1, &s_wrt); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck); - if (*inserted_head == NULL) { - *inserted_head = tmp_buck; - } - } - else { - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - } - } - } - return 0; -} - -static int handle_flastmod(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - char *tag = NULL; - char *tag_val = NULL; - apr_finfo_t finfo; - apr_size_t t_len, t_wrt; - apr_bucket *tmp_buck; - char parsed_string[MAX_STRING_LEN]; - - *inserted_head = NULL; - if (ctx->flags & FLAG_PRINTING) { - while (1) { - ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1); - if (tag_val == NULL) { - if (tag == NULL) { - return 0; - } - else { - return 1; - } - } - else { - ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0); - if (!find_file(r, "flastmod", tag, parsed_string, &finfo)) { - char *t_val; - - t_val = ap_ht_time(r->pool, finfo.mtime, ctx->time_str, 0); - t_len = strlen(t_val); - - tmp_buck = apr_bucket_heap_create(t_val, t_len, 1, &t_wrt); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck); - if (*inserted_head == NULL) { - *inserted_head = tmp_buck; - } - } - else { - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - } - } - } - return 0; -} - -static int re_check(request_rec *r, char *string, char *rexp) -{ - regex_t *compiled; - int regex_error; - - compiled = ap_pregcomp(r->pool, rexp, REG_EXTENDED | REG_NOSUB); - if (compiled == NULL) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "unable to compile pattern \"%s\"", rexp); - return -1; - } - regex_error = ap_regexec(compiled, string, 0, (regmatch_t *) NULL, 0); - ap_pregfree(r->pool, compiled); - return (!regex_error); -} - -enum token_type { - token_string, - token_and, token_or, token_not, token_eq, token_ne, - token_rbrace, token_lbrace, token_group, - token_ge, token_le, token_gt, token_lt -}; -struct token { - enum token_type type; - char value[MAX_STRING_LEN]; -}; - -/* there is an implicit assumption here that string is at most MAX_STRING_LEN-1 - * characters long... - */ -static const char *get_ptoken(request_rec *r, const char *string, struct token *token, - int *unmatched) -{ - char ch; - int next = 0; - int qs = 0; - int tkn_fnd = 0; - - /* Skip leading white space */ - if (string == (char *) NULL) { - return (char *) NULL; - } - while ((ch = *string++)) { - if (!apr_isspace(ch)) { - break; - } - } - if (ch == '\0') { - return (char *) NULL; - } - - token->type = token_string; /* the default type */ - switch (ch) { - case '(': - token->type = token_lbrace; - return (string); - case ')': - token->type = token_rbrace; - return (string); - case '=': - token->type = token_eq; - return (string); - case '!': - if (*string == '=') { - token->type = token_ne; - return (string + 1); - } - else { - token->type = token_not; - return (string); - } - case '\'': - token->type = token_string; - qs = 1; - break; - case '|': - if (*string == '|') { - token->type = token_or; - return (string + 1); - } - break; - case '&': - if (*string == '&') { - token->type = token_and; - return (string + 1); - } - break; - case '>': - if (*string == '=') { - token->type = token_ge; - return (string + 1); - } - else { - token->type = token_gt; - return (string); - } - case '<': - if (*string == '=') { - token->type = token_le; - return (string + 1); - } - else { - token->type = token_lt; - return (string); - } - default: - token->type = token_string; - break; - } - /* We should only be here if we are in a string */ - if (!qs) { - token->value[next++] = ch; - } - - /* - * Yes I know that goto's are BAD. But, c doesn't allow me to - * exit a loop from a switch statement. Yes, I could use a flag, - * but that is (IMHO) even less readable/maintainable than the goto. - */ - /* - * I used the ++string throughout this section so that string - * ends up pointing to the next token and I can just return it - */ - for (ch = *string; ((ch != '\0') && (!tkn_fnd)); ch = *++string) { - if (ch == '\\') { - if ((ch = *++string) == '\0') { - tkn_fnd = 1; - } - else { - token->value[next++] = ch; - } - } - else { - if (!qs) { - if (apr_isspace(ch)) { - tkn_fnd = 1; - } - else { - switch (ch) { - case '(': - case ')': - case '=': - case '!': - case '<': - case '>': - tkn_fnd = 1; - break; - case '|': - if (*(string + 1) == '|') { - tkn_fnd = 1; - } - break; - case '&': - if (*(string + 1) == '&') { - tkn_fnd = 1; - } - break; - } - if (!tkn_fnd) { - token->value[next++] = ch; - } - } - } - else { - if (ch == '\'') { - qs = 0; - ++string; - tkn_fnd = 1; - } - else { - token->value[next++] = ch; - } - } - } - } - - /* If qs is still set, I have an unmatched ' */ - if (qs) { - *unmatched = 1; - next = 0; - } - token->value[next] = '\0'; - return (string); -} - - -/* - * Hey I still know that goto's are BAD. I don't think that I've ever - * used two in the same project, let alone the same file before. But, - * I absolutely want to make sure that I clean up the memory in all - * cases. And, without rewriting this completely, the easiest way - * is to just branch to the return code which cleans it up. - */ -/* there is an implicit assumption here that expr is at most MAX_STRING_LEN-1 - * characters long... - */ -static int parse_expr(request_rec *r, const char *expr, int *was_error, - int *was_unmatched, char *debug) -{ - struct parse_node { - struct parse_node *left, *right, *parent; - struct token token; - int value, done; - } *root, *current, *new; - const char *parse; - char buffer[MAX_STRING_LEN]; - apr_pool_t *expr_pool; - int retval = 0; - apr_size_t debug_pos = 0; - - debug[debug_pos] = '\0'; - *was_error = 0; - *was_unmatched = 0; - if ((parse = expr) == (char *) NULL) { - return (0); - } - root = current = (struct parse_node *) NULL; - if (apr_pool_create(&expr_pool, r->pool) != APR_SUCCESS) - return 0; - - /* Create Parse Tree */ - while (1) { - new = (struct parse_node *) apr_palloc(expr_pool, - sizeof(struct parse_node)); - new->parent = new->left = new->right = (struct parse_node *) NULL; - new->done = 0; - if ((parse = get_ptoken(r, parse, &new->token, was_unmatched)) == (char *) NULL) { - break; - } - switch (new->token.type) { - - case token_string: -#ifdef DEBUG_INCLUDE - debug_pos += sprintf (&debug[debug_pos], " Token: string (%s)\n", - new->token.value); -#endif - if (current == (struct parse_node *) NULL) { - root = current = new; - break; - } - switch (current->token.type) { - case token_string: - if (current->token.value[0] != '\0') { - strncat(current->token.value, " ", - sizeof(current->token.value) - - strlen(current->token.value) - 1); - } - strncat(current->token.value, new->token.value, - sizeof(current->token.value) - - strlen(current->token.value) - 1); - current->token.value[sizeof(current->token.value) - 1] = '\0'; - break; - case token_eq: - case token_ne: - case token_and: - case token_or: - case token_lbrace: - case token_not: - case token_ge: - case token_gt: - case token_le: - case token_lt: - new->parent = current; - current = current->right = new; - break; - default: - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - *was_error = 1; - goto RETURN; - } - break; - - case token_and: - case token_or: -#ifdef DEBUG_INCLUDE - memcpy (&debug[debug_pos], " Token: and/or\n", - sizeof (" Token: and/or\n")); - debug_pos += sizeof (" Token: and/or\n"); -#endif - if (current == (struct parse_node *) NULL) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - *was_error = 1; - goto RETURN; - } - /* Percolate upwards */ - while (current != (struct parse_node *) NULL) { - switch (current->token.type) { - case token_string: - case token_group: - case token_not: - case token_eq: - case token_ne: - case token_and: - case token_or: - case token_ge: - case token_gt: - case token_le: - case token_lt: - current = current->parent; - continue; - case token_lbrace: - break; - default: - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - *was_error = 1; - goto RETURN; - } - break; - } - if (current == (struct parse_node *) NULL) { - new->left = root; - new->left->parent = new; - new->parent = (struct parse_node *) NULL; - root = new; - } - else { - new->left = current->right; - current->right = new; - new->parent = current; - } - current = new; - break; - - case token_not: -#ifdef DEBUG_INCLUDE - memcpy (&debug[debug_pos], " Token: not\n", - sizeof (" Token: not\n")); - debug_pos += sizeof (" Token: not\n"); -#endif - if (current == (struct parse_node *) NULL) { - root = current = new; - break; - } - /* Percolate upwards */ - while (current != (struct parse_node *) NULL) { - switch (current->token.type) { - case token_not: - case token_eq: - case token_ne: - case token_and: - case token_or: - case token_lbrace: - case token_ge: - case token_gt: - case token_le: - case token_lt: - break; - default: - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - *was_error = 1; - goto RETURN; - } - break; - } - if (current == (struct parse_node *) NULL) { - new->left = root; - new->left->parent = new; - new->parent = (struct parse_node *) NULL; - root = new; - } - else { - new->left = current->right; - current->right = new; - new->parent = current; - } - current = new; - break; - - case token_eq: - case token_ne: - case token_ge: - case token_gt: - case token_le: - case token_lt: -#ifdef DEBUG_INCLUDE - memcpy (&debug[debug_pos], " Token: eq/ne/ge/gt/le/lt\n", - sizeof (" Token: eq/ne/ge/gt/le/lt\n")); - debug_pos += sizeof (" Token: eq/ne/ge/gt/le/lt\n"); -#endif - if (current == (struct parse_node *) NULL) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - *was_error = 1; - goto RETURN; - } - /* Percolate upwards */ - while (current != (struct parse_node *) NULL) { - switch (current->token.type) { - case token_string: - case token_group: - current = current->parent; - continue; - case token_lbrace: - case token_and: - case token_or: - break; - case token_not: - case token_eq: - case token_ne: - case token_ge: - case token_gt: - case token_le: - case token_lt: - default: - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - *was_error = 1; - goto RETURN; - } - break; - } - if (current == (struct parse_node *) NULL) { - new->left = root; - new->left->parent = new; - new->parent = (struct parse_node *) NULL; - root = new; - } - else { - new->left = current->right; - current->right = new; - new->parent = current; - } - current = new; - break; - - case token_rbrace: -#ifdef DEBUG_INCLUDE - memcpy (&debug[debug_pos], " Token: rbrace\n", - sizeof (" Token: rbrace\n")); - debug_pos += sizeof (" Token: rbrace\n"); -#endif - while (current != (struct parse_node *) NULL) { - if (current->token.type == token_lbrace) { - current->token.type = token_group; - break; - } - current = current->parent; - } - if (current == (struct parse_node *) NULL) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Unmatched ')' in \"%s\" in file %s", - expr, r->filename); - *was_error = 1; - goto RETURN; - } - break; - - case token_lbrace: -#ifdef DEBUG_INCLUDE - memcpy (&debug[debug_pos], " Token: lbrace\n", - sizeof (" Token: lbrace\n")); - debug_pos += sizeof (" Token: lbrace\n"); -#endif - if (current == (struct parse_node *) NULL) { - root = current = new; - break; - } - /* Percolate upwards */ - while (current != (struct parse_node *) NULL) { - switch (current->token.type) { - case token_not: - case token_eq: - case token_ne: - case token_and: - case token_or: - case token_lbrace: - case token_ge: - case token_gt: - case token_le: - case token_lt: - break; - case token_string: - case token_group: - default: - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - *was_error = 1; - goto RETURN; - } - break; - } - if (current == (struct parse_node *) NULL) { - new->left = root; - new->left->parent = new; - new->parent = (struct parse_node *) NULL; - root = new; - } - else { - new->left = current->right; - current->right = new; - new->parent = current; - } - current = new; - break; - default: - break; - } - } - - /* Evaluate Parse Tree */ - current = root; - while (current != (struct parse_node *) NULL) { - switch (current->token.type) { - case token_string: -#ifdef DEBUG_INCLUDE - memcpy (&debug[debug_pos], " Evaluate string\n", - sizeof (" Evaluate string\n")); - debug_pos += sizeof (" Evaluate string\n"); -#endif - ap_ssi_parse_string(r, current->token.value, buffer, sizeof(buffer), 0); - apr_cpystrn(current->token.value, buffer, sizeof(current->token.value)); - current->value = (current->token.value[0] != '\0'); - current->done = 1; - current = current->parent; - break; - - case token_and: - case token_or: -#ifdef DEBUG_INCLUDE - memcpy (&debug[debug_pos], " Evaluate and/or\n", - sizeof (" Evaluate and/or\n")); - debug_pos += sizeof (" Evaluate and/or\n"); -#endif - if (current->left == (struct parse_node *) NULL || - current->right == (struct parse_node *) NULL) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - *was_error = 1; - goto RETURN; - } - if (!current->left->done) { - switch (current->left->token.type) { - case token_string: - ap_ssi_parse_string(r, current->left->token.value, - buffer, sizeof(buffer), 0); - apr_cpystrn(current->left->token.value, buffer, - sizeof(current->left->token.value)); - current->left->value = (current->left->token.value[0] != '\0'); - current->left->done = 1; - break; - default: - current = current->left; - continue; - } - } - if (!current->right->done) { - switch (current->right->token.type) { - case token_string: - ap_ssi_parse_string(r, current->right->token.value, - buffer, sizeof(buffer), 0); - apr_cpystrn(current->right->token.value, buffer, - sizeof(current->right->token.value)); - current->right->value = (current->right->token.value[0] != '\0'); - current->right->done = 1; - break; - default: - current = current->right; - continue; - } - } -#ifdef DEBUG_INCLUDE - debug_pos += sprintf (&debug[debug_pos], " Left: %c\n", - current->left->value ? '1' : '0'); - debug_pos += sprintf (&debug[debug_pos], " Right: %c\n", - current->right->value ? '1' : '0'); -#endif - if (current->token.type == token_and) { - current->value = current->left->value && current->right->value; - } - else { - current->value = current->left->value || current->right->value; - } -#ifdef DEBUG_INCLUDE - debug_pos += sprintf (&debug[debug_pos], " Returning %c\n", - current->value ? '1' : '0'); -#endif - current->done = 1; - current = current->parent; - break; - - case token_eq: - case token_ne: -#ifdef DEBUG_INCLUDE - memcpy (&debug[debug_pos], " Evaluate eq/ne\n", - sizeof (" Evaluate eq/ne\n")); - debug_pos += sizeof (" Evaluate eq/ne\n"); -#endif - if ((current->left == (struct parse_node *) NULL) || - (current->right == (struct parse_node *) NULL) || - (current->left->token.type != token_string) || - (current->right->token.type != token_string)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - *was_error = 1; - goto RETURN; - } - ap_ssi_parse_string(r, current->left->token.value, - buffer, sizeof(buffer), 0); - apr_cpystrn(current->left->token.value, buffer, - sizeof(current->left->token.value)); - ap_ssi_parse_string(r, current->right->token.value, - buffer, sizeof(buffer), 0); - apr_cpystrn(current->right->token.value, buffer, - sizeof(current->right->token.value)); - if (current->right->token.value[0] == '/') { - int len; - len = strlen(current->right->token.value); - if (current->right->token.value[len - 1] == '/') { - current->right->token.value[len - 1] = '\0'; - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid rexp \"%s\" in file %s", - current->right->token.value, r->filename); - *was_error = 1; - goto RETURN; - } -#ifdef DEBUG_INCLUDE - debug_pos += sprintf (&debug[debug_pos], - " Re Compare (%s) with /%s/\n", - current->left->token.value, - ¤t->right->token.value[1]); -#endif - current->value = - re_check(r, current->left->token.value, - ¤t->right->token.value[1]); - } - else { -#ifdef DEBUG_INCLUDE - debug_pos += sprintf (&debug[debug_pos], - " Compare (%s) with (%s)\n", - current->left->token.value, - current->right->token.value); -#endif - current->value = - (strcmp(current->left->token.value, - current->right->token.value) == 0); - } - if (current->token.type == token_ne) { - current->value = !current->value; - } -#ifdef DEBUG_INCLUDE - debug_pos += sprintf (&debug[debug_pos], " Returning %c\n", - current->value ? '1' : '0'); -#endif - current->done = 1; - current = current->parent; - break; - case token_ge: - case token_gt: - case token_le: - case token_lt: -#ifdef DEBUG_INCLUDE - memcpy (&debug[debug_pos], " Evaluate ge/gt/le/lt\n", - sizeof (" Evaluate ge/gt/le/lt\n")); - debug_pos += sizeof (" Evaluate ge/gt/le/lt\n"); -#endif - if ((current->left == (struct parse_node *) NULL) || - (current->right == (struct parse_node *) NULL) || - (current->left->token.type != token_string) || - (current->right->token.type != token_string)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - *was_error = 1; - goto RETURN; - } - ap_ssi_parse_string(r, current->left->token.value, - buffer, sizeof(buffer), 0); - apr_cpystrn(current->left->token.value, buffer, - sizeof(current->left->token.value)); - ap_ssi_parse_string(r, current->right->token.value, - buffer, sizeof(buffer), 0); - apr_cpystrn(current->right->token.value, buffer, - sizeof(current->right->token.value)); -#ifdef DEBUG_INCLUDE - debug_pos += sprintf (&debug[debug_pos], - " Compare (%s) with (%s)\n", - current->left->token.value, - current->right->token.value); -#endif - current->value = - strcmp(current->left->token.value, - current->right->token.value); - if (current->token.type == token_ge) { - current->value = current->value >= 0; - } - else if (current->token.type == token_gt) { - current->value = current->value > 0; - } - else if (current->token.type == token_le) { - current->value = current->value <= 0; - } - else if (current->token.type == token_lt) { - current->value = current->value < 0; - } - else { - current->value = 0; /* Don't return -1 if unknown token */ - } -#ifdef DEBUG_INCLUDE - debug_pos += sprintf (&debug[debug_pos], " Returning %c\n", - current->value ? '1' : '0'); -#endif - current->done = 1; - current = current->parent; - break; - - case token_not: - if (current->right != (struct parse_node *) NULL) { - if (!current->right->done) { - current = current->right; - continue; - } - current->value = !current->right->value; - } - else { - current->value = 0; - } -#ifdef DEBUG_INCLUDE - debug_pos += sprintf (&debug[debug_pos], " Evaluate !: %c\n", - current->value ? '1' : '0'); -#endif - current->done = 1; - current = current->parent; - break; - - case token_group: - if (current->right != (struct parse_node *) NULL) { - if (!current->right->done) { - current = current->right; - continue; - } - current->value = current->right->value; - } - else { - current->value = 1; - } -#ifdef DEBUG_INCLUDE - debug_pos += sprintf (&debug[debug_pos], " Evaluate (): %c\n", - current->value ? '1' : '0'); -#endif - current->done = 1; - current = current->parent; - break; - - case token_lbrace: - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Unmatched '(' in \"%s\" in file %s", - expr, r->filename); - *was_error = 1; - goto RETURN; - - case token_rbrace: - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Unmatched ')' in \"%s\" in file %s", - expr, r->filename); - *was_error = 1; - goto RETURN; - - default: - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "bad token type"); - *was_error = 1; - goto RETURN; - } - } - - retval = (root == (struct parse_node *) NULL) ? 0 : root->value; - RETURN: - apr_pool_destroy(expr_pool); - return (retval); -} - -/*-------------------------------------------------------------------------*/ -#ifdef DEBUG_INCLUDE - -/* XXX overlaying the static string pointed to by cond_txt isn't cool */ - -#define MAX_DEBUG_SIZE MAX_STRING_LEN -#define LOG_COND_STATUS(cntx, t_buck, h_ptr, ins_head, tag_text) \ -{ \ - char *cond_txt = "**** X conditional_status=\"0\"\n"; \ - apr_size_t c_wrt; \ - \ - if (cntx->flags & FLAG_COND_TRUE) { \ - cond_txt[31] = '1'; \ - } \ - memcpy(&cond_txt[5], tag_text, sizeof(tag_text)); \ - t_buck = apr_bucket_heap_create(cond_txt, sizeof(cond_txt), 1, &c_wrt); \ - APR_BUCKET_INSERT_BEFORE(h_ptr, t_buck); \ - \ - if (ins_head == NULL) { \ - ins_head = t_buck; \ - } \ -} -#define DUMP_PARSE_EXPR_DEBUG(t_buck, h_ptr, d_buf, ins_head) \ -{ \ - apr_size_t b_wrt; \ - if (d_buf[0] != '\0') { \ - t_buck = apr_bucket_heap_create(d_buf, strlen(d_buf), 1, &b_wrt); \ - APR_BUCKET_INSERT_BEFORE(h_ptr, t_buck); \ - \ - if (ins_head == NULL) { \ - ins_head = t_buck; \ - } \ - } \ -} -#else - -#define MAX_DEBUG_SIZE 10 -#define LOG_COND_STATUS(cntx, t_buck, h_ptr, ins_head, tag_text) -#define DUMP_PARSE_EXPR_DEBUG(t_buck, h_ptr, d_buf, ins_head) - -#endif -/*-------------------------------------------------------------------------*/ - -/* pjr - These seem to allow expr="fred" expr="joe" where joe overwrites fred. */ -static int handle_if(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - char *tag = NULL; - char *tag_val = NULL; - char *expr = NULL; - int expr_ret, was_error, was_unmatched; - apr_bucket *tmp_buck; - char debug_buf[MAX_DEBUG_SIZE]; - - *inserted_head = NULL; - if (!ctx->flags & FLAG_PRINTING) { - ctx->if_nesting_level++; - } - else { - while (1) { - ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 0); - if (tag == NULL) { - if (expr == NULL) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "missing expr in if statement: %s", r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - return 1; - } - expr_ret = parse_expr(r, expr, &was_error, &was_unmatched, debug_buf); - if (was_error) { - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - return 1; - } - if (was_unmatched) { - DUMP_PARSE_EXPR_DEBUG(tmp_buck, head_ptr, "\nUnmatched '\n", - *inserted_head); - } - DUMP_PARSE_EXPR_DEBUG(tmp_buck, head_ptr, debug_buf, *inserted_head); - - if (expr_ret) { - ctx->flags |= (FLAG_PRINTING | FLAG_COND_TRUE); - } - else { - ctx->flags &= FLAG_CLEAR_PRINT_COND; - } - LOG_COND_STATUS(ctx, tmp_buck, head_ptr, *inserted_head, " if"); - ctx->if_nesting_level = 0; - return 0; - } - else if (!strcmp(tag, "expr")) { - expr = tag_val; -#ifdef DEBUG_INCLUDE - if (1) { - apr_size_t d_len = 0, d_wrt = 0; - d_len = sprintf(debug_buf, "**** if expr=\"%s\"\n", expr); - tmp_buck = apr_bucket_heap_create(debug_buf, d_len, 1, &d_wrt); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck); - - if (*inserted_head == NULL) { - *inserted_head = tmp_buck; - } - } -#endif - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "unknown parameter \"%s\" to tag if in %s", tag, r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - - } - } - return 0; -} - -static int handle_elif(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - char *tag = NULL; - char *tag_val = NULL; - char *expr = NULL; - int expr_ret, was_error, was_unmatched; - apr_bucket *tmp_buck; - char debug_buf[MAX_DEBUG_SIZE]; - - *inserted_head = NULL; - if (!ctx->if_nesting_level) { - while (1) { - ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 0); - if (tag == '\0') { - LOG_COND_STATUS(ctx, tmp_buck, head_ptr, *inserted_head, " elif"); - - if (ctx->flags & FLAG_COND_TRUE) { - ctx->flags &= FLAG_CLEAR_PRINTING; - return (0); - } - if (expr == NULL) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "missing expr in elif statement: %s", r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - return (1); - } - expr_ret = parse_expr(r, expr, &was_error, &was_unmatched, debug_buf); - if (was_error) { - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - return 1; - } - if (was_unmatched) { - DUMP_PARSE_EXPR_DEBUG(tmp_buck, head_ptr, "\nUnmatched '\n", - *inserted_head); - } - DUMP_PARSE_EXPR_DEBUG(tmp_buck, head_ptr, debug_buf, *inserted_head); - - if (expr_ret) { - ctx->flags |= (FLAG_PRINTING | FLAG_COND_TRUE); - } - else { - ctx->flags &= FLAG_CLEAR_PRINT_COND; - } - LOG_COND_STATUS(ctx, tmp_buck, head_ptr, *inserted_head, " elif"); - return (0); - } - else if (!strcmp(tag, "expr")) { - expr = tag_val; -#ifdef DEBUG_INCLUDE - if (1) { - apr_size_t d_len = 0, d_wrt = 0; - d_len = sprintf(debug_buf, "**** elif expr=\"%s\"\n", expr); - tmp_buck = apr_bucket_heap_create(debug_buf, d_len, 1, &d_wrt); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck); - - if (*inserted_head == NULL) { - *inserted_head = tmp_buck; - } - } -#endif - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "unknown parameter \"%s\" to tag if in %s", tag, r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - } - } - return 0; -} - -static int handle_else(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - char *tag = NULL; - char *tag_val = NULL; - apr_bucket *tmp_buck; - - *inserted_head = NULL; - if (!ctx->if_nesting_level) { - ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1); - if ((tag != NULL) || (tag_val != NULL)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "else directive does not take tags in %s", r->filename); - if (ctx->flags & FLAG_PRINTING) { - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - return -1; - } - else { - LOG_COND_STATUS(ctx, tmp_buck, head_ptr, *inserted_head, " else"); - - if (ctx->flags & FLAG_COND_TRUE) { - ctx->flags &= FLAG_CLEAR_PRINTING; - } - else { - ctx->flags |= (FLAG_PRINTING | FLAG_COND_TRUE); - } - return 0; - } - } - return 0; -} - -static int handle_endif(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - char *tag = NULL; - char *tag_val = NULL; - apr_bucket *tmp_buck; - - *inserted_head = NULL; - if (!ctx->if_nesting_level) { - ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1); - if ((tag != NULL) || (tag_val != NULL)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "endif directive does not take tags in %s", r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - return -1; - } - else { - LOG_COND_STATUS(ctx, tmp_buck, head_ptr, *inserted_head, "endif"); - ctx->flags |= (FLAG_PRINTING | FLAG_COND_TRUE); - return 0; - } - } - else { - ctx->if_nesting_level--; - return 0; - } -} - -static int handle_set(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - char *tag = NULL; - char *tag_val = NULL; - char *var = NULL; - apr_bucket *tmp_buck; - char parsed_string[MAX_STRING_LEN]; - - *inserted_head = NULL; - if (ctx->flags & FLAG_PRINTING) { - while (1) { - ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1); - if ((tag == NULL) && (tag_val == NULL)) { - return 0; - } - else if (tag_val == NULL) { - return 1; - } - else if (!strcmp(tag, "var")) { - var = tag_val; - } - else if (!strcmp(tag, "value")) { - if (var == (char *) NULL) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "variable must precede value in set directive in %s", - r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - return (-1); - } - ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0); - apr_table_setn(r->subprocess_env, apr_pstrdup(r->pool, var), - apr_pstrdup(r->pool, parsed_string)); - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid tag for set directive in %s", r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - return -1; - } - } - } - return 0; -} - -static int handle_printenv(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - char *tag = NULL; - char *tag_val = NULL; - apr_bucket *tmp_buck; - - if (ctx->flags & FLAG_PRINTING) { - ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1); - if ((tag == NULL) && (tag_val == NULL)) { - apr_array_header_t *arr = apr_table_elts(r->subprocess_env); - apr_table_entry_t *elts = (apr_table_entry_t *)arr->elts; - int i; - char *key_text, *val_text; - apr_size_t k_len, v_len, t_wrt; - - *inserted_head = NULL; - for (i = 0; i < arr->nelts; ++i) { - key_text = ap_escape_html(r->pool, elts[i].key); - val_text = ap_escape_html(r->pool, elts[i].val); - k_len = strlen(key_text); - v_len = strlen(val_text); - - /* Key_text */ - tmp_buck = apr_bucket_heap_create(key_text, k_len, 1, &t_wrt); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck); - if (*inserted_head == NULL) { - *inserted_head = tmp_buck; - } - /* = */ - tmp_buck = apr_bucket_immortal_create("=", 1); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck); - /* Value_text */ - tmp_buck = apr_bucket_heap_create(val_text, v_len, 1, &t_wrt); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck); - /* newline... */ - tmp_buck = apr_bucket_immortal_create("\n", 1); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck); - } - return 0; - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "printenv directive does not take tags in %s", r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - return -1; - } - } - return 0; -} - -/* -------------------------- The main function --------------------------- */ - -static void send_parsed_content(apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f) -{ - include_ctx_t *ctx = f->ctx; - apr_bucket *dptr = APR_BRIGADE_FIRST(*bb); - apr_bucket *tmp_dptr; - apr_bucket_brigade *tag_and_after; - int ret; - - if (r->args) { /* add QUERY stuff to env cause it ain't yet */ - char *arg_copy = apr_pstrdup(r->pool, r->args); - - apr_table_setn(r->subprocess_env, "QUERY_STRING", r->args); - ap_unescape_url(arg_copy); - apr_table_setn(r->subprocess_env, "QUERY_STRING_UNESCAPED", - ap_escape_shell_cmd(r->pool, arg_copy)); - } - - while (dptr != APR_BRIGADE_SENTINEL(*bb)) { - /* State to check for the STARTING_SEQUENCE. */ - if ((ctx->state == PRE_HEAD) || (ctx->state == PARSE_HEAD)) { - int do_cleanup = 0; - apr_size_t cleanup_bytes = ctx->parse_pos; - - tmp_dptr = find_start_sequence(dptr, ctx, *bb, &do_cleanup); - - /* The few bytes stored in the ssi_tag_brigade turned out not to - * be a tag after all. This can only happen if the starting - * tag actually spans brigades. This should be very rare. - */ - if ((do_cleanup) && (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade))) { - apr_bucket *tmp_bkt; - - tmp_bkt = apr_bucket_immortal_create(STARTING_SEQUENCE, - cleanup_bytes); - APR_BRIGADE_INSERT_HEAD(*bb, tmp_bkt); - apr_brigade_cleanup(ctx->ssi_tag_brigade); - } - - /* If I am inside a conditional (if, elif, else) that is false - * then I need to throw away anything contained in it. - */ - if ((!(ctx->flags & FLAG_PRINTING)) && (tmp_dptr != NULL) && - (dptr != APR_BRIGADE_SENTINEL(*bb))) { - while ((dptr != APR_BRIGADE_SENTINEL(*bb)) && - (dptr != tmp_dptr)) { - apr_bucket *free_bucket = dptr; - - dptr = APR_BUCKET_NEXT (dptr); - apr_bucket_delete(free_bucket); - } - } - - /* Adjust the current bucket position based on what was found... */ - if ((tmp_dptr != NULL) && (ctx->state == PARSE_DIRECTIVE)) { - if (ctx->tag_start_bucket != NULL) { - dptr = ctx->tag_start_bucket; - } - else { - dptr = APR_BRIGADE_SENTINEL(*bb); - } - } - else if ((tmp_dptr != NULL) && (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD)) { - /* Send the large chunk of pre-tag bytes... */ - tag_and_after = apr_brigade_split(*bb, tmp_dptr); - ap_pass_brigade(f->next, *bb); - *bb = tag_and_after; - dptr = tmp_dptr; - ctx->bytes_parsed = 0; - } - else if (tmp_dptr == NULL) { /* There was no possible SSI tag in the */ - dptr = APR_BRIGADE_SENTINEL(*bb); /* remainder of this brigade... */ - } - } - - /* State to check for the ENDING_SEQUENCE. */ - if (((ctx->state == PARSE_DIRECTIVE) || - (ctx->state == PARSE_TAG) || - (ctx->state == PARSE_TAIL)) && - (dptr != APR_BRIGADE_SENTINEL(*bb))) { - tmp_dptr = find_end_sequence(dptr, ctx, *bb); - - if (tmp_dptr != NULL) { - dptr = tmp_dptr; /* Adjust bucket pos... */ - - /* If some of the tag has already been set aside then set - * aside remainder of tag. Now the full tag is in ssi_tag_brigade. - * If none has yet been set aside, then leave it all where it is. - * In any event after this the entire set of tag buckets will be - * in one place or another. - */ - if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) { - tag_and_after = apr_brigade_split(*bb, dptr); - APR_BRIGADE_CONCAT(ctx->ssi_tag_brigade, *bb); - *bb = tag_and_after; - } - else if (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD) { - SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next); - } - } - else { - dptr = APR_BRIGADE_SENTINEL(*bb); /* remainder of this brigade... */ - } - } - - /* State to processed the directive... */ - if (ctx->state == PARSED) { - apr_bucket *content_head = NULL, *tmp_bkt; - apr_size_t tmp_i; - char tmp_buf[TMP_BUF_SIZE]; - int (*handle_func)(include_ctx_t *, apr_bucket_brigade **, request_rec *, - ap_filter_t *, apr_bucket *, apr_bucket **); - - /* By now the full tag (all buckets) should either be set aside into - * ssi_tag_brigade or contained within the current bb. All tag - * processing from here on can assume that. - */ - - /* At this point, everything between ctx->head_start_bucket and - * ctx->tail_start_bucket is an SSI - * directive, we just have to deal with it now. - */ - if (get_combined_directive(ctx, r, *bb, tmp_buf, - TMP_BUF_SIZE) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "mod_include: error copying directive in %s", - r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_bkt, dptr, content_head); - - /* DO CLEANUP HERE!!!!! */ - tmp_dptr = ctx->head_start_bucket; - if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) { - apr_brigade_cleanup(ctx->ssi_tag_brigade); - } - else { - do { - tmp_bkt = tmp_dptr; - tmp_dptr = APR_BUCKET_NEXT (tmp_dptr); - apr_bucket_delete(tmp_bkt); - } while ((tmp_dptr != dptr) && - (tmp_dptr != APR_BRIGADE_SENTINEL(*bb))); - } - - return; - } - - /* Can't destroy the tag buckets until I'm done processing - * because the combined_tag might just be pointing to - * the contents of a single bucket! - */ - - /* Retrieve the handler function to be called for this directive from the - * functions registered in the hash table. - * Need to lower case the directive for proper matching. Also need to have - * it NULL terminated (and include the NULL in the length) for proper - * hash matching. - */ - for (tmp_i = 0; tmp_i < ctx->directive_length; tmp_i++) { - ctx->combined_tag[tmp_i] = apr_tolower(ctx->combined_tag[tmp_i]); - } - ctx->combined_tag[ctx->directive_length] = '\0'; - ctx->curr_tag_pos = &ctx->combined_tag[ctx->directive_length+1]; - - handle_func = - (include_handler_fn_t *)apr_hash_get(include_hash, - ctx->combined_tag, - ctx->directive_length+1); - if (handle_func != NULL) { - ret = (*handle_func)(ctx, bb, r, f, dptr, &content_head); - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "unknown directive \"%s\" in parsed doc %s", - ctx->combined_tag, r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_bkt, dptr, content_head); - } - - /* This chunk of code starts at the first bucket in the chain - * of tag buckets (assuming that by this point the bucket for - * the STARTING_SEQUENCE has been split) and loops through to - * the end of the tag buckets freeing them all. - * - * Remember that some part of this may have been set aside - * into the ssi_tag_brigade and the remainder (possibly as - * little as one byte) will be in the current brigade. - * - * The value of dptr should have been set during the - * PARSE_TAIL state to the first bucket after the - * ENDING_SEQUENCE. - * - * The value of content_head may have been set during processing - * of the directive. If so, the content was inserted in front - * of the dptr bucket. The inserted buckets should not be thrown - * away here, but they should also not be parsed later. - */ - if (content_head == NULL) { - content_head = dptr; - } - tmp_dptr = ctx->head_start_bucket; - if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) { - apr_brigade_cleanup(ctx->ssi_tag_brigade); - } - else { - do { - tmp_bkt = tmp_dptr; - tmp_dptr = APR_BUCKET_NEXT (tmp_dptr); - apr_bucket_delete(tmp_bkt); - } while ((tmp_dptr != content_head) && - (tmp_dptr != APR_BRIGADE_SENTINEL(*bb))); - } - if (ctx->combined_tag == tmp_buf) { - memset (ctx->combined_tag, '\0', ctx->tag_length); - ctx->combined_tag = NULL; - } - - /* Don't reset the flags or the nesting level!!! */ - ctx->parse_pos = 0; - ctx->head_start_bucket = NULL; - ctx->head_start_index = 0; - ctx->tag_start_bucket = NULL; - ctx->tag_start_index = 0; - ctx->tail_start_bucket = NULL; - ctx->tail_start_index = 0; - ctx->curr_tag_pos = NULL; - ctx->tag_length = 0; - ctx->directive_length = 0; - - if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) { - apr_brigade_cleanup(ctx->ssi_tag_brigade); - } - - ctx->state = PRE_HEAD; - } - } - - /* If I am in the middle of parsing an SSI tag then I need to set aside - * the pertinent trailing buckets and pass on the initial part of the - * brigade. The pertinent parts of the next brigades will be added to - * these set aside buckets to form the whole tag and will be processed - * once the whole tag has been found. - */ - if (ctx->state == PRE_HEAD) { - /* Inside a false conditional (if, elif, else), so toss it all... */ - if ((dptr != APR_BRIGADE_SENTINEL(*bb)) && - (!(ctx->flags & FLAG_PRINTING))) { - apr_bucket *free_bucket; - do { - free_bucket = dptr; - dptr = APR_BUCKET_NEXT (dptr); - apr_bucket_delete(free_bucket); - } while (dptr != APR_BRIGADE_SENTINEL(*bb)); - } - else { /* Otherwise pass it along... */ - ap_pass_brigade(f->next, *bb); /* No SSI tags in this brigade... */ - ctx->bytes_parsed = 0; - } - } - else if (ctx->state == PARSED) { /* Invalid internal condition... */ - apr_bucket *content_head = NULL, *tmp_bkt; - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid mod_include state during file %s", r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_bkt, APR_BRIGADE_FIRST(*bb), content_head); - } - else { /* Entire brigade is middle chunk of SSI tag... */ - if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) { - APR_BRIGADE_CONCAT(ctx->ssi_tag_brigade, *bb); - } - else { /* End of brigade contains part of SSI tag... */ - if (ctx->head_start_index > 0) { - apr_bucket_split(ctx->head_start_bucket, ctx->head_start_index); - ctx->head_start_bucket = APR_BUCKET_NEXT(ctx->head_start_bucket); - ctx->head_start_index = 0; - } - /* Set aside tag, pass pre-tag... */ - tag_and_after = apr_brigade_split(*bb, ctx->head_start_bucket); - ap_save_brigade(f, &ctx->ssi_tag_brigade, &tag_and_after); - ap_pass_brigade(f->next, *bb); - ctx->bytes_parsed = 0; - } - } -} - -/***************************************************************** - * - * XBITHACK. Sigh... NB it's configurable per-directory; the compile-time - * option only changes the default. - */ - -module include_module; -enum xbithack { - xbithack_off, xbithack_on, xbithack_full -}; - -typedef struct { - char *default_error_msg; - char *default_time_fmt; - enum xbithack *xbithack; -} include_dir_config; - -#ifdef XBITHACK -#define DEFAULT_XBITHACK xbithack_full -#else -#define DEFAULT_XBITHACK xbithack_off -#endif - -static void *create_includes_dir_config(apr_pool_t *p, char *dummy) -{ - include_dir_config *result = - (include_dir_config *)apr_palloc(p, sizeof(include_dir_config)); - enum xbithack *xbh = (enum xbithack *) apr_palloc(p, sizeof(enum xbithack)); - *xbh = DEFAULT_XBITHACK; - result->default_error_msg = DEFAULT_ERROR_MSG; - result->default_time_fmt = DEFAULT_TIME_FORMAT; - result->xbithack = xbh; - return result; - return result; -} - -static const char *set_xbithack(cmd_parms *cmd, void *xbp, const char *arg) -{ - include_dir_config *conf = (include_dir_config *)xbp; - - if (!strcasecmp(arg, "off")) { - *conf->xbithack = xbithack_off; - } - else if (!strcasecmp(arg, "on")) { - *conf->xbithack = xbithack_on; - } - else if (!strcasecmp(arg, "full")) { - *conf->xbithack = xbithack_full; - } - else { - return "XBitHack must be set to Off, On, or Full"; - } - - return NULL; -} - -static int includes_filter(ap_filter_t *f, apr_bucket_brigade *b) -{ - request_rec *r = f->r; - include_ctx_t *ctx = f->ctx; - request_rec *parent; - include_dir_config *conf = - (include_dir_config *)ap_get_module_config(r->per_dir_config, - &include_module); - - if (!(ap_allow_options(r) & OPT_INCLUDES)) { - return ap_pass_brigade(f->next, b); - } - r->allowed |= (1 << M_GET); - if (r->method_number != M_GET) { - return ap_pass_brigade(f->next, b); - } - - if (!f->ctx) { - f->ctx = ctx = apr_pcalloc(f->c->pool, sizeof(*ctx)); - if (ctx != NULL) { - ctx->state = PRE_HEAD; - ctx->flags = (FLAG_PRINTING | FLAG_COND_TRUE); - if (ap_allow_options(r) & OPT_INCNOEXEC) { - ctx->flags |= FLAG_NO_EXEC; - } - ctx->ssi_tag_brigade = apr_brigade_create(f->c->pool); - - apr_cpystrn(ctx->error_str, conf->default_error_msg, sizeof(ctx->error_str)); - apr_cpystrn(ctx->time_str, conf->default_time_fmt, sizeof(ctx->time_str)); - ctx->error_length = strlen(ctx->error_str); - } - else { - ap_pass_brigade(f->next, b); - return APR_ENOMEM; - } - } - else { - ctx->bytes_parsed = 0; - } - - /* Assure the platform supports Group protections */ - if ((*conf->xbithack == xbithack_full) - && (r->finfo.valid & APR_FINFO_GPROT) - && (r->finfo.protection & APR_GEXECUTE)) { - ap_update_mtime(r, r->finfo.mtime); - ap_set_last_modified(r); - } - - if ((parent = ap_get_module_config(r->request_config, &include_module))) { - /* Kludge --- for nested includes, we want to keep the subprocess - * environment of the base document (for compatibility); that means - * torquing our own last_modified date as well so that the - * LAST_MODIFIED variable gets reset to the proper value if the - * nested document resets <!--#config timefmt-->. - * We also insist that the memory for this subrequest not be - * destroyed, that's dealt with in handle_include(). - */ - r->subprocess_env = r->main->subprocess_env; - apr_pool_join(r->main->pool, r->pool); - r->finfo.mtime = r->main->finfo.mtime; - } - else { - /* we're not a nested include, so we create an initial - * environment */ - ap_add_common_vars(r); - ap_add_cgi_vars(r); - add_include_vars(r, conf->default_time_fmt); - } - /* XXX: this is bogus, at some point we're going to do a subrequest, - * and when we do it we're going to be subjecting code that doesn't - * expect to be signal-ready to SIGALRM. There is no clean way to - * fix this, except to put alarm support into BUFF. -djg - */ - - - /* Always unset the content-length. There is no way to know if - * the content will be modified at some point by send_parsed_content. - * It is very possible for us to not find any content in the first - * 9k of the file, but still have to modify the content of the file. - * If we are going to pass the file through send_parsed_content, then - * the content-length should just be unset. - */ - apr_table_unset(f->r->headers_out, "Content-Length"); - - send_parsed_content(&b, r, f); - - if (parent) { - /* signify that the sub request should not be killed */ - ap_set_module_config(r->request_config, &include_module, - NESTED_INCLUDE_MAGIC); - } - - return OK; -} - -static void ap_register_include_handler(char *tag, include_handler_fn_t *func) -{ - apr_hash_set(include_hash, tag, strlen(tag) + 1, (const void *)func); -} - -static void include_post_config(apr_pool_t *p, apr_pool_t *plog, - apr_pool_t *ptemp, server_rec *s) -{ - include_hash = apr_hash_make(p); - - ssi_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler); - - if(ssi_pfn_register) { - ssi_pfn_register("if", handle_if); - ssi_pfn_register("set", handle_set); - ssi_pfn_register("else", handle_else); - ssi_pfn_register("elif", handle_elif); - ssi_pfn_register("echo", handle_echo); - ssi_pfn_register("endif", handle_endif); - ssi_pfn_register("fsize", handle_fsize); - ssi_pfn_register("config", handle_config); - ssi_pfn_register("include", handle_include); - ssi_pfn_register("flastmod", handle_flastmod); - ssi_pfn_register("printenv", handle_printenv); - } -} - -static const char *set_default_error_msg(cmd_parms *cmd, void *mconfig, const char *msg) -{ - include_dir_config *conf = (include_dir_config *)mconfig; - conf->default_error_msg = apr_pstrdup(cmd->pool, msg); - return NULL; -} - -static const char *set_default_time_fmt(cmd_parms *cmd, void *mconfig, const char *fmt) -{ - include_dir_config *conf = (include_dir_config *)mconfig; - conf->default_time_fmt = apr_pstrdup(cmd->pool, fmt); - return NULL; -} - -/* - * Module definition and configuration data structs... - */ -static const command_rec includes_cmds[] = -{ - AP_INIT_TAKE1("XBitHack", set_xbithack, NULL, OR_OPTIONS, - "Off, On, or Full"), - AP_INIT_TAKE1("SSIErrorMsg", set_default_error_msg, NULL, OR_ALL, - "a string"), - AP_INIT_TAKE1("SSITimeFormat", set_default_time_fmt, NULL, OR_ALL, - "a strftime(3) formatted string"), - {NULL} -}; - -static void register_hooks(apr_pool_t *p) -{ - APR_REGISTER_OPTIONAL_FN(ap_ssi_get_tag_and_value); - APR_REGISTER_OPTIONAL_FN(ap_ssi_parse_string); - APR_REGISTER_OPTIONAL_FN(ap_register_include_handler); - ap_hook_post_config(include_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST); - ap_register_output_filter("INCLUDES", includes_filter, AP_FTYPE_CONTENT); -} - -module AP_MODULE_DECLARE_DATA include_module = -{ - STANDARD20_MODULE_STUFF, - create_includes_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - includes_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/filters/mod_include.exp b/modules/filters/mod_include.exp deleted file mode 100644 index 335da742da..0000000000 --- a/modules/filters/mod_include.exp +++ /dev/null @@ -1 +0,0 @@ -includes_module diff --git a/modules/filters/mod_include.h b/modules/filters/mod_include.h deleted file mode 100644 index 6a92e0a57b..0000000000 --- a/modules/filters/mod_include.h +++ /dev/null @@ -1,214 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef _MOD_INCLUDE_H -#define _MOD_INCLUDE_H 1 - -#define STARTING_SEQUENCE "<!--#" -#define ENDING_SEQUENCE "-->" - -#define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]" -#define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z" -#define SIZEFMT_BYTES 0 -#define SIZEFMT_KMG 1 -#define TMP_BUF_SIZE 1024 -#if APR_CHARSET_EBCDIC -#define RAW_ASCII_CHAR(ch) apr_xlate_conv_byte(ap_hdrs_from_ascii, (unsigned char)ch) -#else /*APR_CHARSET_EBCDIC*/ -#define RAW_ASCII_CHAR(ch) (ch) -#endif /*APR_CHARSET_EBCDIC*/ - -/* just need some arbitrary non-NULL pointer which can't also be a request_rec */ -#define NESTED_INCLUDE_MAGIC (&include_module) - -/**************************************************************************** - * Used to keep context information during parsing of a request for SSI tags. - * This is especially useful if the tag stretches across multiple buckets or - * brigades. This keeps track of which buckets need to be replaced with the - * content generated by the SSI tag. - * - * state: PRE_HEAD - State prior to finding the first character of the - * STARTING_SEQUENCE. Next state is PARSE_HEAD. - * PARSE_HEAD - State entered once the first character of the - * STARTING_SEQUENCE is found and exited when the - * the full STARTING_SEQUENCE has been matched or - * a match failure occurs. Next state is PRE_HEAD - * or PARSE_TAG. - * PARSE_TAG - State entered once the STARTING sequence has been - * matched. It is exited when the first character in - * ENDING_SEQUENCE is found. Next state is PARSE_TAIL. - * PARSE_TAIL - State entered from PARSE_TAG state when the first - * character in ENDING_SEQUENCE is encountered. This - * state is exited when the ENDING_SEQUENCE has been - * completely matched, or when a match failure occurs. - * Next state is PARSE_TAG or PARSED. - * PARSED - State entered from PARSE_TAIL once the complete - * ENDING_SEQUENCE has been matched. The SSI tag is - * processed and the SSI buckets are replaced with the - * SSI content during this state. - * parse_pos: Current matched position within the STARTING_SEQUENCE or - * ENDING_SEQUENCE during the PARSE_HEAD and PARSE_TAIL states. - * This is especially useful when the sequence spans brigades. - * X_start_bucket: These point to the buckets containing the first character - * of the STARTING_SEQUENCE, the first non-whitespace - * character of the tag, and the first character in the - * ENDING_SEQUENCE (head_, tag_, and tail_ respectively). - * The buckets are kept intact until the PARSED state is - * reached, at which time the tag is consolidated and the - * buckets are released. The buckets that these point to - * have all been set aside in the ssi_tag_brigade (along - * with all of the intervening buckets). - * X_start_index: The index points within the specified bucket contents - * where the first character of the STARTING_SEQUENCE, - * the first non-whitespace character of the tag, and the - * first character in the ENDING_SEQUENCE can be found - * (head_, tag_, and tail_ respectively). - * combined_tag: Once the PARSED state is reached the tag is collected from - * the bucket(s) in the ssi_tag_brigade into this contiguous - * buffer. The buckets in the ssi_tag_brigade are released - * and the tag is processed. - * curr_tag_pos: Ptr to the combined_tag buffer indicating the current - * parse position. - * tag_length: The number of bytes in the actual tag (excluding the - * STARTING_SEQUENCE, leading and trailing whitespace, - * and ENDING_SEQUENCE). This length is computed as the - * buckets are parsed and set aside during the PARSE_TAG state. - * ssi_tag_brigade: The temporary brigade used by this filter to set aside - * the buckets containing parts of the ssi tag and headers. - */ -typedef enum {PRE_HEAD, PARSE_HEAD, PARSE_DIRECTIVE, PARSE_TAG, PARSE_TAIL, PARSED} states; -typedef struct include_filter_ctx { - states state; - long flags; /* See the FLAG_XXXXX definitions. */ - int if_nesting_level; - apr_size_t parse_pos; - int bytes_parsed; - - apr_bucket *head_start_bucket; - apr_size_t head_start_index; - - apr_bucket *tag_start_bucket; - apr_size_t tag_start_index; - - apr_bucket *tail_start_bucket; - apr_size_t tail_start_index; - - char *combined_tag; - char *curr_tag_pos; - apr_size_t directive_length; - apr_size_t tag_length; - - apr_size_t error_length; - char error_str[MAX_STRING_LEN]; - char time_str[MAX_STRING_LEN]; - - apr_bucket_brigade *ssi_tag_brigade; -} include_ctx_t; - -/* These flags are used to set flag bits. */ -#define FLAG_PRINTING 0x00000001 /* Printing conditional lines. */ -#define FLAG_COND_TRUE 0x00000002 /* Conditional eval'd to true. */ -#define FLAG_SIZE_IN_BYTES 0x00000004 /* Sizes displayed in bytes. */ -#define FLAG_NO_EXEC 0x00000008 /* No Exec in current context. */ - -/* These flags are used to clear flag bits. */ -#define FLAG_SIZE_ABBREV 0xFFFFFFFB /* Reset SIZE_IN_BYTES bit. */ -#define FLAG_CLEAR_PRINT_COND 0xFFFFFFFC /* Reset PRINTING and COND_TRUE*/ -#define FLAG_CLEAR_PRINTING 0xFFFFFFFE /* Reset just PRINTING bit. */ - -#define CREATE_ERROR_BUCKET(cntx, t_buck, h_ptr, ins_head) \ -{ \ - apr_size_t e_wrt; \ - t_buck = apr_bucket_heap_create(cntx->error_str, \ - cntx->error_length, 1, &e_wrt); \ - APR_BUCKET_INSERT_BEFORE(h_ptr, t_buck); \ - \ - if (ins_head == NULL) { \ - ins_head = t_buck; \ - } \ -} - -#define SPLIT_AND_PASS_PRETAG_BUCKETS(brgd, cntxt, next) \ -if ((APR_BRIGADE_EMPTY(cntxt->ssi_tag_brigade)) && \ - (cntxt->head_start_bucket != NULL)) { \ - apr_bucket_brigade *tag_plus; \ - \ - tag_plus = apr_brigade_split(brgd, cntxt->head_start_bucket); \ - ap_pass_brigade(next, brgd); \ - cntxt->bytes_parsed = 0; \ - brgd = tag_plus; \ -} - - -typedef int (include_handler_fn_t)(include_ctx_t *ctx, apr_bucket_brigade **bb, - request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, - apr_bucket **inserted_head); - -APR_DECLARE_OPTIONAL_FN(void, ap_ssi_get_tag_and_value, (include_ctx_t *ctx, - char **tag, - char **tag_val, - int dodecode)); -APR_DECLARE_OPTIONAL_FN(void, ap_ssi_parse_string, (request_rec *r, - const char *in, - char *out, - size_t length, - int leave_name)); -APR_DECLARE_OPTIONAL_FN(void, ap_register_include_handler, - (char *tag, include_handler_fn_t *func)); - -#endif /* MOD_INCLUDE */ diff --git a/modules/generators/.cvsignore b/modules/generators/.cvsignore deleted file mode 100644 index 65f0cc30cf..0000000000 --- a/modules/generators/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -.deps -.libs -*.la -modules.mk -Makefile -*.lo -*.slo -*.so -Debug -Release diff --git a/modules/generators/.indent.pro b/modules/generators/.indent.pro deleted file mode 100644 index a9fbe9f9a1..0000000000 --- a/modules/generators/.indent.pro +++ /dev/null @@ -1,54 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 --TBUFF --TFILE --TTRANS --TUINT4 --T_trans --Tallow_options_t --Tapache_sfio --Tarray_header --Tbool_int --Tbuf_area --Tbuff_struct --Tbuffy --Tcmd_how --Tcmd_parms --Tcommand_rec --Tcommand_struct --Tconn_rec --Tcore_dir_config --Tcore_server_config --Tdir_maker_func --Tevent --Tglobals_s --Thandler_func --Thandler_rec --Tjoblist_s --Tlisten_rec --Tmerger_func --Tmode_t --Tmodule --Tmodule_struct --Tmutex --Tn_long --Tother_child_rec --Toverrides_t --Tparent_score --Tpid_t --Tpiped_log --Tpool --Trequest_rec --Trequire_line --Trlim_t --Tscoreboard --Tsemaphore --Tserver_addr_rec --Tserver_rec --Tserver_rec_chain --Tshort_score --Ttable --Ttable_entry --Tthread --Tu_wide_int --Tvtime_t --Twide_int diff --git a/modules/generators/Makefile.in b/modules/generators/Makefile.in deleted file mode 100644 index 167b343d0d..0000000000 --- a/modules/generators/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ - -include $(top_srcdir)/build/special.mk - diff --git a/modules/generators/config5.m4 b/modules/generators/config5.m4 deleted file mode 100644 index 4e4379a681..0000000000 --- a/modules/generators/config5.m4 +++ /dev/null @@ -1,29 +0,0 @@ -dnl modules enabled in this directory by default - -dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]]) - -APACHE_MODPATH_INIT(generators) - -APACHE_MODULE(status, process/thread monitoring, , , yes) -APACHE_MODULE(autoindex, directory listing, , , yes) -APACHE_MODULE(asis, as-is filetypes, , , yes) -APACHE_MODULE(info, server information, , , most) -APACHE_MODULE(suexec, set uid and gid for spawned processes, , , no, [ - other_targets=suexec ] ) - -APR_ADDTO(LTFLAGS,-export-dynamic) - -if test "$apache_cv_mpm" = "threaded" -o "$apache_cv_mpm" = "perchild"; then -# if we are using a threaded MPM, we will get better performance with -# mod_cgid, so make it the default. - APACHE_MODULE(cgid, CGI scripts, , , yes) - APACHE_MODULE(cgi, CGI scripts, , , no) -else -# if we are using a non-threaded MPM, it makes little sense to use -# mod_cgid, and it just opens up holes we don't need. Make mod_cgi the -# default - APACHE_MODULE(cgi, CGI scripts, , , yes) - APACHE_MODULE(cgid, CGI scripts, , , no) -fi - -APACHE_MODPATH_FINISH diff --git a/modules/generators/mod_asis.c b/modules/generators/mod_asis.c deleted file mode 100644 index 63594236d5..0000000000 --- a/modules/generators/mod_asis.c +++ /dev/null @@ -1,142 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr_strings.h" -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_protocol.h" -#include "http_log.h" -#include "util_script.h" -#include "http_main.h" -#include "http_request.h" - -#include "mod_core.h" - -#define ASIS_MAGIC_TYPE "httpd/send-as-is" - -static int asis_handler(request_rec *r) -{ - apr_file_t *f = NULL; - apr_status_t status; - const char *location; - apr_size_t nbytes; - - if(strcmp(r->handler,ASIS_MAGIC_TYPE) && strcmp(r->handler,"send-as-is")) - return DECLINED; - - r->allowed |= (1 << M_GET); - if (r->method_number != M_GET) - return DECLINED; - if (r->finfo.filetype == 0) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "File does not exist: %s", r->filename); - return HTTP_NOT_FOUND; - } - - if ((status = apr_file_open(&f, r->filename, APR_READ, - APR_OS_DEFAULT, r->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, - "file permissions deny server access: %s", r->filename); - return HTTP_FORBIDDEN; - } - - ap_scan_script_header_err(r, f, NULL); - location = apr_table_get(r->headers_out, "Location"); - - if (location && location[0] == '/' && - ((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) { - - apr_file_close(f); - - /* Internal redirect -- fake-up a pseudo-request */ - r->status = HTTP_OK; - - /* This redirect needs to be a GET no matter what the original - * method was. - */ - r->method = apr_pstrdup(r->pool, "GET"); - r->method_number = M_GET; - - ap_internal_redirect_handler(location, r); - return OK; - } - - if (!r->header_only) { - ap_send_fd(f, r, 0, r->finfo.size, &nbytes); - } - - apr_file_close(f); - return OK; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_handler(asis_handler,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA asis_module = -{ - STANDARD20_MODULE_STUFF, - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - NULL, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/generators/mod_asis.exp b/modules/generators/mod_asis.exp deleted file mode 100644 index 4f347d921e..0000000000 --- a/modules/generators/mod_asis.exp +++ /dev/null @@ -1 +0,0 @@ -asis_module diff --git a/modules/generators/mod_autoindex.c b/modules/generators/mod_autoindex.c deleted file mode 100644 index 8ede153343..0000000000 --- a/modules/generators/mod_autoindex.c +++ /dev/null @@ -1,1713 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_autoindex.c: Handles the on-the-fly html index generation - * - * Rob McCool - * 3/23/93 - * - * Adapted to Apache by rst. - * - * Version sort added by Martin Pool <mbp@humbug.org.au>. - */ - -#include "apr_strings.h" -#include "apr_fnmatch.h" -#include "apr_strings.h" -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_request.h" -#include "http_protocol.h" -#include "http_log.h" -#include "http_main.h" -#include "util_script.h" - -#include "mod_core.h" - -module AP_MODULE_DECLARE_DATA autoindex_module; - -/**************************************************************** - * - * Handling configuration directives... - */ - -#define HRULE 1 -#define NO_HRULE 0 -#define FRONT_MATTER 1 -#define END_MATTER 0 - -#define FANCY_INDEXING 1 /* Indexing options */ -#define ICONS_ARE_LINKS 2 -#define SCAN_HTML_TITLES 4 -#define SUPPRESS_LAST_MOD 8 -#define SUPPRESS_SIZE 16 -#define SUPPRESS_DESC 32 -#define SUPPRESS_PREAMBLE 64 -#define SUPPRESS_COLSORT 128 -#define NO_OPTIONS 256 -#define VERSION_SORT 512 - -#define K_PAD 1 -#define K_NOPAD 0 - -#define K_NOADJUST 0 -#define K_ADJUST 1 -#define K_UNSET 2 - -/* - * Define keys for sorting. - */ -#define K_NAME 'N' /* Sort by file name (default) */ -#define K_LAST_MOD 'M' /* Last modification date */ -#define K_SIZE 'S' /* Size (absolute, not as displayed) */ -#define K_DESC 'D' /* Description */ - -#define D_ASCENDING 'A' -#define D_DESCENDING 'D' - -/* - * These are the dimensions of the default icons supplied with Apache. - */ -#define DEFAULT_ICON_WIDTH 20 -#define DEFAULT_ICON_HEIGHT 22 - -/* - * Other default dimensions. - */ -#define DEFAULT_NAME_WIDTH 23 - -struct item { - char *type; - char *apply_to; - char *apply_path; - char *data; -}; - -typedef struct ai_desc_t { - char *pattern; - char *description; - int full_path; - int wildcards; -} ai_desc_t; - -typedef struct autoindex_config_struct { - - char *default_icon; - int opts; - int incremented_opts; - int decremented_opts; - int name_width; - int name_adjust; - int icon_width; - int icon_height; - char *default_order; - - apr_array_header_t *icon_list; - apr_array_header_t *alt_list; - apr_array_header_t *desc_list; - apr_array_header_t *ign_list; - apr_array_header_t *hdr_list; - apr_array_header_t *rdme_list; - -} autoindex_config_rec; - -static char c_by_encoding, c_by_type, c_by_path; - -#define BY_ENCODING &c_by_encoding -#define BY_TYPE &c_by_type -#define BY_PATH &c_by_path - -/* - * Return true if the specified string refers to the parent directory (i.e., - * matches ".." or "../"). Hopefully this one call is significantly less - * expensive than multiple strcmp() calls. - */ -static APR_INLINE int is_parent(const char *name) -{ - /* - * Now, IFF the first two bytes are dots, and the third byte is either - * EOS (\0) or a slash followed by EOS, we have a match. - */ - if (((name[0] == '.') && (name[1] == '.')) - && ((name[2] == '\0') - || ((name[2] == '/') && (name[3] == '\0')))) { - return 1; - } - return 0; -} - -/* - * This routine puts the standard HTML header at the top of the index page. - * We include the DOCTYPE because we may be using features therefrom (i.e., - * HEIGHT and WIDTH attributes on the icons if we're FancyIndexing). - */ -static void emit_preamble(request_rec *r, char *title) -{ - ap_rvputs(r, DOCTYPE_HTML_3_2, - "<HTML>\n <HEAD>\n <TITLE>Index of ", title, - "</TITLE>\n </HEAD>\n <BODY>\n", NULL); -} - -static void push_item(apr_array_header_t *arr, char *type, const char *to, - const char *path, const char *data) -{ - struct item *p = (struct item *) apr_array_push(arr); - - if (!to) { - to = ""; - } - if (!path) { - path = ""; - } - - p->type = type; - p->data = data ? apr_pstrdup(arr->cont, data) : NULL; - p->apply_path = apr_pstrcat(arr->cont, path, "*", NULL); - - if ((type == BY_PATH) && (!ap_is_matchexp(to))) { - p->apply_to = apr_pstrcat(arr->cont, "*", to, NULL); - } - else if (to) { - p->apply_to = apr_pstrdup(arr->cont, to); - } - else { - p->apply_to = NULL; - } -} - -static const char *add_alt(cmd_parms *cmd, void *d, const char *alt, - const char *to) -{ - if (cmd->info == BY_PATH) { - if (!strcmp(to, "**DIRECTORY**")) { - to = "^^DIRECTORY^^"; - } - } - if (cmd->info == BY_ENCODING) { - char *tmp = apr_pstrdup(cmd->pool, to); - ap_str_tolower(tmp); - to = tmp; - } - - push_item(((autoindex_config_rec *) d)->alt_list, cmd->info, to, - cmd->path, alt); - return NULL; -} - -static const char *add_icon(cmd_parms *cmd, void *d, const char *icon, - const char *to) -{ - char *iconbak = apr_pstrdup(cmd->pool, icon); - - if (icon[0] == '(') { - char *alt; - char *cl = strchr(iconbak, ')'); - - if (cl == NULL) { - return "missing closing paren"; - } - alt = ap_getword_nc(cmd->pool, &iconbak, ','); - *cl = '\0'; /* Lose closing paren */ - add_alt(cmd, d, &alt[1], to); - } - if (cmd->info == BY_PATH) { - if (!strcmp(to, "**DIRECTORY**")) { - to = "^^DIRECTORY^^"; - } - } - if (cmd->info == BY_ENCODING) { - char *tmp = apr_pstrdup(cmd->pool, to); - ap_str_tolower(tmp); - to = tmp; - } - - push_item(((autoindex_config_rec *) d)->icon_list, cmd->info, to, - cmd->path, iconbak); - return NULL; -} - -/* - * Add description text for a filename pattern. If the pattern has - * wildcards already (or we need to add them), add leading and - * trailing wildcards to it to ensure substring processing. If the - * pattern contains a '/' anywhere, force wildcard matching mode, - * add a slash to the prefix so that "bar/bletch" won't be matched - * by "foobar/bletch", and make a note that there's a delimiter; - * the matching routine simplifies to just the actual filename - * whenever it can. This allows definitions in parent directories - * to be made for files in subordinate ones using relative paths. - */ - -/* - * Absent a strcasestr() function, we have to force wildcards on - * systems for which "AAA" and "aaa" mean the same file. - */ -#ifdef CASE_BLIND_FILESYSTEM -#define WILDCARDS_REQUIRED 1 -#else -#define WILDCARDS_REQUIRED 0 -#endif - -static const char *add_desc(cmd_parms *cmd, void *d, const char *desc, - const char *to) -{ - autoindex_config_rec *dcfg = (autoindex_config_rec *) d; - ai_desc_t *desc_entry; - char *prefix = ""; - - desc_entry = (ai_desc_t *) apr_array_push(dcfg->desc_list); - desc_entry->full_path = (ap_strchr_c(to, '/') == NULL) ? 0 : 1; - desc_entry->wildcards = (WILDCARDS_REQUIRED - || desc_entry->full_path - || apr_is_fnmatch(to)); - if (desc_entry->wildcards) { - prefix = desc_entry->full_path ? "*/" : "*"; - desc_entry->pattern = apr_pstrcat(dcfg->desc_list->cont, - prefix, to, "*", NULL); - } - else { - desc_entry->pattern = apr_pstrdup(dcfg->desc_list->cont, to); - } - desc_entry->description = apr_pstrdup(dcfg->desc_list->cont, desc); - return NULL; -} - -static const char *add_ignore(cmd_parms *cmd, void *d, const char *ext) -{ - push_item(((autoindex_config_rec *) d)->ign_list, 0, ext, cmd->path, NULL); - return NULL; -} - -static const char *add_header(cmd_parms *cmd, void *d, const char *name) -{ - push_item(((autoindex_config_rec *) d)->hdr_list, 0, NULL, cmd->path, - name); - return NULL; -} - -static const char *add_readme(cmd_parms *cmd, void *d, const char *name) -{ - push_item(((autoindex_config_rec *) d)->rdme_list, 0, NULL, cmd->path, - name); - return NULL; -} - -/* A legacy directive, FancyIndexing is superseded by the IndexOptions - * keyword. But for compatibility.. - */ -static const char *fancy_indexing(cmd_parms *cmd, void *d, int arg) -{ - int curopts; - int newopts; - autoindex_config_rec *cfg; - - cfg = (autoindex_config_rec *) d; - curopts = cfg->opts; - if (curopts & NO_OPTIONS) { - return "FancyIndexing directive conflicts with existing " - "IndexOptions None"; - } - newopts = (arg ? (curopts | FANCY_INDEXING) : (curopts & ~FANCY_INDEXING)); - cfg->opts = newopts; - return NULL; -} - -static const char *add_opts(cmd_parms *cmd, void *d, const char *optstr) -{ - char *w; - int opts; - int opts_add; - int opts_remove; - char action; - autoindex_config_rec *d_cfg = (autoindex_config_rec *) d; - - opts = d_cfg->opts; - opts_add = d_cfg->incremented_opts; - opts_remove = d_cfg->decremented_opts; - while (optstr[0]) { - int option = 0; - - w = ap_getword_conf(cmd->pool, &optstr); - if ((*w == '+') || (*w == '-')) { - action = *(w++); - } - else { - action = '\0'; - } - if (!strcasecmp(w, "FancyIndexing")) { - option = FANCY_INDEXING; - } - else if (!strcasecmp(w, "IconsAreLinks")) { - option = ICONS_ARE_LINKS; - } - else if (!strcasecmp(w, "ScanHTMLTitles")) { - option = SCAN_HTML_TITLES; - } - else if (!strcasecmp(w, "SuppressLastModified")) { - option = SUPPRESS_LAST_MOD; - } - else if (!strcasecmp(w, "SuppressSize")) { - option = SUPPRESS_SIZE; - } - else if (!strcasecmp(w, "SuppressDescription")) { - option = SUPPRESS_DESC; - } - else if (!strcasecmp(w, "SuppressHTMLPreamble")) { - option = SUPPRESS_PREAMBLE; - } - else if (!strcasecmp(w, "SuppressColumnSorting")) { - option = SUPPRESS_COLSORT; - } - else if (!strcasecmp(w, "VersionSort")) { - option = VERSION_SORT; - } - else if (!strcasecmp(w, "None")) { - if (action != '\0') { - return "Cannot combine '+' or '-' with 'None' keyword"; - } - opts = NO_OPTIONS; - opts_add = 0; - opts_remove = 0; - } - else if (!strcasecmp(w, "IconWidth")) { - if (action != '-') { - d_cfg->icon_width = DEFAULT_ICON_WIDTH; - } - else { - d_cfg->icon_width = 0; - } - } - else if (!strncasecmp(w, "IconWidth=", 10)) { - if (action == '-') { - return "Cannot combine '-' with IconWidth=n"; - } - d_cfg->icon_width = atoi(&w[10]); - } - else if (!strcasecmp(w, "IconHeight")) { - if (action != '-') { - d_cfg->icon_height = DEFAULT_ICON_HEIGHT; - } - else { - d_cfg->icon_height = 0; - } - } - else if (!strncasecmp(w, "IconHeight=", 11)) { - if (action == '-') { - return "Cannot combine '-' with IconHeight=n"; - } - d_cfg->icon_height = atoi(&w[11]); - } - else if (!strcasecmp(w, "NameWidth")) { - if (action != '-') { - return "NameWidth with no value may only appear as " - "'-NameWidth'"; - } - d_cfg->name_width = DEFAULT_NAME_WIDTH; - d_cfg->name_adjust = K_NOADJUST; - } - else if (!strncasecmp(w, "NameWidth=", 10)) { - if (action == '-') { - return "Cannot combine '-' with NameWidth=n"; - } - if (w[10] == '*') { - d_cfg->name_adjust = K_ADJUST; - } - else { - int width = atoi(&w[10]); - - if (width < 5) { - return "NameWidth value must be greater than 5"; - } - d_cfg->name_width = width; - d_cfg->name_adjust = K_NOADJUST; - } - } - else { - return "Invalid directory indexing option"; - } - if (action == '\0') { - opts |= option; - opts_add = 0; - opts_remove = 0; - } - else if (action == '+') { - opts_add |= option; - opts_remove &= ~option; - } - else { - opts_remove |= option; - opts_add &= ~option; - } - } - if ((opts & NO_OPTIONS) && (opts & ~NO_OPTIONS)) { - return "Cannot combine other IndexOptions keywords with 'None'"; - } - d_cfg->incremented_opts = opts_add; - d_cfg->decremented_opts = opts_remove; - d_cfg->opts = opts; - return NULL; -} - -static const char *set_default_order(cmd_parms *cmd, void *m, const char *direction, - const char *key) -{ - char temp[4]; - autoindex_config_rec *d_cfg = (autoindex_config_rec *) m; - - apr_cpystrn(temp, "k=d", sizeof(temp)); - if (!strcasecmp(direction, "Ascending")) { - temp[2] = D_ASCENDING; - } - else if (!strcasecmp(direction, "Descending")) { - temp[2] = D_DESCENDING; - } - else { - return "First keyword must be 'Ascending' or 'Descending'"; - } - - if (!strcasecmp(key, "Name")) { - temp[0] = K_NAME; - } - else if (!strcasecmp(key, "Date")) { - temp[0] = K_LAST_MOD; - } - else if (!strcasecmp(key, "Size")) { - temp[0] = K_SIZE; - } - else if (!strcasecmp(key, "Description")) { - temp[0] = K_DESC; - } - else { - return "Second keyword must be 'Name', 'Date', 'Size', or " - "'Description'"; - } - - if (d_cfg->default_order == NULL) { - d_cfg->default_order = apr_palloc(cmd->pool, 4); - d_cfg->default_order[3] = '\0'; - } - apr_cpystrn(d_cfg->default_order, temp, sizeof(temp)); - return NULL; -} - -#define DIR_CMD_PERMS OR_INDEXES - -static const command_rec autoindex_cmds[] = -{ - AP_INIT_ITERATE2("AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS, - "an icon URL followed by one or more filenames"), - AP_INIT_ITERATE2("AddIconByType", add_icon, BY_TYPE, DIR_CMD_PERMS, - "an icon URL followed by one or more MIME types"), - AP_INIT_ITERATE2("AddIconByEncoding", add_icon, BY_ENCODING, DIR_CMD_PERMS, - "an icon URL followed by one or more content encodings"), - AP_INIT_ITERATE2("AddAlt", add_alt, BY_PATH, DIR_CMD_PERMS, - "alternate descriptive text followed by one or more filenames"), - AP_INIT_ITERATE2("AddAltByType", add_alt, BY_TYPE, DIR_CMD_PERMS, - "alternate descriptive text followed by one or more MIME types"), - AP_INIT_ITERATE2("AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS, - "alternate descriptive text followed by one or more content encodings"), - AP_INIT_RAW_ARGS("IndexOptions", add_opts, NULL, DIR_CMD_PERMS, - "one or more index options"), - AP_INIT_TAKE2("IndexOrderDefault", set_default_order, NULL, DIR_CMD_PERMS, - "{Ascending,Descending} {Name,Size,Description,Date}"), - AP_INIT_ITERATE("IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS, - "one or more file extensions"), - AP_INIT_ITERATE2("AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS, - "Descriptive text followed by one or more filenames"), - AP_INIT_TAKE1("HeaderName", add_header, NULL, DIR_CMD_PERMS, - "a filename"), - AP_INIT_TAKE1("ReadmeName", add_readme, NULL, DIR_CMD_PERMS, - "a filename"), - AP_INIT_FLAG("FancyIndexing", fancy_indexing, NULL, DIR_CMD_PERMS, - "Limited to 'on' or 'off' (superseded by IndexOptions FancyIndexing)"), - AP_INIT_TAKE1("DefaultIcon", ap_set_string_slot, - (void *) XtOffsetOf(autoindex_config_rec, default_icon), - DIR_CMD_PERMS, "an icon URL"), - {NULL} -}; - -static void *create_autoindex_config(apr_pool_t *p, char *dummy) -{ - autoindex_config_rec *new = - (autoindex_config_rec *) apr_pcalloc(p, sizeof(autoindex_config_rec)); - - new->icon_width = 0; - new->icon_height = 0; - new->name_width = DEFAULT_NAME_WIDTH; - new->name_adjust = K_UNSET; - new->icon_list = apr_array_make(p, 4, sizeof(struct item)); - new->alt_list = apr_array_make(p, 4, sizeof(struct item)); - new->desc_list = apr_array_make(p, 4, sizeof(ai_desc_t)); - new->ign_list = apr_array_make(p, 4, sizeof(struct item)); - new->hdr_list = apr_array_make(p, 4, sizeof(struct item)); - new->rdme_list = apr_array_make(p, 4, sizeof(struct item)); - new->opts = 0; - new->incremented_opts = 0; - new->decremented_opts = 0; - new->default_order = NULL; - - return (void *) new; -} - -static void *merge_autoindex_configs(apr_pool_t *p, void *basev, void *addv) -{ - autoindex_config_rec *new; - autoindex_config_rec *base = (autoindex_config_rec *) basev; - autoindex_config_rec *add = (autoindex_config_rec *) addv; - - new = (autoindex_config_rec *) apr_pcalloc(p, sizeof(autoindex_config_rec)); - new->default_icon = add->default_icon ? add->default_icon - : base->default_icon; - new->icon_height = add->icon_height ? add->icon_height : base->icon_height; - new->icon_width = add->icon_width ? add->icon_width : base->icon_width; - - new->alt_list = apr_array_append(p, add->alt_list, base->alt_list); - new->ign_list = apr_array_append(p, add->ign_list, base->ign_list); - new->hdr_list = apr_array_append(p, add->hdr_list, base->hdr_list); - new->desc_list = apr_array_append(p, add->desc_list, base->desc_list); - new->icon_list = apr_array_append(p, add->icon_list, base->icon_list); - new->rdme_list = apr_array_append(p, add->rdme_list, base->rdme_list); - if (add->opts & NO_OPTIONS) { - /* - * If the current directory says 'no options' then we also - * clear any incremental mods from being inheritable further down. - */ - new->opts = NO_OPTIONS; - new->incremented_opts = 0; - new->decremented_opts = 0; - } - else { - /* - * If there were any nonincremental options selected for - * this directory, they dominate and we don't inherit *anything.* - * Contrariwise, we *do* inherit if the only settings here are - * incremental ones. - */ - if (add->opts == 0) { - new->incremented_opts = (base->incremented_opts - | add->incremented_opts) - & ~add->decremented_opts; - new->decremented_opts = (base->decremented_opts - | add->decremented_opts); - /* - * We may have incremental settings, so make sure we don't - * inadvertently inherit an IndexOptions None from above. - */ - new->opts = (base->opts & ~NO_OPTIONS); - } - else { - /* - * There are local nonincremental settings, which clear - * all inheritance from above. They *are* the new base settings. - */ - new->opts = add->opts;; - } - /* - * We're guaranteed that there'll be no overlap between - * the add-options and the remove-options. - */ - new->opts |= new->incremented_opts; - new->opts &= ~new->decremented_opts; - } - /* - * Inherit the NameWidth settings if there aren't any specific to - * the new location; otherwise we'll end up using the defaults set in the - * config-rec creation routine. - */ - if (add->name_adjust == K_UNSET) { - new->name_width = base->name_width; - new->name_adjust = base->name_adjust; - } - else { - new->name_width = add->name_width; - new->name_adjust = add->name_adjust; - } - - new->default_order = (add->default_order != NULL) - ? add->default_order : base->default_order; - return new; -} - -/**************************************************************** - * - * Looking things up in config entries... - */ - -/* Structure used to hold entries when we're actually building an index */ - -struct ent { - char *name; - char *icon; - char *alt; - char *desc; - off_t size; - apr_time_t lm; - struct ent *next; - int ascending, version_sort; - char key; -}; - -static char *find_item(request_rec *r, apr_array_header_t *list, int path_only) -{ - const char *content_type = ap_field_noparam(r->pool, r->content_type); - const char *content_encoding = r->content_encoding; - char *path = r->filename; - - struct item *items = (struct item *) list->elts; - int i; - - for (i = 0; i < list->nelts; ++i) { - struct item *p = &items[i]; - - /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */ - if ((path[0] == '^') || (!ap_strcmp_match(path, p->apply_path))) { - if (!*(p->apply_to)) { - return p->data; - } - else if (p->type == BY_PATH || path[0] == '^') { - if (!ap_strcmp_match(path, p->apply_to)) { - return p->data; - } - } - else if (!path_only) { - if (!content_encoding) { - if (p->type == BY_TYPE) { - if (content_type - && !ap_strcasecmp_match(content_type, - p->apply_to)) { - return p->data; - } - } - } - else { - if (p->type == BY_ENCODING) { - if (!ap_strcasecmp_match(content_encoding, - p->apply_to)) { - return p->data; - } - } - } - } - } - } - return NULL; -} - -#define find_icon(d,p,t) find_item(p,d->icon_list,t) -#define find_alt(d,p,t) find_item(p,d->alt_list,t) -#define find_header(d,p) find_item(p,d->hdr_list,0) -#define find_readme(d,p) find_item(p,d->rdme_list,0) - -static char *find_default_icon(autoindex_config_rec *d, char *bogus_name) -{ - request_rec r; - - /* Bleah. I tried to clean up find_item, and it lead to this bit - * of ugliness. Note that the fields initialized are precisely - * those that find_item looks at... - */ - - r.filename = bogus_name; - r.content_type = r.content_encoding = NULL; - - return find_item(&r, d->icon_list, 1); -} - -/* - * Look through the list of pattern/description pairs and return the first one - * if any) that matches the filename in the request. If multiple patterns - * match, only the first one is used; since the order in the array is the - * same as the order in which directives were processed, earlier matching - * directives will dominate. - */ - -#ifdef CASE_BLIND_FILESYSTEM -#define MATCH_FLAGS FNM_CASE_BLIND -#else -#define MATCH_FLAGS 0 -#endif - -static char *find_desc(autoindex_config_rec *dcfg, request_rec *r) -{ - int i; - ai_desc_t *list = (ai_desc_t *) dcfg->desc_list->elts; - const char *filename_full = r->filename; - const char *filename_only; - const char *filename; - - /* - * If the filename includes a path, extract just the name itself - * for the simple matches. - */ - if ((filename_only = ap_strrchr_c(filename_full, '/')) == NULL) { - filename_only = filename_full; - } - else { - filename_only++; - } - for (i = 0; i < dcfg->desc_list->nelts; ++i) { - ai_desc_t *tuple = &list[i]; - int found; - - /* - * Only use the full-path filename if the pattern contains '/'s. - */ - filename = (tuple->full_path) ? filename_full : filename_only; - /* - * Make the comparison using the cheapest method; only do - * wildcard checking if we must. - */ - if (tuple->wildcards) { - found = (apr_fnmatch(tuple->pattern, filename, MATCH_FLAGS) == 0); - } - else { - found = (ap_strstr_c(filename, tuple->pattern) != NULL); - } - if (found) { - return tuple->description; - } - } - return NULL; -} - -static int ignore_entry(autoindex_config_rec *d, char *path) -{ - apr_array_header_t *list = d->ign_list; - struct item *items = (struct item *) list->elts; - char *tt; - int i; - - if ((tt = strrchr(path, '/')) == NULL) { - tt = path; - } - else { - tt++; - } - - for (i = 0; i < list->nelts; ++i) { - struct item *p = &items[i]; - char *ap; - - if ((ap = strrchr(p->apply_to, '/')) == NULL) { - ap = p->apply_to; - } - else { - ap++; - } - -#ifndef CASE_BLIND_FILESYSTEM - if (!ap_strcmp_match(path, p->apply_path) - && !ap_strcmp_match(tt, ap)) { - return 1; - } -#else /* !CASE_BLIND_FILESYSTEM */ - /* - * On some platforms, the match must be case-blind. This is really - * a factor of the filesystem involved, but we can't detect that - * reliably - so we have to granularise at the OS level. - */ - if (!ap_strcasecmp_match(path, p->apply_path) - && !ap_strcasecmp_match(tt, ap)) { - return 1; - } -#endif /* !CASE_BLIND_FILESYSTEM */ - } - return 0; -} - -/***************************************************************** - * - * Actually generating output - */ - -/* - * Elements of the emitted document: - * Preamble - * Emitted unless SUPPRESS_PREAMBLE is set AND ap_run_sub_req - * succeeds for the (content_type == text/html) header file. - * Header file - * Emitted if found (and able). - * H1 tag line - * Emitted if a header file is NOT emitted. - * Directory stuff - * Always emitted. - * HR - * Emitted if FANCY_INDEXING is set. - * Readme file - * Emitted if found (and able). - * ServerSig - * Emitted if ServerSignature is not Off AND a readme file - * is NOT emitted. - * Postamble - * Emitted unless SUPPRESS_PREAMBLE is set AND ap_run_sub_req - * succeeds for the (content_type == text/html) readme file. - */ - - -/* - * emit a plain text file - */ -static void do_emit_plain(request_rec *r, apr_file_t *f) -{ - char buf[AP_IOBUFSIZE + 1]; - int i, c, ch; - apr_size_t n; - apr_status_t stat; - - ap_rputs("<PRE>\n", r); - while (!apr_file_eof(f)) { - do { - n = sizeof(char) * AP_IOBUFSIZE; - stat = apr_file_read(f, buf, &n); - } - while (stat != APR_SUCCESS && APR_STATUS_IS_EINTR(stat)); - if (n == -1 || n == 0) { - break; - } - buf[n] = '\0'; - c = 0; - while (c < n) { - for (i = c; i < n; i++) { - if (buf[i] == '<' || buf[i] == '>' || buf[i] == '&') { - break; - } - } - ch = buf[i]; - buf[i] = '\0'; - ap_rputs(&buf[c], r); - if (ch == '<') { - ap_rputs("<", r); - } - else if (ch == '>') { - ap_rputs(">", r); - } - else if (ch == '&') { - ap_rputs("&", r); - } - c = i + 1; - } - } - ap_rputs("</PRE>\n", r); -} - -/* - * Handle the preamble through the H1 tag line, inclusive. Locate - * the file with a subrequests. Process text/html documents by actually - * running the subrequest; text/xxx documents get copied verbatim, - * and any other content type is ignored. This means that a non-text - * document (such as HEADER.gif) might get multiviewed as the result - * instead of a text document, meaning nothing will be displayed, but - * oh well. - */ -static void emit_head(request_rec *r, char *header_fname, int suppress_amble, - char *title) -{ - apr_file_t *f = NULL; - request_rec *rr = NULL; - int emit_amble = 1; - int emit_H1 = 1; - - /* - * If there's a header file, send a subrequest to look for it. If it's - * found and a text file, handle it -- otherwise fall through and - * pretend there's nothing there. - */ - if ((header_fname != NULL) - && (rr = ap_sub_req_lookup_uri(header_fname, r, NULL)) - && (rr->status == HTTP_OK) - && (rr->filename != NULL) - && rr->finfo.filetype == APR_REG) { - /* - * Check for the two specific cases we allow: text/html and - * text/anything-else. The former is allowed to be processed for - * SSIs. - */ - if (rr->content_type != NULL) { - if (!strcasecmp(ap_field_noparam(r->pool, rr->content_type), - "text/html")) { - /* Hope everything will work... */ - emit_amble = 0; - emit_H1 = 0; - - if (! suppress_amble) { - emit_preamble(r, title); - } - /* - * If there's a problem running the subrequest, display the - * preamble if we didn't do it before -- the header file - * didn't get displayed. - */ - if (ap_run_sub_req(rr) != OK) { - /* It didn't work */ - emit_amble = suppress_amble; - emit_H1 = 1; - } - } - else if (!strncasecmp("text/", rr->content_type, 5)) { - /* - * If we can open the file, prefix it with the preamble - * regardless; since we'll be sending a <PRE> block around - * the file's contents, any HTML header it had won't end up - * where it belongs. - */ - if (apr_file_open(&f, rr->filename, APR_READ, - APR_OS_DEFAULT, r->pool) == APR_SUCCESS) { - emit_preamble(r, title); - emit_amble = 0; - do_emit_plain(r, f); - apr_file_close(f); - emit_H1 = 0; - } - } - } - } - - if (emit_amble) { - emit_preamble(r, title); - } - if (emit_H1) { - ap_rvputs(r, "<H1>Index of ", title, "</H1>\n", NULL); - } - if (rr != NULL) { - ap_destroy_sub_req(rr); - } -} - - -/* - * Handle the Readme file through the postamble, inclusive. Locate - * the file with a subrequests. Process text/html documents by actually - * running the subrequest; text/xxx documents get copied verbatim, - * and any other content type is ignored. This means that a non-text - * document (such as FOOTER.gif) might get multiviewed as the result - * instead of a text document, meaning nothing will be displayed, but - * oh well. - */ -static void emit_tail(request_rec *r, char *readme_fname, int suppress_amble) -{ - apr_file_t *f = NULL; - request_rec *rr = NULL; - int suppress_post = 0; - int suppress_sig = 0; - - /* - * If there's a readme file, send a subrequest to look for it. If it's - * found and a text file, handle it -- otherwise fall through and - * pretend there's nothing there. - */ - if ((readme_fname != NULL) - && (rr = ap_sub_req_lookup_uri(readme_fname, r, NULL)) - && (rr->status == HTTP_OK) - && (rr->filename != NULL) - && rr->finfo.filetype == APR_REG) { - /* - * Check for the two specific cases we allow: text/html and - * text/anything-else. The former is allowed to be processed for - * SSIs. - */ - if (rr->content_type != NULL) { - if (!strcasecmp(ap_field_noparam(r->pool, rr->content_type), - "text/html")) { - if (ap_run_sub_req(rr) == OK) { - /* worked... */ - suppress_sig = 1; - suppress_post = suppress_amble; - } - } - else if (!strncasecmp("text/", rr->content_type, 5)) { - /* - * If we can open the file, suppress the signature. - */ - if (apr_file_open(&f, rr->filename, APR_READ, - APR_OS_DEFAULT, r->pool) == APR_SUCCESS) { - do_emit_plain(r, f); - apr_file_close(f); - suppress_sig = 1; - } - } - } - } - - if (!suppress_sig) { - ap_rputs(ap_psignature("", r), r); - } - if (!suppress_post) { - ap_rputs("</BODY></HTML>\n", r); - } - if (rr != NULL) { - ap_destroy_sub_req(rr); - } -} - - -static char *find_title(request_rec *r) -{ - char titlebuf[MAX_STRING_LEN], *find = "<TITLE>"; - apr_file_t *thefile = NULL; - int x, y, p; - apr_size_t n; - - if (r->status != HTTP_OK) { - return NULL; - } - if ((r->content_type != NULL) - && (!strcasecmp(ap_field_noparam(r->pool, r->content_type), - "text/html") - || !strcmp(r->content_type, INCLUDES_MAGIC_TYPE)) - && !r->content_encoding) { - if (apr_file_open(&thefile, r->filename, APR_READ, - APR_OS_DEFAULT, r->pool) != APR_SUCCESS) { - return NULL; - } - n = sizeof(char) * (MAX_STRING_LEN - 1); - apr_file_read(thefile, titlebuf, &n); - if (n <= 0) { - apr_file_close(thefile); - return NULL; - } - titlebuf[n] = '\0'; - for (x = 0, p = 0; titlebuf[x]; x++) { - if (apr_toupper(titlebuf[x]) == find[p]) { - if (!find[++p]) { - if ((p = ap_ind(&titlebuf[++x], '<')) != -1) { - titlebuf[x + p] = '\0'; - } - /* Scan for line breaks for Tanmoy's secretary */ - for (y = x; titlebuf[y]; y++) { - if ((titlebuf[y] == CR) || (titlebuf[y] == LF)) { - if (y == x) { - x++; - } - else { - titlebuf[y] = ' '; - } - } - } - apr_file_close(thefile); - return apr_pstrdup(r->pool, &titlebuf[x]); - } - } - else { - p = 0; - } - } - apr_file_close(thefile); - } - return NULL; -} - -static struct ent *make_autoindex_entry(const char *name, int autoindex_opts, - autoindex_config_rec *d, - request_rec *r, char keyid, - char direction) -{ - struct ent *p; - - if ((name[0] == '.') && (!name[1])) { - return (NULL); - } - - if (ignore_entry(d, ap_make_full_path(r->pool, r->filename, name))) { - return (NULL); - } - - p = (struct ent *) apr_pcalloc(r->pool, sizeof(struct ent)); - p->name = apr_pstrdup(r->pool, name); - p->size = -1; - p->icon = NULL; - p->alt = NULL; - p->desc = NULL; - p->lm = -1; - p->key = apr_toupper(keyid); - p->ascending = (apr_toupper(direction) == D_ASCENDING); - p->version_sort = autoindex_opts & VERSION_SORT; - - if (autoindex_opts & FANCY_INDEXING) { - request_rec *rr = ap_sub_req_lookup_file(name, r, NULL); - - if (rr->finfo.filetype != 0) { - p->lm = rr->finfo.mtime; - if (rr->finfo.filetype == APR_DIR) { - if (!(p->icon = find_icon(d, rr, 1))) { - p->icon = find_default_icon(d, "^^DIRECTORY^^"); - } - if (!(p->alt = find_alt(d, rr, 1))) { - p->alt = "DIR"; - } - p->size = -1; - p->name = apr_pstrcat(r->pool, name, "/", NULL); - } - else { - p->icon = find_icon(d, rr, 0); - p->alt = find_alt(d, rr, 0); - p->size = rr->finfo.size; - } - } - - p->desc = find_desc(d, rr); - - if ((!p->desc) && (autoindex_opts & SCAN_HTML_TITLES)) { - p->desc = apr_pstrdup(r->pool, find_title(rr)); - } - - ap_destroy_sub_req(rr); - } - /* - * We don't need to take any special action for the file size key. If - * we did, it would go here. - */ - if (keyid == K_LAST_MOD) { - if (p->lm < 0) { - p->lm = 0; - } - } - return (p); -} - -static char *terminate_description(autoindex_config_rec *d, char *desc, - int autoindex_opts) -{ - int maxsize = 23; - register int x; - - if (autoindex_opts & SUPPRESS_LAST_MOD) { - maxsize += 19; - } - if (autoindex_opts & SUPPRESS_SIZE) { - maxsize += 7; - } - - for (x = 0; desc[x] && (maxsize > 0 || desc[x]=='<'); x++) { - if (desc[x] == '<') { - while (desc[x] != '>') { - if (!desc[x]) { - maxsize = 0; - break; - } - ++x; - } - } - else if (desc[x] == '&') { - /* entities like ä count as one character */ - --maxsize; - for ( ; desc[x] != ';'; ++x) { - if (desc[x] == '\0') { - maxsize = 0; - break; - } - } - } - else { - --maxsize; - } - } - if (!maxsize && desc[x] != '\0') { - desc[x - 1] = '>'; /* Grump. */ - desc[x] = '\0'; /* Double Grump! */ - } - return desc; -} - -/* - * Emit the anchor for the specified field. If a field is the key for the - * current request, the link changes its meaning to reverse the order when - * selected again. Non-active fields always start in ascending order. - */ -static void emit_link(request_rec *r, char *anchor, char fname, char curkey, - char curdirection, int nosort) -{ - char qvalue[5]; - int reverse; - - if (!nosort) { - qvalue[0] = '?'; - qvalue[1] = fname; - qvalue[2] = '='; - qvalue[4] = '\0'; - reverse = ((curkey == fname) && (curdirection == D_ASCENDING)); - qvalue[3] = reverse ? D_DESCENDING : D_ASCENDING; - ap_rvputs(r, "<A HREF=\"", qvalue, "\">", anchor, "</A>", NULL); - } - else { - ap_rputs(anchor, r); - } -} - -static void output_directories(struct ent **ar, int n, - autoindex_config_rec *d, request_rec *r, - int autoindex_opts, char keyid, char direction) -{ - int x; - apr_size_t rv; - char *name = r->uri; - char *tp; - int static_columns = (autoindex_opts & SUPPRESS_COLSORT); - apr_pool_t *scratch; - int name_width; - char *name_scratch; - char *pad_scratch; - - apr_pool_create(&scratch, r->pool); - if (name[0] == '\0') { - name = "/"; - } - - name_width = d->name_width; - if (d->name_adjust == K_ADJUST) { - for (x = 0; x < n; x++) { - int t = strlen(ar[x]->name); - if (t > name_width) { - name_width = t; - } - } - } - name_scratch = apr_palloc(r->pool, name_width + 1); - pad_scratch = apr_palloc(r->pool, name_width + 1); - memset(pad_scratch, ' ', name_width); - pad_scratch[name_width] = '\0'; - - if (autoindex_opts & FANCY_INDEXING) { - ap_rputs("<PRE>", r); - if ((tp = find_default_icon(d, "^^BLANKICON^^"))) { - ap_rvputs(r, "<IMG SRC=\"", ap_escape_html(scratch, tp), - "\" ALT=\" \"", NULL); - if (d->icon_width && d->icon_height) { - ap_rprintf - ( - r, - " HEIGHT=\"%d\" WIDTH=\"%d\"", - d->icon_height, - d->icon_width - ); - } - ap_rputs("> ", r); - } - emit_link(r, "Name", K_NAME, keyid, direction, static_columns); - ap_rputs(pad_scratch + 4, r); - /* - * Emit the guaranteed-at-least-one-space-between-columns byte. - */ - ap_rputs(" ", r); - if (!(autoindex_opts & SUPPRESS_LAST_MOD)) { - emit_link(r, "Last modified", K_LAST_MOD, keyid, direction, - static_columns); - ap_rputs(" ", r); - } - if (!(autoindex_opts & SUPPRESS_SIZE)) { - emit_link(r, "Size", K_SIZE, keyid, direction, static_columns); - ap_rputs(" ", r); - } - if (!(autoindex_opts & SUPPRESS_DESC)) { - emit_link(r, "Description", K_DESC, keyid, direction, - static_columns); - } - ap_rputs("\n<HR>\n", r); - } - else { - ap_rputs("<UL>", r); - } - - for (x = 0; x < n; x++) { - char *anchor, *t, *t2; - int nwidth; - - apr_pool_clear(scratch); - - if (is_parent(ar[x]->name)) { - t = ap_make_full_path(scratch, name, "../"); - ap_getparents(t); - if (t[0] == '\0') { - t = "/"; - } - t2 = "Parent Directory"; - anchor = ap_escape_html(scratch, ap_os_escape_path(scratch, t, 0)); - } - else { - t = ar[x]->name; - t2 = t; - anchor = ap_escape_html(scratch, ap_os_escape_path(scratch, t, 0)); - } - - if (autoindex_opts & FANCY_INDEXING) { - if (autoindex_opts & ICONS_ARE_LINKS) { - ap_rvputs(r, "<A HREF=\"", anchor, "\">", NULL); - } - if ((ar[x]->icon) || d->default_icon) { - ap_rvputs(r, "<IMG SRC=\"", - ap_escape_html(scratch, - ar[x]->icon ? ar[x]->icon - : d->default_icon), - "\" ALT=\"[", (ar[x]->alt ? ar[x]->alt : " "), - "]\"", NULL); - if (d->icon_width && d->icon_height) { - ap_rprintf(r, " HEIGHT=\"%d\" WIDTH=\"%d\"", - d->icon_height, d->icon_width); - } - ap_rputs(">", r); - } - if (autoindex_opts & ICONS_ARE_LINKS) { - ap_rputs("</A>", r); - } - - nwidth = strlen(t2); - if (nwidth > name_width) { - memcpy(name_scratch, t2, name_width - 3); - name_scratch[name_width - 3] = '.'; - name_scratch[name_width - 2] = '.'; - name_scratch[name_width - 1] = '>'; - name_scratch[name_width] = 0; - t2 = name_scratch; - nwidth = name_width; - } - ap_rvputs(r, " <A HREF=\"", anchor, "\">", - ap_escape_html(scratch, t2), "</A>", pad_scratch + nwidth, - NULL); - /* - * The blank before the storm.. er, before the next field. - */ - ap_rputs(" ", r); - if (!(autoindex_opts & SUPPRESS_LAST_MOD)) { - if (ar[x]->lm != -1) { - char time_str[MAX_STRING_LEN]; - apr_exploded_time_t ts; - apr_explode_localtime(&ts, ar[x]->lm); - apr_strftime(time_str, &rv, MAX_STRING_LEN, - "%d-%b-%Y %H:%M ", &ts); - ap_rputs(time_str, r); - } - else { - /*Length="22-Feb-1998 23:42 " (see 4 lines above) */ - ap_rputs(" ", r); - } - } - if (!(autoindex_opts & SUPPRESS_SIZE)) { - ap_send_size(ar[x]->size, r); - ap_rputs(" ", r); - } - if (!(autoindex_opts & SUPPRESS_DESC)) { - if (ar[x]->desc) { - ap_rputs(terminate_description(d, ar[x]->desc, - autoindex_opts), r); - } - } - } - else { - ap_rvputs(r, "<LI><A HREF=\"", anchor, "\"> ", t2, - "</A>", NULL); - } - ap_rputc('\n', r); - } - if (autoindex_opts & FANCY_INDEXING) { - ap_rputs("</PRE>", r); - } - else { - ap_rputs("</UL>", r); - } -} - -/* - * Compare two file entries according to the sort criteria. The return - * is essentially a signum function value. - */ - -static int dsortf(struct ent **e1, struct ent **e2) -{ - struct ent *c1; - struct ent *c2; - int result = 0; - - /* - * First, see if either of the entries is for the parent directory. - * If so, that *always* sorts lower than anything else. - */ - if (is_parent((*e1)->name)) { - return -1; - } - if (is_parent((*e2)->name)) { - return 1; - } - /* - * All of our comparisons will be of the c1 entry against the c2 one, - * so assign them appropriately to take care of the ordering. - */ - if ((*e1)->ascending) { - c1 = *e1; - c2 = *e2; - } - else { - c1 = *e2; - c2 = *e1; - } - - switch (c1->key) { - case K_LAST_MOD: - if (c1->lm > c2->lm) { - return 1; - } - else if (c1->lm < c2->lm) { - return -1; - } - break; - case K_SIZE: - if (c1->size > c2->size) { - return 1; - } - else if (c1->size < c2->size) { - return -1; - } - break; - case K_DESC: - if (c1->version_sort) - result = apr_strnatcmp(c1->desc ? c1->desc : "", c2->desc ? c2->desc : ""); - else - result = strcmp(c1->desc ? c1->desc : "", c2->desc ? c2->desc : ""); - if (result) { - return result; - } - break; - } - if (c1->version_sort) - return apr_strnatcmp(c1->name, c2->name); - else - return strcmp(c1->name, c2->name); -} - - -static int index_directory(request_rec *r, - autoindex_config_rec *autoindex_conf) -{ - char *title_name = ap_escape_html(r->pool, r->uri); - char *title_endp; - char *name = r->filename; - apr_finfo_t dirent; - apr_dir_t *thedir; - apr_status_t status; - int num_ent = 0, x; - struct ent *head, *p; - struct ent **ar = NULL; - const char *qstring; - int autoindex_opts = autoindex_conf->opts; - char keyid; - char direction; - - if ((status = apr_dir_open(&thedir, name, r->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, - "Can't open directory for index: %s", r->filename); - return HTTP_FORBIDDEN; - } - -#if APR_HAS_UNICODE_FS - r->content_type = "text/html;charset=utf-8"; -#else - r->content_type = "text/html"; -#endif - ap_update_mtime(r, r->finfo.mtime); - ap_set_last_modified(r); - ap_set_etag(r); - - if (r->header_only) { - apr_dir_close(thedir); - return 0; - } - - /* Spew HTML preamble */ - - title_endp = title_name + strlen(title_name) - 1; - - while (title_endp > title_name && *title_endp == '/') { - *title_endp-- = '\0'; - } - - emit_head(r, find_header(autoindex_conf, r), - autoindex_opts & SUPPRESS_PREAMBLE, title_name); - - /* - * Figure out what sort of indexing (if any) we're supposed to use. - * - * If no QUERY_STRING was specified or column sorting has been - * explicitly disabled, we use the default specified by the - * IndexOrderDefault directive (if there is one); otherwise, - * we fall back to ascending by name. - */ - qstring = r->args; - if ((autoindex_opts & SUPPRESS_COLSORT) - || ((qstring == NULL) || (*qstring == '\0'))) { - qstring = autoindex_conf->default_order; - } - /* - * If there is no specific ordering defined for this directory, - * default to ascending by filename. - */ - if ((qstring == NULL) || (*qstring == '\0')) { - keyid = K_NAME; - direction = D_ASCENDING; - } - else { - keyid = *qstring; - ap_getword(r->pool, &qstring, '='); - if (qstring != '\0') { - direction = *qstring; - } - else { - direction = D_ASCENDING; - } - } - - /* - * Since we don't know how many dir. entries there are, put them into a - * linked list and then arrayificate them so qsort can use them. - */ - head = NULL; - while (apr_dir_read(&dirent, APR_FINFO_DIRENT, thedir) == APR_SUCCESS) { - p = make_autoindex_entry(dirent.name, autoindex_opts, - autoindex_conf, r, keyid, direction); - if (p != NULL) { - p->next = head; - head = p; - num_ent++; - } - } - if (num_ent > 0) { - ar = (struct ent **) apr_palloc(r->pool, - num_ent * sizeof(struct ent *)); - p = head; - x = 0; - while (p) { - ar[x++] = p; - p = p->next; - } - - qsort((void *) ar, num_ent, sizeof(struct ent *), - (int (*)(const void *, const void *)) dsortf); - } - output_directories(ar, num_ent, autoindex_conf, r, autoindex_opts, keyid, - direction); - apr_dir_close(thedir); - - if (autoindex_opts & FANCY_INDEXING) { - ap_rputs("<HR>\n", r); - } - emit_tail(r, find_readme(autoindex_conf, r), - autoindex_opts & SUPPRESS_PREAMBLE); - - return 0; -} - -/* The formal handler... */ - -static int handle_autoindex(request_rec *r) -{ - autoindex_config_rec *d; - int allow_opts; - - if(strcmp(r->handler,DIR_MAGIC_TYPE)) - return DECLINED; - - allow_opts = ap_allow_options(r); - - d = (autoindex_config_rec *) ap_get_module_config(r->per_dir_config, - &autoindex_module); - - r->allowed |= (1 << M_GET); - if (r->method_number != M_GET) { - return DECLINED; - } - - /* OK, nothing easy. Trot out the heavy artillery... */ - - if (allow_opts & OPT_INDEXES) { - /* KLUDGE --- make the sub_req lookups happen in the right directory. - * Fixing this in the sub_req_lookup functions themselves is difficult, - * and would probably break virtual includes... - */ - - if (r->filename[strlen(r->filename) - 1] != '/') { - r->filename = apr_pstrcat(r->pool, r->filename, "/", NULL); - } - return index_directory(r, d); - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Directory index forbidden by rule: %s", r->filename); - return HTTP_FORBIDDEN; - } -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_handler(handle_autoindex,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA autoindex_module = -{ - STANDARD20_MODULE_STUFF, - create_autoindex_config, /* dir config creater */ - merge_autoindex_configs, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - autoindex_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/generators/mod_autoindex.exp b/modules/generators/mod_autoindex.exp deleted file mode 100644 index 90f4057e9c..0000000000 --- a/modules/generators/mod_autoindex.exp +++ /dev/null @@ -1 +0,0 @@ -autoindex_module diff --git a/modules/generators/mod_cgi.c b/modules/generators/mod_cgi.c deleted file mode 100644 index 3431936985..0000000000 --- a/modules/generators/mod_cgi.c +++ /dev/null @@ -1,1005 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_script: keeps all script-related ramblings together. - * - * Compliant to CGI/1.1 spec - * - * Adapted by rst from original NCSA code by Rob McCool - * - * Apache adds some new env vars; REDIRECT_URL and REDIRECT_QUERY_STRING for - * custom error responses, and DOCUMENT_ROOT because we found it useful. - * It also adds SERVER_ADMIN - useful for scripts to know who to mail when - * they fail. - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_thread_proc.h" /* for RLIMIT stuff */ -#include "apr_optional.h" -#include "apr_buckets.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#define CORE_PRIVATE - -#include "util_filter.h" -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_main.h" -#include "http_log.h" -#include "util_script.h" -#include "ap_mpm.h" -#include "mod_core.h" -#include "../filters/mod_include.h" - - -module AP_MODULE_DECLARE_DATA cgi_module; - -static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *cgi_pfn_reg_with_ssi; -static APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value) *cgi_pfn_gtv; -static APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string) *cgi_pfn_ps; - -typedef enum {RUN_AS_SSI, RUN_AS_CGI} prog_types; - -typedef struct { - apr_int32_t in_pipe; - apr_int32_t out_pipe; - apr_int32_t err_pipe; - apr_cmdtype_e cmd_type; - prog_types prog_type; - apr_bucket_brigade **bb; - include_ctx_t *ctx; - ap_filter_t *next; -} exec_info; - -/* KLUDGE --- for back-combatibility, we don't have to check ExecCGI - * in ScriptAliased directories, which means we need to know if this - * request came through ScriptAlias or not... so the Alias module - * leaves a note for us. - */ - -static int is_scriptaliased(request_rec *r) -{ - const char *t = apr_table_get(r->notes, "alias-forced-type"); - return t && (!strcasecmp(t, "cgi-script")); -} - -/* Configuration stuff */ - -#define DEFAULT_LOGBYTES 10385760 -#define DEFAULT_BUFBYTES 1024 - -typedef struct { - const char *logname; - long logbytes; - int bufbytes; -} cgi_server_conf; - -static void *create_cgi_config(apr_pool_t *p, server_rec *s) -{ - cgi_server_conf *c = - (cgi_server_conf *) apr_pcalloc(p, sizeof(cgi_server_conf)); - - c->logname = NULL; - c->logbytes = DEFAULT_LOGBYTES; - c->bufbytes = DEFAULT_BUFBYTES; - - return c; -} - -static void *merge_cgi_config(apr_pool_t *p, void *basev, void *overridesv) -{ - cgi_server_conf *base = (cgi_server_conf *) basev, *overrides = (cgi_server_conf *) overridesv; - - return overrides->logname ? overrides : base; -} - -static const char *set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg) -{ - server_rec *s = cmd->server; - cgi_server_conf *conf = ap_get_module_config(s->module_config, - &cgi_module); - - conf->logname = arg; - return NULL; -} - -static const char *set_scriptlog_length(cmd_parms *cmd, void *dummy, - const char *arg) -{ - server_rec *s = cmd->server; - cgi_server_conf *conf = ap_get_module_config(s->module_config, - &cgi_module); - - conf->logbytes = atol(arg); - return NULL; -} - -static const char *set_scriptlog_buffer(cmd_parms *cmd, void *dummy, - const char *arg) -{ - server_rec *s = cmd->server; - cgi_server_conf *conf = ap_get_module_config(s->module_config, - &cgi_module); - - conf->bufbytes = atoi(arg); - return NULL; -} - -static const command_rec cgi_cmds[] = -{ -AP_INIT_TAKE1("ScriptLog", set_scriptlog, NULL, RSRC_CONF, - "the name of a log for script debugging info"), -AP_INIT_TAKE1("ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF, - "the maximum length (in bytes) of the script debug log"), -AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF, - "the maximum size (in bytes) to record of a POST request"), - {NULL} -}; - -static int log_scripterror(request_rec *r, cgi_server_conf * conf, int ret, - apr_status_t rv, char *error) -{ - apr_file_t *f = NULL; - apr_finfo_t finfo; - char time_str[APR_CTIME_LEN]; - int log_flags = rv ? APLOG_ERR : APLOG_NOERRNO | APLOG_ERR; - - ap_log_rerror(APLOG_MARK, log_flags, rv, r, - "%s: %s", error, r->filename); - - if (!conf->logname || - ((apr_stat(&finfo, ap_server_root_relative(r->pool, conf->logname), - APR_FINFO_SIZE, r->pool) == APR_SUCCESS) - && (finfo.size > conf->logbytes)) || - (apr_file_open(&f, ap_server_root_relative(r->pool, conf->logname), - APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, r->pool) - != APR_SUCCESS)) { - return ret; - } - - /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */ - apr_ctime(time_str, apr_time_now()); - apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri, - r->args ? "?" : "", r->args ? r->args : "", r->protocol); - /* "%% 500 /usr/local/apache/cgi-bin */ - apr_file_printf(f, "%%%% %d %s\n", ret, r->filename); - - apr_file_printf(f, "%%error\n%s\n", error); - - apr_file_close(f); - return ret; -} - -/* Soak up stderr from a script and redirect it to the error log. - */ -static void log_script_err(request_rec *r, apr_file_t *script_err) -{ - char argsbuffer[HUGE_STRING_LEN]; - char *newline; - - while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_err) == 0) { - newline = strchr(argsbuffer, '\n'); - if (newline) { - *newline = '\0'; - } - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "%s", argsbuffer); - } -} - -static int log_script(request_rec *r, cgi_server_conf * conf, int ret, - char *dbuf, const char *sbuf, apr_file_t *script_in, - apr_file_t *script_err) -{ - apr_array_header_t *hdrs_arr = apr_table_elts(r->headers_in); - apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts; - char argsbuffer[HUGE_STRING_LEN]; - apr_file_t *f = NULL; - int i; - apr_finfo_t finfo; - char time_str[APR_CTIME_LEN]; - - if (!conf->logname || - ((apr_stat(&finfo, ap_server_root_relative(r->pool, conf->logname), - APR_FINFO_SIZE, r->pool) == APR_SUCCESS) - && (finfo.size > conf->logbytes)) || - (apr_file_open(&f, ap_server_root_relative(r->pool, conf->logname), - APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS)) { - /* Soak up script output */ - while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_in) == 0) - continue; - - log_script_err(r, script_err); - return ret; - } - - /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */ - apr_ctime(time_str, apr_time_now()); - apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri, - r->args ? "?" : "", r->args ? r->args : "", r->protocol); - /* "%% 500 /usr/local/apache/cgi-bin" */ - apr_file_printf(f, "%%%% %d %s\n", ret, r->filename); - - apr_file_puts("%request\n", f); - for (i = 0; i < hdrs_arr->nelts; ++i) { - if (!hdrs[i].key) - continue; - apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); - } - if ((r->method_number == M_POST || r->method_number == M_PUT) - && *dbuf) { - apr_file_printf(f, "\n%s\n", dbuf); - } - - apr_file_puts("%response\n", f); - hdrs_arr = apr_table_elts(r->err_headers_out); - hdrs = (apr_table_entry_t *) hdrs_arr->elts; - - for (i = 0; i < hdrs_arr->nelts; ++i) { - if (!hdrs[i].key) - continue; - apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); - } - - if (sbuf && *sbuf) - apr_file_printf(f, "%s\n", sbuf); - - if (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_in) == 0) { - apr_file_puts("%stdout\n", f); - apr_file_puts(argsbuffer, f); - while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_in) == 0) - apr_file_puts(argsbuffer, f); - apr_file_puts("\n", f); - } - - if (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_err) == 0) { - apr_file_puts("%stderr\n", f); - apr_file_puts(argsbuffer, f); - while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_err) == 0) - apr_file_puts(argsbuffer, f); - apr_file_puts("\n", f); - } - - apr_file_close(script_in); - apr_file_close(script_err); - - apr_file_close(f); - return ret; -} - - -/* This is the special environment used for running the "exec cmd=" - * variety of SSI directives. - */ -static void add_ssi_vars(request_rec *r, ap_filter_t *next) -{ - apr_table_t *e = r->subprocess_env; - - if (r->path_info && r->path_info[0] != '\0') { - request_rec *pa_req; - - apr_table_setn(e, "PATH_INFO", ap_escape_shell_cmd(r->pool, r->path_info)); - - pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info), r, next); - if (pa_req->filename) { - apr_table_setn(e, "PATH_TRANSLATED", - apr_pstrcat(r->pool, pa_req->filename, pa_req->path_info, NULL)); - } - } - - if (r->args) { - char *arg_copy = apr_pstrdup(r->pool, r->args); - - apr_table_setn(e, "QUERY_STRING", r->args); - ap_unescape_url(arg_copy); - apr_table_setn(e, "QUERY_STRING_UNESCAPED", ap_escape_shell_cmd(r->pool, arg_copy)); - } -} - -static apr_status_t run_cgi_child(apr_file_t **script_out, - apr_file_t **script_in, - apr_file_t **script_err, - const char *command, - const char * const argv[], - request_rec *r, - apr_pool_t *p, - exec_info *e_info) -{ - const char * const *env; - apr_procattr_t *procattr; - apr_proc_t *procnew; - apr_status_t rc = APR_SUCCESS; - -#if defined(RLIMIT_CPU) || defined(RLIMIT_NPROC) || \ - defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined (RLIMIT_AS) - - core_dir_config *conf = ap_get_module_config(r->per_dir_config, - &core_module); -#endif - - -#ifdef DEBUG_CGI -#ifdef OS2 - /* Under OS/2 need to use device con. */ - FILE *dbg = fopen("con", "w"); -#else - FILE *dbg = fopen("/dev/tty", "w"); -#endif - int i; -#endif - - RAISE_SIGSTOP(CGI_CHILD); -#ifdef DEBUG_CGI - fprintf(dbg, "Attempting to exec %s as %sCGI child (argv0 = %s)\n", - r->filename, cld->nph ? "NPH " : "", argv0); -#endif - - if (e_info->prog_type == RUN_AS_CGI) { - ap_add_cgi_vars(r); - } - else /* SSIs want a controlled environment and a special path. */ - { - add_ssi_vars(r, e_info->next); - } - env = (const char * const *)ap_create_environment(p, r->subprocess_env); - -#ifdef DEBUG_CGI - fprintf(dbg, "Environment: \n"); - for (i = 0; env[i]; ++i) - fprintf(dbg, "'%s'\n", env[i]); -#endif - - /* Transmute ourselves into the script. - * NB only ISINDEX scripts get decoded arguments. - */ - if (((rc = apr_procattr_create(&procattr, p)) != APR_SUCCESS) || - ((rc = apr_procattr_io_set(procattr, - e_info->in_pipe, - e_info->out_pipe, - e_info->err_pipe)) != APR_SUCCESS) || - ((rc = apr_procattr_dir_set(procattr, - ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) || -#ifdef RLIMIT_CPU - ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_CPU, conf->limit_cpu)) != APR_SUCCESS) || -#endif -#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) - ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_MEM, conf->limit_mem)) != APR_SUCCESS) || -#endif -#ifdef RLIMIT_NPROC - ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC, conf->limit_nproc)) != APR_SUCCESS) || -#endif - ((rc = apr_procattr_cmdtype_set(procattr, e_info->cmd_type)) != APR_SUCCESS)) { - /* Something bad happened, tell the world. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, - "couldn't set child process attributes: %s", r->filename); - } - else { - procnew = apr_pcalloc(p, sizeof(*procnew)); - if (e_info->prog_type == RUN_AS_SSI) { - SPLIT_AND_PASS_PRETAG_BUCKETS(*(e_info->bb), e_info->ctx, e_info->next); - } - - rc = ap_os_create_privileged_process(r, procnew, command, argv, env, procattr, p); - - if (rc != APR_SUCCESS) { - /* Bad things happened. Everyone should have cleaned up. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, - "couldn't create child process: %d: %s", rc, r->filename); - } - else { - apr_pool_note_subprocess(p, procnew, kill_after_timeout); - - *script_in = procnew->out; - if (!script_in) - return APR_EBADF; - apr_file_pipe_timeout_set(*script_in, (int)(r->server->timeout * APR_USEC_PER_SEC)); - - if (e_info->prog_type == RUN_AS_CGI) { - *script_out = procnew->in; - if (!*script_out) - return APR_EBADF; - apr_file_pipe_timeout_set(*script_out, (int)(r->server->timeout * APR_USEC_PER_SEC)); - - *script_err = procnew->err; - if (!*script_err) - return APR_EBADF; - apr_file_pipe_timeout_set(*script_err, (int)(r->server->timeout * APR_USEC_PER_SEC)); - } - } - } - return (rc); -} - -static apr_status_t build_argv_list(const char ***argv, request_rec *r, - apr_pool_t *p) -{ - int numwords, x, idx; - char *w; - const char *args = r->args; - - if (!args || !args[0] || ap_strchr_c(args, '=')) { - numwords = 1; - } - else { - /* count the number of keywords */ - for (x = 0, numwords = 2; args[x]; x++) { - if (args[x] == '+') { - ++numwords; - } - } - } - /* Everything is - 1 to account for the first parameter which is the - * program name. We didn't used to have to do this, but APR wants it. - */ - if (numwords > APACHE_ARG_MAX - 1) { - numwords = APACHE_ARG_MAX - 1; /* Truncate args to prevent overrun */ - } - *argv = apr_palloc(p, (numwords + 2) * sizeof(char *)); - - for (x = 1, idx = 1; x < numwords; x++) { - w = ap_getword_nulls(p, &args, '+'); - ap_unescape_url(w); - (*argv)[idx++] = ap_escape_shell_cmd(p, w); - } - (*argv)[idx] = NULL; - - return APR_SUCCESS; -} - -static apr_status_t build_command_line(const char **cmd, request_rec *r, - apr_pool_t *p) -{ -#ifdef WIN32 - char *quoted_filename = NULL; - char *interpreter = NULL; - char *arguments = NULL; - file_type_e fileType; -#endif - const char *argv0; - - /* Allow suexec's "/" check to succeed */ - if ((argv0 = strrchr(r->filename, '/')) != NULL) - argv0++; - else - argv0 = r->filename; - -#ifdef WIN32 - *cmd = NULL; - fileType = ap_get_win32_interpreter(r, &interpreter, &arguments); - - if (fileType == eFileTypeUNKNOWN) { - ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, - "%s is not executable; ensure interpreted scripts have " - "\"#!\" first line", - r->filename); - return APR_EBADF; - } - - /* - * Build the command string to pass to ap_os_create_privileged_process() - */ - quoted_filename = apr_pstrcat(p, "\"", r->filename, "\"", NULL); - if (interpreter && *interpreter) { - if (arguments && *arguments) - *cmd = apr_pstrcat(p, interpreter, " ", quoted_filename, " ", - arguments, NULL); - else - *cmd = apr_pstrcat(p, interpreter, " ", quoted_filename, " ", NULL); - } - else if (arguments && *arguments) { - *cmd = apr_pstrcat(p, quoted_filename, " ", arguments, NULL); - } - else { - *cmd = apr_pstrcat(p, quoted_filename, NULL); - } -#else - *cmd = argv0; -#endif - return APR_SUCCESS; -} - -static int cgi_handler(request_rec *r) -{ - int retval, nph, dbpos = 0; - const char *argv0; - const char *command; - const char **argv; - char *dbuf = NULL; - apr_file_t *script_out = NULL, *script_in = NULL, *script_err = NULL; - apr_bucket_brigade *bb; - apr_bucket *b; - char argsbuffer[HUGE_STRING_LEN]; - int is_included = !strcmp(r->protocol, "INCLUDED"); - apr_pool_t *p; - cgi_server_conf *conf; - apr_status_t rv; - exec_info e_info; - - if(strcmp(r->handler,CGI_MAGIC_TYPE) && strcmp(r->handler,"cgi-script")) - return DECLINED; - - p = r->main ? r->main->pool : r->pool; - - if (r->method_number == M_OPTIONS) { - /* 99 out of 100 CGI scripts, this is all they support */ - r->allowed |= (1 << M_GET); - r->allowed |= (1 << M_POST); - return DECLINED; - } - - if ((argv0 = strrchr(r->filename, '/')) != NULL) - argv0++; - else - argv0 = r->filename; - - nph = !(strncmp(argv0, "nph-", 4)); - conf = ap_get_module_config(r->server->module_config, &cgi_module); - - if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r)) - return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, - "Options ExecCGI is off in this directory"); - if (nph && is_included) - return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, - "attempt to include NPH CGI script"); - -#if defined(OS2) || defined(WIN32) - /* XXX: This is wrong. As an option, perhaps, but not by default... - * we are back to the same argument that a url should be a unique - * entity until the sysadmin overrides that behavior. - * Allow for cgi files without the .EXE extension on them under OS/2 - */ - if (r->finfo.filetype == 0) { - apr_finfo_t finfo; - char *newfile; - apr_status_t rv; - - newfile = apr_pstrcat(r->pool, r->filename, ".EXE", NULL); - if (((rv = apr_stat(&finfo, newfile, APR_FINFO_TYPE, r->pool)) - != APR_SUCCESS) || (finfo.filetype != APR_REG)) { - return log_scripterror(r, conf, HTTP_NOT_FOUND, rv, - "script not found or unable to stat"); - } else { - r->filename = newfile; - } - } -#else - if (r->finfo.filetype == 0) - return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, - "script not found or unable to stat"); -#endif - if (r->finfo.filetype == APR_DIR) - return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, - "attempt to invoke directory as script"); - -/* - if (!ap_suexec_enabled) { - if (!ap_can_exec(&r->finfo)) - return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, - "file permissions deny server execution"); - } - -*/ - if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) - return retval; - - ap_add_common_vars(r); - - /* build the command line */ - if ((rv = build_command_line(&command, r, p)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "couldn't spawn child process: %s", r->filename); - return HTTP_INTERNAL_SERVER_ERROR; - } - /* build the argument list */ - else if ((rv = build_argv_list(&argv, r, p)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "couldn't spawn child process: %s", r->filename); - return HTTP_INTERNAL_SERVER_ERROR; - } - argv[0] = apr_pstrdup(p, command); - - e_info.cmd_type = APR_PROGRAM; - e_info.in_pipe = APR_CHILD_BLOCK; - e_info.out_pipe = APR_CHILD_BLOCK; - e_info.err_pipe = APR_CHILD_BLOCK; - e_info.prog_type = RUN_AS_CGI; - e_info.bb = NULL; - e_info.ctx = NULL; - e_info.next = NULL; - - /* run the script in its own process */ - if ((rv = run_cgi_child(&script_out, &script_in, &script_err, - command, argv, r, p, &e_info)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "couldn't spawn child process: %s", r->filename); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* Transfer any put/post args, CERN style... - * Note that we already ignore SIGPIPE in the core server. - */ - if (ap_should_client_block(r)) { - int dbsize, len_read; - apr_size_t bytes_written, bytes_to_write; - apr_status_t rv; - - if (conf->logname) { - dbuf = apr_pcalloc(r->pool, conf->bufbytes + 1); - dbpos = 0; - } - - while ((len_read = - ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN)) > 0) { - if (conf->logname) { - if ((dbpos + len_read) > conf->bufbytes) { - dbsize = conf->bufbytes - dbpos; - } - else { - dbsize = len_read; - } - memcpy(dbuf + dbpos, argsbuffer, dbsize); - dbpos += dbsize; - } - /* Keep writing data to the child until done or too much time - * elapses with no progress or an error occurs. - */ - bytes_written = 0; - do { - bytes_to_write = len_read - bytes_written; - rv = apr_file_write(script_out, argsbuffer + bytes_written, - &bytes_to_write); - bytes_written += bytes_to_write; - } while (rv == APR_SUCCESS && bytes_written < len_read); - if (rv != APR_SUCCESS || bytes_written < len_read) { - /* silly script stopped reading, soak up remaining message */ - while (ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0) { - /* dump it */ - } - break; - } - } - apr_file_flush(script_out); - } - - apr_file_close(script_out); - - /* Handle script return... */ - if (script_in && !nph) { - const char *location; - char sbuf[MAX_STRING_LEN]; - int ret; - - if ((ret = ap_scan_script_header_err(r, script_in, sbuf))) { - return log_script(r, conf, ret, dbuf, sbuf, script_in, script_err); - } - - location = apr_table_get(r->headers_out, "Location"); - - if (location && location[0] == '/' && r->status == 200) { - - /* Soak up all the script output */ - while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_in) == 0) { - continue; - } - log_script_err(r, script_err); - /* This redirect needs to be a GET no matter what the original - * method was. - */ - r->method = apr_pstrdup(r->pool, "GET"); - r->method_number = M_GET; - - /* We already read the message body (if any), so don't allow - * the redirected request to think it has one. We can ignore - * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. - */ - apr_table_unset(r->headers_in, "Content-Length"); - - ap_internal_redirect_handler(location, r); - return OK; - } - else if (location && r->status == 200) { - /* XX Note that if a script wants to produce its own Redirect - * body, it now has to explicitly *say* "Status: 302" - */ - return HTTP_MOVED_TEMPORARILY; - } - - if (!r->header_only) { - bb = apr_brigade_create(r->pool); - b = apr_bucket_pipe_create(script_in); - APR_BRIGADE_INSERT_TAIL(bb, b); - b = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - ap_pass_brigade(r->output_filters, bb); - } - - log_script_err(r, script_err); - apr_file_close(script_err); - } - - if (script_in && nph) { - bb = apr_brigade_create(r->pool); - b = apr_bucket_pipe_create(script_in); - APR_BRIGADE_INSERT_TAIL(bb, b); - b = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - ap_pass_brigade(r->output_filters, bb); - } - - return OK; /* NOT r->status, even if it has changed. */ -} - -/*============================================================================ - *============================================================================ - * This is the beginning of the cgi filter code moved from mod_include. This - * is the code required to handle the "exec" SSI directive. - *============================================================================ - *============================================================================*/ -static int include_cgi(char *s, request_rec *r, ap_filter_t *next, - apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - request_rec *rr = ap_sub_req_lookup_uri(s, r, next); - int rr_status; - apr_bucket *tmp_buck, *tmp2_buck; - - if (rr->status != HTTP_OK) { - return -1; - } - - /* No hardwired path info or query allowed */ - - if ((rr->path_info && rr->path_info[0]) || rr->args) { - return -1; - } - if (rr->finfo.protection == 0) { - return -1; - } - - /* Script gets parameters of the *document*, for back compatibility */ - - rr->path_info = r->path_info; /* hard to get right; see mod_cgi.c */ - rr->args = r->args; - - /* Force sub_req to be treated as a CGI request, even if ordinary - * typing rules would have called it something else. - */ - - rr->content_type = CGI_MAGIC_TYPE; - - /* Run it. */ - - rr_status = ap_run_sub_req(rr); - if (ap_is_HTTP_REDIRECT(rr_status)) { - apr_size_t len_loc, h_wrt; - const char *location = apr_table_get(rr->headers_out, "Location"); - - location = ap_escape_html(rr->pool, location); - len_loc = strlen(location); - - tmp_buck = apr_bucket_immortal_create("<A HREF=\"", sizeof("<A HREF=\"")); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck); - tmp2_buck = apr_bucket_heap_create(location, len_loc, 1, &h_wrt); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck); - tmp2_buck = apr_bucket_immortal_create("\">", sizeof("\">")); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck); - tmp2_buck = apr_bucket_heap_create(location, len_loc, 1, &h_wrt); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck); - tmp2_buck = apr_bucket_immortal_create("</A>", sizeof("</A>")); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck); - - if (*inserted_head == NULL) { - *inserted_head = tmp_buck; - } - } - - ap_destroy_sub_req(rr); - - return 0; -} - - -static int include_cmd(include_ctx_t *ctx, apr_bucket_brigade **bb, char *command, - request_rec *r, ap_filter_t *f) -{ - exec_info e_info; - const char **argv; - apr_file_t *script_out = NULL, *script_in = NULL, *script_err = NULL; - apr_bucket_brigade *bcgi; - apr_bucket *b; - - if (build_argv_list(&argv, r, r->pool) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, - "couldn't spawn cmd child process: %s", r->filename); - return HTTP_INTERNAL_SERVER_ERROR; - } - argv[0] = apr_pstrdup(r->pool, command); - - e_info.cmd_type = APR_SHELLCMD; - e_info.in_pipe = APR_NO_PIPE; - e_info.out_pipe = APR_FULL_BLOCK; - e_info.err_pipe = APR_NO_PIPE; - e_info.prog_type = RUN_AS_SSI; - e_info.bb = bb; - e_info.ctx = ctx; - e_info.next = f->next; - - /* run the script in its own process */ - if (run_cgi_child(&script_out, &script_in, &script_err, - command, argv, r, r->pool, &e_info) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, - "couldn't spawn child process: %s", r->filename); - return HTTP_INTERNAL_SERVER_ERROR; - } - - bcgi = apr_brigade_create(r->pool); - b = apr_bucket_pipe_create(script_in); - APR_BRIGADE_INSERT_TAIL(bcgi, b); - ap_pass_brigade(f->next, bcgi); - - /* We can't close the pipe here, because we may return before the - * full CGI has been sent to the network. That's okay though, - * because we can rely on the pool to close the pipe for us. - */ - - return 0; -} - -static int handle_exec(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - char *tag = NULL; - char *tag_val = NULL; - char *file = r->filename; - apr_bucket *tmp_buck; - char parsed_string[MAX_STRING_LEN]; - - *inserted_head = NULL; - if (ctx->flags & FLAG_PRINTING) { - if (ctx->flags & FLAG_NO_EXEC) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "exec used but not allowed in %s", r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - else { - while (1) { - cgi_pfn_gtv(ctx, &tag, &tag_val, 1); - if (tag_val == NULL) { - if (tag == NULL) { - return (0); - } - else { - return 1; - } - } - if (!strcmp(tag, "cmd")) { - cgi_pfn_ps(r, tag_val, parsed_string, sizeof(parsed_string), 1); - if (include_cmd(ctx, bb, parsed_string, r, f) == -1) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "execution failure for parameter \"%s\" " - "to tag exec in file %s", tag, r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - } - else if (!strcmp(tag, "cgi")) { - cgi_pfn_ps(r, tag_val, parsed_string, sizeof(parsed_string), 0); - SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next); - if (include_cgi(parsed_string, r, f->next, head_ptr, inserted_head) == -1) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "invalid CGI ref \"%s\" in %s", tag_val, file); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "unknown parameter \"%s\" to tag exec in %s", tag, file); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - } - } - } - return 0; -} - - -/*============================================================================ - *============================================================================ - * This is the end of the cgi filter code moved from mod_include. - *============================================================================ - *============================================================================*/ - - -static void cgi_post_config(apr_pool_t *p, apr_pool_t *plog, - apr_pool_t *ptemp, server_rec *s) -{ - cgi_pfn_reg_with_ssi = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler); - cgi_pfn_gtv = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_get_tag_and_value); - cgi_pfn_ps = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_parse_string); - - if ((cgi_pfn_reg_with_ssi) && (cgi_pfn_gtv) && (cgi_pfn_ps)) { - /* Required by mod_include filter. This is how mod_cgi registers - * with mod_include to provide processing of the exec directive. - */ - cgi_pfn_reg_with_ssi("exec", handle_exec); - } -} - -static void register_hooks(apr_pool_t *p) -{ - static const char * const aszPre[] = { "mod_include.c", NULL }; - ap_hook_handler(cgi_handler, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_config(cgi_post_config, aszPre, NULL, APR_HOOK_REALLY_FIRST); -} - -module AP_MODULE_DECLARE_DATA cgi_module = -{ - STANDARD20_MODULE_STUFF, - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - create_cgi_config, /* server config */ - merge_cgi_config, /* merge server config */ - cgi_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/generators/mod_cgi.exp b/modules/generators/mod_cgi.exp deleted file mode 100644 index 96ea0c2348..0000000000 --- a/modules/generators/mod_cgi.exp +++ /dev/null @@ -1 +0,0 @@ -cgi_module diff --git a/modules/generators/mod_cgid.c b/modules/generators/mod_cgid.c deleted file mode 100644 index cbb09d3525..0000000000 --- a/modules/generators/mod_cgid.c +++ /dev/null @@ -1,1300 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_script: keeps all script-related ramblings together. - * - * Compliant to cgi/1.1 spec - * - * Adapted by rst from original NCSA code by Rob McCool - * - * Apache adds some new env vars; REDIRECT_URL and REDIRECT_QUERY_STRING for - * custom error responses, and DOCUMENT_ROOT because we found it useful. - * It also adds SERVER_ADMIN - useful for scripts to know who to mail when - * they fail. - */ - -#include "apr_lib.h" -#include "apr_strings.h" -#include "apr_general.h" -#include "apr_file_io.h" -#include "apr_portable.h" -#include "apr_buckets.h" -#include "apr_optional.h" -#include "apr_signal.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#define CORE_PRIVATE - -#include "util_filter.h" -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_main.h" -#include "http_log.h" -#include "util_script.h" -#include "ap_mpm.h" -#include "unixd.h" -#include "mod_suexec.h" -#include "../filters/mod_include.h" - -#include "mod_core.h" - - -/* ### should be tossed in favor of APR */ -#include <sys/stat.h> -#include <sys/un.h> /* for sockaddr_un */ - - -module AP_MODULE_DECLARE_DATA cgid_module; - -static void cgid_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server); -static int handle_exec(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head); - -static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *cgid_pfn_reg_with_ssi; -static APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value) *cgid_pfn_gtv; -static APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string) *cgid_pfn_ps; - -static apr_pool_t *pcgi; -static int total_modules = 0; - -/* KLUDGE --- for back-combatibility, we don't have to check Execcgid - * in ScriptAliased directories, which means we need to know if this - * request came through ScriptAlias or not... so the Alias module - * leaves a note for us. - */ - -static int is_scriptaliased(request_rec *r) -{ - const char *t = apr_table_get(r->notes, "alias-forced-type"); - return t && (!strcasecmp(t, "cgi-script")); -} - -/* Configuration stuff */ - -#define DEFAULT_LOGBYTES 10385760 -#define DEFAULT_BUFBYTES 1024 -#define DEFAULT_SOCKET "logs/cgisock" - -#define SHELL_PATH "/bin/sh" - -#define CGI_REQ 1 -#define SSI_REQ 2 - -/* DEFAULT_CGID_LISTENBACKLOG controls the max depth on the unix socket's - * pending connection queue. If a bunch of cgi requests arrive at about - * the same time, connections from httpd threads/processes will back up - * in the queue while the cgid process slowly forks off a child to process - * each connection on the unix socket. If the queue is too short, the - * httpd process will get ECONNREFUSED when trying to connect. - */ -#ifndef DEFAULT_CGID_LISTENBACKLOG -#define DEFAULT_CGID_LISTENBACKLOG 100 -#endif - -typedef struct { - const char *sockname; - const char *logname; - long logbytes; - int bufbytes; -} cgid_server_conf; - -/* If a request includes query info in the URL (stuff after "?"), and - * the query info does not contain "=" (indicative of a FORM submission), - * then this routine is called to create the argument list to be passed - * to the CGI script. When suexec is enabled, the suexec path, user, and - * group are the first three arguments to be passed; if not, all three - * must be NULL. The query info is split into separate arguments, where - * "+" is the separator between keyword arguments. - * - * XXXX: note that the WIN32 code uses one of the suexec strings - * to pass an interpreter name. Remember this if changing the way they - * are handled in create_argv. - * - */ -static char **create_argv(apr_pool_t *p, char *path, char *user, char *group, - char *av0, const char *args) -{ - int x, numwords; - char **av; - char *w; - int idx = 0; - - /* count the number of keywords */ - - for (x = 0, numwords = 1; args[x]; x++) { - if (args[x] == '+') { - ++numwords; - } - } - - if (numwords > APACHE_ARG_MAX - 5) { - numwords = APACHE_ARG_MAX - 5; /* Truncate args to prevent overrun */ - } - av = (char **) apr_pcalloc(p, (numwords + 5) * sizeof(char *)); - - if (path) { - av[idx++] = path; - } - if (user) { - av[idx++] = user; - } - if (group) { - av[idx++] = group; - } - - av[idx++] = apr_pstrdup(p, av0); - - for (x = 1; x <= numwords; x++) { - w = ap_getword_nulls(p, &args, '+'); - if (strcmp(w, "")) { - ap_unescape_url(w); - av[idx++] = ap_escape_shell_cmd(p, w); - } - } - av[idx] = NULL; - return av; -} - -#if APR_HAS_OTHER_CHILD -static void cgid_maint(int reason, void *data, apr_wait_t status) -{ - pid_t *sd = data; - switch (reason) { - case APR_OC_REASON_DEATH: - case APR_OC_REASON_LOST: - /* stop gap to make sure everything else works. In the end, - * we'll just restart the cgid server. */ - apr_pool_destroy(pcgi); - kill(getpid(), SIGWINCH); /* yes, to ourself */ - break; - case APR_OC_REASON_RESTART: - apr_proc_other_child_unregister(data); - break; - case APR_OC_REASON_UNREGISTER: - apr_pool_destroy(pcgi); - kill(*sd, SIGHUP); - break; - } -} -#endif - -static void get_req(int fd, request_rec *r, char **argv0, char ***env, int *req_type) -{ - int i, len, j; - unsigned char *data; - char **environ; - core_dir_config *temp_core; - void **dconf; - module *suexec_mod = ap_find_linked_module("mod_suexec.c"); - - r->server = apr_pcalloc(r->pool, sizeof(server_rec)); - - read(fd, req_type, sizeof(int)); - read(fd, &j, sizeof(int)); - read(fd, &len, sizeof(int)); - data = apr_pcalloc(r->pool, len + 1); /* get a cleared byte for final '\0' */ - i = read(fd, data, len); - - r->filename = ap_getword(r->pool, (const char **)&data, '\n'); - *argv0 = ap_getword(r->pool, (const char **)&data, '\n'); - - r->uri = ap_getword(r->pool, (const char **)&data, '\n'); - - environ = apr_pcalloc(r->pool, (j + 2) *sizeof(char *)); - i = 0; - for (i = 0; i < j; i++) { - environ[i] = ap_getword(r->pool, (const char **)&data, '\n'); - } - *env = environ; - r->args = ap_getword(r->pool, (const char **)&data, '\n'); - - read(fd, &i, sizeof(int)); - - /* add 1, so that if i == 0, we still malloc something. */ - - dconf = (void **) apr_pcalloc(r->pool, sizeof(void *) * (total_modules + DYNAMIC_MODULE_LIMIT)); - - temp_core = (core_dir_config *)apr_palloc(r->pool, sizeof(core_module)); - - dconf[i] = (void *)temp_core; - - if (suexec_mod) { - suexec_config_t *suexec_cfg = apr_pcalloc(r->pool, sizeof(*suexec_cfg)); - - read(fd, &i, sizeof(int)); - read(fd, &suexec_cfg->ugid.uid, sizeof(uid_t)); - read(fd, &suexec_cfg->ugid.gid, sizeof(gid_t)); - read(fd, &suexec_cfg->active, sizeof(int)); - dconf[i] = (void *)suexec_cfg; - } - - r->per_dir_config = (ap_conf_vector_t *)dconf; -#if 0 -#ifdef RLIMIT_CPU - read(fd, &j, sizeof(int)); - if (j) { - temp_core->limit_cpu = (struct rlimit *)apr_palloc (sizeof(struct rlimit)); - read(fd, temp_core->limit_cpu, sizeof(struct rlimit)); - } - else { - temp_core->limit_cpu = NULL; - } -#endif - -#if defined (RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) - read(fd, &j, sizeof(int)); - if (j) { - temp_core->limit_mem = (struct rlimit *)apr_palloc(r->pool, sizeof(struct rlimit)); - read(fd, temp_core->limit_mem, sizeof(struct rlimit)); - } - else { - temp_core->limit_mem = NULL; - } -#endif - -#ifdef RLIMIT_NPROC - read(fd, &j, sizeof(int)); - if (j) { - temp_core->limit_nproc = (struct rlimit *)apr_palloc(r->pool, sizeof(struct rlimit)); - read(fd, temp_core->limit_nproc, sizeof(struct rlimit)); - } - else { - temp_core->limit_nproc = NULL; - } -#endif -#endif - /* For right now, just make the notes table. At some point we will need - * to actually fill this out, but for now we just don't want suexec to - * seg fault. - */ - r->notes = apr_table_make(r->pool, 1); -} - - - -static void send_req(int fd, request_rec *r, char *argv0, char **env, int req_type) -{ - int len, r_type = req_type; - int i = 0; - char *data; - module *suexec_mod = ap_find_linked_module("mod_suexec.c"); - - data = apr_pstrcat(r->pool, r->filename, "\n", argv0, "\n", r->uri, "\n", - NULL); - - for (i =0; env[i]; i++) { - continue; - } - - /* Write the request type (SSI "exec cmd" or cgi). */ - if (write(fd, &r_type, sizeof(int)) < 0) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, - "write to cgi daemon process"); - } - - /* Write the number of entries in the environment. */ - if (write(fd, &i, sizeof(int)) < 0) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, - "write to cgi daemon process"); - } - - for (i = 0; env[i]; i++) { - data = apr_pstrcat(r->pool, data, env[i], "\n", NULL); - } - data = apr_pstrcat(r->pool, data, r->args, NULL); - len = strlen(data); - /* Write the length of the concatenated env string. */ - if (write(fd, &len, sizeof(int)) < 0) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, - "write to cgi daemon process"); - } - /* Write the concatted env string. */ - if (write(fd, data, len) < 0) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, - "write to cgi daemon process"); - } - /* Write module_index id value. */ - if (write(fd, &core_module.module_index, sizeof(int)) < 0) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, - "write to cgi daemon process"); - } - if (suexec_mod) { - suexec_config_t *suexec_cfg = ap_get_module_config(r->per_dir_config, - suexec_mod); - - write(fd, &suexec_mod->module_index, sizeof(int)); - write(fd, &suexec_cfg->ugid.uid, sizeof(uid_t)); - write(fd, &suexec_cfg->ugid.gid, sizeof(gid_t)); - write(fd, &suexec_cfg->active, sizeof(int)); - } - -#if 0 -#ifdef RLIMIT_CPU - if (conf->limit_cpu) { - len = 1; - write(fd, &len, sizeof(int)); - write(fd, conf->limit_cpu, sizeof(struct rlimit)); - } - else { - len = 0; - write(fd, &len, sizeof(int)); - } -#endif - -#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) - if (conf->limit_mem) { - len = 1; - write(fd, &len, sizeof(int)); - write(fd, conf->limit_mem, sizeof(struct rlimit)); - } - else { - len = 0; - write(fd, &len, sizeof(int)); - } -#endif - -#ifdef RLIMIT_NPROC - if (conf->limit_nproc) { - len = 1; - write(fd, &len, sizeof(int)); - write(fd, conf->limit_nproc, sizeof(struct rlimit)); - } - else { - len = 0; - write(fd, &len, sizeof(int)); - } -#endif -#endif -} - -static int cgid_server(void *data) -{ - struct sockaddr_un unix_addr; - int sd, sd2, rc, req_type; - mode_t omask; - apr_socklen_t len; - apr_pool_t *ptrans; - server_rec *main_server = data; - cgid_server_conf *sconf = ap_get_module_config(main_server->module_config, - &cgid_module); - - apr_pool_create(&ptrans, pcgi); - - apr_signal(SIGCHLD, SIG_IGN); - if (unlink(sconf->sockname) < 0 && errno != ENOENT) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, - "Couldn't unlink unix domain socket %s", - sconf->sockname); - /* just a warning; don't bail out */ - } - - if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, - "Couldn't create unix domain socket"); - return errno; - } - - memset(&unix_addr, 0, sizeof(unix_addr)); - unix_addr.sun_family = AF_UNIX; - strcpy(unix_addr.sun_path, sconf->sockname); - - omask = umask(0077); /* so that only Apache can use socket */ - rc = bind(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)); - umask(omask); /* can't fail, so can't clobber errno */ - if (rc < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, - "Couldn't bind unix domain socket %s", - sconf->sockname); - return errno; - } - - if (listen(sd, DEFAULT_CGID_LISTENBACKLOG) < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, - "Couldn't listen on unix domain socket"); - return errno; - } - - if (!geteuid()) { - if (chown(sconf->sockname, unixd_config.user_id, -1) < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, - "Couldn't change owner of unix domain socket %s", - sconf->sockname); - return errno; - } - } - - unixd_setup_child(); /* if running as root, switch to configured user/group */ - while (1) { - int errfileno = STDERR_FILENO; - char *argv0; - char **env; - const char * const *argv; - apr_int32_t in_pipe = APR_CHILD_BLOCK; - apr_int32_t out_pipe = APR_CHILD_BLOCK; - apr_int32_t err_pipe = APR_CHILD_BLOCK; - apr_cmdtype_e cmd_type = APR_PROGRAM; - request_rec *r; - apr_procattr_t *procattr = NULL; - apr_proc_t *procnew = NULL; - apr_file_t *inout; - - apr_pool_clear(ptrans); - - len = sizeof(unix_addr); - sd2 = accept(sd, (struct sockaddr *)&unix_addr, &len); - if (sd2 < 0) { - if (errno != EINTR) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, - (server_rec *)data, - "Error accepting on cgid socket."); - } - continue; - } - - r = apr_pcalloc(ptrans, sizeof(request_rec)); - procnew = apr_pcalloc(ptrans, sizeof(*procnew)); - r->pool = ptrans; - get_req(sd2, r, &argv0, &env, &req_type); - apr_os_file_put(&r->server->error_log, &errfileno, r->pool); - apr_os_file_put(&inout, &sd2, r->pool); - - if (req_type == SSI_REQ) { - in_pipe = APR_NO_PIPE; - out_pipe = APR_FULL_BLOCK; - err_pipe = APR_NO_PIPE; - cmd_type = APR_SHELLCMD; - } - - if (((rc = apr_procattr_create(&procattr, ptrans)) != APR_SUCCESS) || - ((req_type == CGI_REQ) && - (((rc = apr_procattr_io_set(procattr, - in_pipe, - out_pipe, - err_pipe)) != APR_SUCCESS) || - /* XXX apr_procattr_child_*_set() is creating an unnecessary - * pipe between this process and the child being created... - * It is cleaned up with the temporary pool for this request. - */ - ((rc = apr_procattr_child_err_set(procattr, r->server->error_log, NULL)) != APR_SUCCESS) || - ((rc = apr_procattr_child_in_set(procattr, inout, NULL)) != APR_SUCCESS))) || - ((rc = apr_procattr_child_out_set(procattr, inout, NULL)) != APR_SUCCESS) || - ((rc = apr_procattr_dir_set(procattr, - ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) || - ((rc = apr_procattr_cmdtype_set(procattr, cmd_type)) != APR_SUCCESS)) { - /* Something bad happened, tell the world. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, - "couldn't set child process attributes: %s", r->filename); - } - else { - argv = (const char * const *)create_argv(r->pool, NULL, NULL, NULL, argv0, r->args); - - /* We want to sd2 close for new CGI process too. - * If it's remained open it'll make ap_pass_brigade() block - * waiting for EOF if CGI forked something running long. - * close(sd2) here should be okay, as CGI channel - * is already dup()ed by apr_procattr_child_{in,out}_set() - * above. - */ - close(sd2); - - rc = ap_os_create_privileged_process(r, procnew, argv0, argv, - (const char * const *)env, - procattr, ptrans); - - if (rc != APR_SUCCESS) { - /* Bad things happened. Everyone should have cleaned up. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, - "couldn't create child process: %d: %s", rc, r->filename); - } - } - } - return -1; -} - -static void cgid_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, - server_rec *main_server) -{ - pid_t pid; - apr_proc_t *procnew; - void *data; - int first_time = 0; - const char *userdata_key = "cgid_init"; - module **m; - - apr_pool_userdata_get(&data, userdata_key, main_server->process->pool); - if (!data) { - first_time = 1; - apr_pool_userdata_set((const void *)1, userdata_key, - apr_pool_cleanup_null, main_server->process->pool); - } - - if (!first_time) { - apr_pool_create(&pcgi, p); - - total_modules = 0; - for (m = ap_preloaded_modules; *m != NULL; m++) - total_modules++; - - - if ((pid = fork()) < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, - "Couldn't spawn cgid daemon process"); - } - else if (pid == 0) { - cgid_server(main_server); - exit(-1); - } - procnew = apr_pcalloc(p, sizeof(*procnew)); - procnew->pid = pid; - procnew->err = procnew->in = procnew->out = NULL; - apr_pool_note_subprocess(p, procnew, kill_after_timeout); -#if APR_HAS_OTHER_CHILD - apr_proc_other_child_register(procnew, cgid_maint, &procnew->pid, NULL, p); -#endif - - cgid_pfn_reg_with_ssi = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler); - cgid_pfn_gtv = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_get_tag_and_value); - cgid_pfn_ps = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_parse_string); - - if ((cgid_pfn_reg_with_ssi) && (cgid_pfn_gtv) && (cgid_pfn_ps)) { - /* Required by mod_include filter. This is how mod_cgid registers - * with mod_include to provide processing of the exec directive. - */ - cgid_pfn_reg_with_ssi("exec", handle_exec); - } - } -} - -static void *create_cgid_config(apr_pool_t *p, server_rec *s) -{ - cgid_server_conf *c = - (cgid_server_conf *) apr_pcalloc(p, sizeof(cgid_server_conf)); - - c->logname = NULL; - c->logbytes = DEFAULT_LOGBYTES; - c->bufbytes = DEFAULT_BUFBYTES; - c->sockname = ap_server_root_relative(p, DEFAULT_SOCKET); - return c; -} - -static void *merge_cgid_config(apr_pool_t *p, void *basev, void *overridesv) -{ - cgid_server_conf *base = (cgid_server_conf *) basev, *overrides = (cgid_server_conf *) overridesv; - - return overrides->logname ? overrides : base; -} - -static const char *set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg) -{ - server_rec *s = cmd->server; - cgid_server_conf *conf = ap_get_module_config(s->module_config, - &cgid_module); - - conf->logname = arg; - return NULL; -} - -static const char *set_scriptlog_length(cmd_parms *cmd, void *dummy, const char *arg) -{ - server_rec *s = cmd->server; - cgid_server_conf *conf = ap_get_module_config(s->module_config, - &cgid_module); - - conf->logbytes = atol(arg); - return NULL; -} - -static const char *set_scriptlog_buffer(cmd_parms *cmd, void *dummy, const char *arg) -{ - server_rec *s = cmd->server; - cgid_server_conf *conf = ap_get_module_config(s->module_config, - &cgid_module); - - conf->bufbytes = atoi(arg); - return NULL; -} - -static const char *set_script_socket(cmd_parms *cmd, void *dummy, const char *arg) -{ - server_rec *s = cmd->server; - cgid_server_conf *conf = ap_get_module_config(s->module_config, - &cgid_module); - - conf->sockname = ap_server_root_relative(cmd->pool, arg); - return NULL; -} - -static const command_rec cgid_cmds[] = -{ - AP_INIT_TAKE1("ScriptLog", set_scriptlog, NULL, RSRC_CONF, - "the name of a log for script debugging info"), - AP_INIT_TAKE1("ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF, - "the maximum length (in bytes) of the script debug log"), - AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF, - "the maximum size (in bytes) to record of a POST request"), - AP_INIT_TAKE1("Scriptsock", set_script_socket, NULL, RSRC_CONF, - "the name of the socket to use for communication with " - "the cgi daemon."), - {NULL} -}; - -static int log_scripterror(request_rec *r, cgid_server_conf * conf, int ret, - apr_status_t rv, char *error) -{ - apr_file_t *f = NULL; - struct stat finfo; - char time_str[APR_CTIME_LEN]; - int log_flags = rv ? APLOG_ERR : APLOG_NOERRNO | APLOG_ERR; - - ap_log_rerror(APLOG_MARK, log_flags, rv, r, - "%s: %s", error, r->filename); - - if (!conf->logname || - ((stat(ap_server_root_relative(r->pool, conf->logname), &finfo) == 0) - && (finfo.st_size > conf->logbytes)) || - (apr_file_open(&f, ap_server_root_relative(r->pool, conf->logname), - APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS)) { - return ret; - } - - /* "%% [Wed Jun 19 10:53:21 1996] GET /cgid-bin/printenv HTTP/1.0" */ - apr_ctime(time_str, apr_time_now()); - apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri, - r->args ? "?" : "", r->args ? r->args : "", r->protocol); - /* "%% 500 /usr/local/apache/cgid-bin */ - apr_file_printf(f, "%%%% %d %s\n", ret, r->filename); - - apr_file_printf(f, "%%error\n%s\n", error); - - apr_file_close(f); - return ret; -} - -static int log_script(request_rec *r, cgid_server_conf * conf, int ret, - char *dbuf, const char *sbuf, apr_file_t *script_in, apr_file_t *script_err) -{ - apr_array_header_t *hdrs_arr = apr_table_elts(r->headers_in); - apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts; - char argsbuffer[HUGE_STRING_LEN]; - apr_file_t *f = NULL; - int i; - struct stat finfo; - char time_str[APR_CTIME_LEN]; - - if (!conf->logname || - ((stat(ap_server_root_relative(r->pool, conf->logname), &finfo) == 0) - && (finfo.st_size > conf->logbytes)) || - (apr_file_open(&f, ap_server_root_relative(r->pool, conf->logname), - APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS)) { - /* Soak up script output */ - while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_in) == 0) - continue; - if (script_err) { - while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_err) == 0) - continue; - } - return ret; - } - - /* "%% [Wed Jun 19 10:53:21 1996] GET /cgid-bin/printenv HTTP/1.0" */ - apr_ctime(time_str, apr_time_now()); - apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri, - r->args ? "?" : "", r->args ? r->args : "", r->protocol); - /* "%% 500 /usr/local/apache/cgid-bin" */ - apr_file_printf(f, "%%%% %d %s\n", ret, r->filename); - - apr_file_puts("%request\n", f); - for (i = 0; i < hdrs_arr->nelts; ++i) { - if (!hdrs[i].key) - continue; - apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); - } - if ((r->method_number == M_POST || r->method_number == M_PUT) - && *dbuf) { - apr_file_printf(f, "\n%s\n", dbuf); - } - - apr_file_puts("%response\n", f); - hdrs_arr = apr_table_elts(r->err_headers_out); - hdrs = (apr_table_entry_t *) hdrs_arr->elts; - - for (i = 0; i < hdrs_arr->nelts; ++i) { - if (!hdrs[i].key) - continue; - apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); - } - - if (sbuf && *sbuf) - apr_file_printf(f, "%s\n", sbuf); - - if (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_in) == 0) { - apr_file_puts("%stdout\n", f); - apr_file_puts(argsbuffer, f); - while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_in) == 0) - apr_file_puts(argsbuffer, f); - apr_file_puts("\n", f); - } - - if (script_err) { - if (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_err) == 0) { - apr_file_puts("%stderr\n", f); - apr_file_puts(argsbuffer, f); - while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_err) == 0) - apr_file_puts(argsbuffer, f); - apr_file_puts("\n", f); - } - } - - apr_file_close(script_in); - if (script_err) { - apr_file_close(script_err); - } - - apr_file_close(f); - return ret; -} - - - -/**************************************************************** - * - * Actual cgid handling... - */ -static int cgid_handler(request_rec *r) -{ - int retval, nph, dbpos = 0; - char *argv0, *dbuf = NULL; - apr_bucket_brigade *bb; - apr_bucket *b; - char argsbuffer[HUGE_STRING_LEN]; - cgid_server_conf *conf; - int is_included; - int sd; - char **env; - struct sockaddr_un unix_addr; - apr_file_t *tempsock; - apr_size_t nbytes; - - if(strcmp(r->handler,CGI_MAGIC_TYPE) && strcmp(r->handler,"cgi-script")) - return DECLINED; - - if (r->method_number == M_OPTIONS) { - /* 99 out of 100 cgid scripts, this is all they support */ - r->allowed |= (1 << M_GET); - r->allowed |= (1 << M_POST); - return DECLINED; - } - - conf = ap_get_module_config(r->server->module_config, &cgid_module); - is_included = !strcmp(r->protocol, "INCLUDED"); - - if ((argv0 = strrchr(r->filename, '/')) != NULL) - argv0++; - else - argv0 = r->filename; - - nph = !(strncmp(argv0, "nph-", 4)); - - if ((argv0 = strrchr(r->filename, '/')) != NULL) - argv0++; - else - argv0 = r->filename; - - if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r)) - return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, - "Options ExecCGI is off in this directory"); - if (nph && is_included) - return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, - "attempt to include NPH CGI script"); - -#if defined(OS2) || defined(WIN32) -#error mod_cgid does not work on this platform. If you teach it to, look -#error at mod_cgi.c for required code in this path. -#else - if (r->finfo.filetype == 0) - return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, - "script not found or unable to stat"); -#endif - if (r->finfo.filetype == APR_DIR) - return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, - "attempt to invoke directory as script"); -/* - if (!ap_suexec_enabled) { - if (!ap_can_exec(&r->finfo)) - return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, - "file permissions deny server execution"); - } -*/ - ap_add_common_vars(r); - ap_add_cgi_vars(r); - env = ap_create_environment(r->pool, r->subprocess_env); - - if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, errno, - "unable to create socket to cgi daemon"); - } - memset(&unix_addr, 0, sizeof(unix_addr)); - unix_addr.sun_family = AF_UNIX; - strcpy(unix_addr.sun_path, conf->sockname); - - if (connect(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0) { - return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, errno, - "unable to connect to cgi daemon"); - } - - send_req(sd, r, argv0, env, CGI_REQ); - - /* We are putting the tempsock variable into a file so that we can use - * a pipe bucket to send the data to the client. - */ - apr_os_file_put(&tempsock, &sd, r->pool); - - if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) - return retval; - - if ((argv0 = strrchr(r->filename, '/')) != NULL) - argv0++; - else - argv0 = r->filename; - - /* Transfer any put/post args, CERN style... - * Note that we already ignore SIGPIPE in the core server. - */ - - if (ap_should_client_block(r)) { - int dbsize, len_read; - - if (conf->logname) { - dbuf = apr_pcalloc(r->pool, conf->bufbytes + 1); - dbpos = 0; - } - - while ((len_read = - ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN)) > 0) { - if (conf->logname) { - if ((dbpos + len_read) > conf->bufbytes) { - dbsize = conf->bufbytes - dbpos; - } - else { - dbsize = len_read; - } - memcpy(dbuf + dbpos, argsbuffer, dbsize); - dbpos += dbsize; - } - nbytes = len_read; - apr_file_write(tempsock, argsbuffer, &nbytes); - if (nbytes < len_read) { - /* silly script stopped reading, soak up remaining message */ - while (ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0) { - /* dump it */ - } - break; - } - } - } - /* we're done writing, or maybe we didn't write at all; - * force EOF on child's stdin so that the cgi detects end (or - * absence) of data - */ - shutdown(sd, 1); - - /* Handle script return... */ - if (!nph) { - const char *location; - char sbuf[MAX_STRING_LEN]; - int ret; - - if ((ret = ap_scan_script_header_err(r, tempsock, sbuf))) { - return log_script(r, conf, ret, dbuf, sbuf, tempsock, NULL); - } - - location = apr_table_get(r->headers_out, "Location"); - - if (location && location[0] == '/' && r->status == 200) { - - /* Soak up all the script output */ - while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, tempsock) > 0) { - continue; - } - /* This redirect needs to be a GET no matter what the original - * method was. - */ - r->method = apr_pstrdup(r->pool, "GET"); - r->method_number = M_GET; - - /* We already read the message body (if any), so don't allow - * the redirected request to think it has one. We can ignore - * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. - */ - apr_table_unset(r->headers_in, "Content-Length"); - - ap_internal_redirect_handler(location, r); - return OK; - } - else if (location && r->status == 200) { - /* XX Note that if a script wants to produce its own Redirect - * body, it now has to explicitly *say* "Status: 302" - */ - return HTTP_MOVED_TEMPORARILY; - } - - if (!r->header_only) { - bb = apr_brigade_create(r->pool); - b = apr_bucket_pipe_create(tempsock); - APR_BRIGADE_INSERT_TAIL(bb, b); - b = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - ap_pass_brigade(r->output_filters, bb); - } - } - - if (nph) { - bb = apr_brigade_create(r->pool); - b = apr_bucket_pipe_create(tempsock); - APR_BRIGADE_INSERT_TAIL(bb, b); - b = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - ap_pass_brigade(r->output_filters, bb); - } - - apr_file_close(tempsock); - - return OK; /* NOT r->status, even if it has changed. */ -} - - - - -/*============================================================================ - *============================================================================ - * This is the beginning of the cgi filter code moved from mod_include. This - * is the code required to handle the "exec" SSI directive. - *============================================================================ - *============================================================================*/ -static int include_cgi(char *s, request_rec *r, ap_filter_t *next, - apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - request_rec *rr = ap_sub_req_lookup_uri(s, r, next); - int rr_status; - apr_bucket *tmp_buck, *tmp2_buck; - - if (rr->status != HTTP_OK) { - return -1; - } - - /* No hardwired path info or query allowed */ - - if ((rr->path_info && rr->path_info[0]) || rr->args) { - return -1; - } - if (rr->finfo.protection == 0) { - return -1; - } - - /* Script gets parameters of the *document*, for back compatibility */ - - rr->path_info = r->path_info; /* hard to get right; see mod_cgi.c */ - rr->args = r->args; - - /* Force sub_req to be treated as a CGI request, even if ordinary - * typing rules would have called it something else. - */ - - rr->content_type = CGI_MAGIC_TYPE; - - /* Run it. */ - - rr_status = ap_run_sub_req(rr); - if (ap_is_HTTP_REDIRECT(rr_status)) { - apr_size_t len_loc, h_wrt; - const char *location = apr_table_get(rr->headers_out, "Location"); - - location = ap_escape_html(rr->pool, location); - len_loc = strlen(location); - - tmp_buck = apr_bucket_immortal_create("<A HREF=\"", sizeof("<A HREF=\"")); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck); - tmp2_buck = apr_bucket_heap_create(location, len_loc, 1, &h_wrt); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck); - tmp2_buck = apr_bucket_immortal_create("\">", sizeof("\">")); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck); - tmp2_buck = apr_bucket_heap_create(location, len_loc, 1, &h_wrt); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck); - tmp2_buck = apr_bucket_immortal_create("</A>", sizeof("</A>")); - APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck); - - if (*inserted_head == NULL) { - *inserted_head = tmp_buck; - } - } - - ap_destroy_sub_req(rr); - - return 0; -} - - -/* This is the special environment used for running the "exec cmd=" - * variety of SSI directives. - */ -static void add_ssi_vars(request_rec *r, ap_filter_t *next) -{ - apr_table_t *e = r->subprocess_env; - - if (r->path_info && r->path_info[0] != '\0') { - request_rec *pa_req; - - apr_table_setn(e, "PATH_INFO", ap_escape_shell_cmd(r->pool, r->path_info)); - - pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info), r, next); - if (pa_req->filename) { - apr_table_setn(e, "PATH_TRANSLATED", - apr_pstrcat(r->pool, pa_req->filename, pa_req->path_info, NULL)); - } - } - - if (r->args) { - char *arg_copy = apr_pstrdup(r->pool, r->args); - - apr_table_setn(e, "QUERY_STRING", r->args); - ap_unescape_url(arg_copy); - apr_table_setn(e, "QUERY_STRING_UNESCAPED", ap_escape_shell_cmd(r->pool, arg_copy)); - } -} - -static int include_cmd(include_ctx_t *ctx, apr_bucket_brigade **bb, char *command, - request_rec *r, ap_filter_t *f) -{ - char **env; - const char *location; - int sd; - int retval; - apr_bucket_brigade *bcgi; - apr_bucket *b; - struct sockaddr_un unix_addr; - apr_file_t *tempsock = NULL; - cgid_server_conf *conf = ap_get_module_config(r->server->module_config, - &cgid_module); - - add_ssi_vars(r, f->next); - env = ap_create_environment(r->pool, r->subprocess_env); - - if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, 0, - "unable to create socket to cgi daemon"); - } - - memset(&unix_addr, 0, sizeof(unix_addr)); - unix_addr.sun_family = AF_UNIX; - strcpy(unix_addr.sun_path, conf->sockname); - - if (connect(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0) { - return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, 0, - "unable to connect to cgi daemon"); - } - - SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next); - - send_req(sd, r, command, env, SSI_REQ); - - /* We are putting the tempsock variable into a file so that we can use - * a pipe bucket to send the data to the client. - */ - apr_os_file_put(&tempsock, &sd, r->pool); - - if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) - return retval; - - location = apr_table_get(r->headers_out, "Location"); - - if (location && location[0] == '/' && r->status == 200) { - char argsbuffer[HUGE_STRING_LEN]; - - /* Soak up all the script output */ - while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, tempsock) > 0) { - continue; - } - /* This redirect needs to be a GET no matter what the original - * method was. - */ - r->method = apr_pstrdup(r->pool, "GET"); - r->method_number = M_GET; - - /* We already read the message body (if any), so don't allow - * the redirected request to think it has one. We can ignore - * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. - */ - apr_table_unset(r->headers_in, "Content-Length"); - - ap_internal_redirect_handler(location, r); - return OK; - } - else if (location && r->status == 200) { - /* XX Note that if a script wants to produce its own Redirect - * body, it now has to explicitly *say* "Status: 302" - */ - return HTTP_MOVED_TEMPORARILY; - } - - if (!r->header_only) { - bcgi = apr_brigade_create(r->pool); - b = apr_bucket_pipe_create(tempsock); - APR_BRIGADE_INSERT_TAIL(bcgi, b); - ap_pass_brigade(f->next, bcgi); - } - - return 0; -} - -static int handle_exec(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r, - ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) -{ - char *tag = NULL; - char *tag_val = NULL; - char *file = r->filename; - apr_bucket *tmp_buck; - char parsed_string[MAX_STRING_LEN]; - - *inserted_head = NULL; - if (ctx->flags & FLAG_PRINTING) { - if (ctx->flags & FLAG_NO_EXEC) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "exec used but not allowed in %s", r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - else { - while (1) { - cgid_pfn_gtv(ctx, &tag, &tag_val, 1); - if (tag_val == NULL) { - if (tag == NULL) { - return (0); - } - else { - return 1; - } - } - if (!strcmp(tag, "cmd")) { - cgid_pfn_ps(r, tag_val, parsed_string, sizeof(parsed_string), 1); - if (include_cmd(ctx, bb, parsed_string, r, f) == -1) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "execution failure for parameter \"%s\" " - "to tag exec in file %s", tag, r->filename); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - /* just in case some stooge changed directories */ - } - else if (!strcmp(tag, "cgi")) { - cgid_pfn_ps(r, tag_val, parsed_string, sizeof(parsed_string), 0); - SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next); - if (include_cgi(parsed_string, r, f->next, head_ptr, inserted_head) == -1) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "invalid CGI ref \"%s\" in %s", tag_val, file); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "unknown parameter \"%s\" to tag exec in %s", tag, file); - CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); - } - } - } - } - return 0; -} -/*============================================================================ - *============================================================================ - * This is the end of the cgi filter code moved from mod_include. - *============================================================================ - *============================================================================*/ - - -static void register_hook(apr_pool_t *p) -{ - static const char * const aszPre[] = { "mod_include.c", NULL }; - - ap_hook_post_config(cgid_init, aszPre, NULL, APR_HOOK_MIDDLE); - ap_hook_handler(cgid_handler, NULL, NULL, APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA cgid_module = { - STANDARD20_MODULE_STUFF, - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - create_cgid_config, /* server config */ - merge_cgid_config, /* merge server config */ - cgid_cmds, /* command table */ - register_hook /* register_handlers */ -}; - diff --git a/modules/generators/mod_info.c b/modules/generators/mod_info.c deleted file mode 100644 index 3c5e014fcf..0000000000 --- a/modules/generators/mod_info.c +++ /dev/null @@ -1,491 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * Info Module. Display configuration information for the server and - * all included modules. - * - * <Location /server-info> - * SetHandler server-info - * </Location> - * - * 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 <rasmus@vex.net>, May 1996 - * - * 05.01.96 Initial Version - * - * Lou Langholtz <ldl@usi.utah.edu>, July 1997 - * - * 07.11.97 Addition of the AddModuleInfo directive - * - * Ryan Morgan <rmorgan@covalent.net> - * - * 8.11.00 Port to Apache 2.0. Read configuation from the configuration - * tree rather than reparse the entire configuation file. - * - */ - -#define CORE_PRIVATE - -#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 "apr_strings.h" -#include "apr_lib.h" -#define APR_WANT_STRFUNC -#include "apr_want.h" -#include "ap_mpm.h" - -typedef struct { - const char *name; /* matching module name */ - const char *info; /* additional info */ -} info_entry; - -typedef struct { - apr_array_header_t *more_info; -} info_svr_conf; - -module AP_MODULE_DECLARE_DATA info_module; - -static void *create_info_config(apr_pool_t *p, server_rec *s) -{ - info_svr_conf *conf = (info_svr_conf *) apr_pcalloc(p, sizeof(info_svr_conf)); - - conf->more_info = apr_array_make(p, 20, sizeof(info_entry)); - return conf; -} - -static void *merge_info_config(apr_pool_t *p, void *basev, void *overridesv) -{ - info_svr_conf *new = (info_svr_conf *) apr_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 = apr_array_append(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, int close) -{ - 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 == '<') { - if (close) { - strncpy(t, "</,", end_buf -t); - t += 5; - } else { - 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 if (*s == ' ') { - if (close) { - strncpy(t, ">", end_buf -t); - t += 4; - break; - } else { - *t++ = *s; - } - } else { - *t++ = *s; - } - s++; - } - /* oops, overflowed... don't overwrite */ - if (t > end_buf) { - *end_buf = '\0'; - } - else { - *t = '\0'; - } - return (buf); -} - -static void mod_info_module_cmds(request_rec * r, const command_rec * cmds, - ap_directive_t * conftree) -{ - const command_rec *cmd; - ap_directive_t *tmptree = conftree; - - char buf[MAX_STRING_LEN]; - char htmlstring[MAX_STRING_LEN]; - int block_start = 0; - int nest = 0; - - while (tmptree != NULL) { - cmd = cmds; - while (cmd->name) { - if ((cmd->name[0] != '<') && - (strcasecmp(cmd->name, tmptree->directive) == 0)) { - if (nest > block_start) { - block_start++; - apr_snprintf(htmlstring, sizeof(htmlstring), "%s %s", - tmptree->parent->directive, - tmptree->parent->args); - ap_rprintf(r, "<dd><tt>%s</tt><br>\n", - mod_info_html_cmd_string(htmlstring, buf, - sizeof(buf), 0)); - } - if (nest == 2) { - ap_rprintf(r, "<dd><tt> %s " - "<i>%s</i></tt><br>\n", - tmptree->directive, tmptree->args); - } else if (nest == 1) { - ap_rprintf(r, - "<dd><tt> %s <i>%s</i></tt><br>\n", - tmptree->directive, tmptree->args); - } else { - ap_rprintf(r, "<dd><tt>%s <i>%s</i></tt><br>\n", - mod_info_html_cmd_string(tmptree->directive, - buf, sizeof(buf), - 0), tmptree->args); - } - } - ++cmd; - } - if (tmptree->first_child != NULL) { - tmptree = tmptree->first_child; - nest++; - } else if (tmptree->next != NULL) { - tmptree = tmptree->next; - } else { - if (block_start) { - apr_snprintf(htmlstring, sizeof(htmlstring), "%s %s", - tmptree->parent->directive, - tmptree->parent->args); - ap_rprintf(r, "<dd><tt>%s</tt><br>\n", - mod_info_html_cmd_string(htmlstring, buf, - sizeof(buf), 1)); - block_start--; - } - if (tmptree->parent) { - tmptree = tmptree->parent->next; - } - else { - tmptree = NULL; - } - nest--; - } - - } -} -static const 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]; - const char *more_info; - const command_rec *cmd = NULL; -#ifdef NEVERMORE - const handler_rec *hand = NULL; -#endif - server_rec *serv = r->server; - int comma = 0; - - if (strcmp(r->handler, "server-info")) - return DECLINED; - - r->allowed |= (1 << M_GET); - if (r->method_number != M_GET) - return DECLINED; - - r->content_type = "text/html"; - if (r->header_only) { - return 0; - } - - ap_rputs(DOCTYPE_HTML_3_2 - "<html><head><title>Server Information</title></head>\n", r); - ap_rputs("<body><h1 align=center>Apache Server Information</h1>\n", r); - if (!r->args || strcasecmp(r->args, "list")) { - if (!r->args) { - ap_rputs("<tt><a href=\"#server\">Server Settings</a>, ", r); - for (modp = ap_top_module; modp; modp = modp->next) { - ap_rprintf(r, "<a href=\"#%s\">%s</a>", modp->name, modp->name); - if (modp->next) { - ap_rputs(", ", r); - } - } - ap_rputs("</tt><hr>", r); - - } - if (!r->args || !strcasecmp(r->args, "server")) { - int max_daemons, forked, threaded; - - ap_rprintf(r, "<a name=\"server\"><strong>Server Version:</strong> " - "<font size=+1><tt>%s</tt></a></font><br>\n", - ap_get_server_version()); - ap_rprintf(r, "<strong>Server Built:</strong> " - "<font size=+1><tt>%s</tt></a></font><br>\n", - ap_get_server_built()); - ap_rprintf(r, "<strong>API Version:</strong> " - "<tt>%d:%d</tt><br>\n", - MODULE_MAGIC_NUMBER_MAJOR, MODULE_MAGIC_NUMBER_MINOR); - ap_rprintf(r, "<strong>Hostname/port:</strong> " - "<tt>%s:%u</tt><br>\n", - serv->server_hostname, serv->port); - ap_rprintf(r, "<strong>Timeouts:</strong> " - "<tt>connection: %d " - "keep-alive: %d</tt><br>", - serv->timeout, serv->keep_alive_timeout); - ap_mpm_query(AP_MPMQ_MAX_DAEMONS, &max_daemons); - ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded); - ap_mpm_query(AP_MPMQ_IS_FORKED, &forked); - ap_rprintf(r, "MPM used is %s<br>\n", ap_show_mpm()); - ap_rprintf(r, "<strong>MPM Information:</strong> " - "<tt>Max Daemons: %d Threaded: %s Forked: %s</tt><br>\n", - max_daemons, threaded ? "yes" : "no", - forked ? "yes" : "no"); - ap_rprintf(r, "<strong>Server Root:</strong> " - "<tt>%s</tt><br>\n", ap_server_root); - ap_rprintf(r, "<strong>Config File:</strong> " - "<tt>%s</tt><br>\n", SERVER_CONFIG_FILE); - } - ap_rputs("<hr><dl>", r); - for (modp = ap_top_module; modp; modp = modp->next) { - if (!r->args || !strcasecmp(modp->name, r->args)) { - ap_rprintf(r, "<dt><a name=\"%s\"><strong>Module Name:</strong> " - "<font size=+1><tt>%s</tt></a></font>\n", - modp->name, modp->name); - ap_rputs("<dt><strong>Content handlers:</strong>", r); -#ifdef NEVERMORE - hand = modp->handlers; - if (hand) { - while (hand) { - if (hand->content_type) { - ap_rprintf(r, " <tt>%s</tt>\n", hand->content_type); - } - else { - break; - } - hand++; - if (hand && hand->content_type) { - ap_rputs(",", r); - } - } - } - else { - ap_rputs("<tt> <EM>none</EM></tt>", r); - } -#else - ap_rputs("<tt> <EM>(code broken)</EM></tt>", r); -#endif - ap_rputs("<dt><strong>Configuration Phase Participation:</strong> \n", - r); - if (modp->create_dir_config) { - if (comma) { - ap_rputs(", ", r); - } - ap_rputs("<tt>Create Directory Config</tt>", r); - comma = 1; - } - if (modp->merge_dir_config) { - if (comma) { - ap_rputs(", ", r); - } - ap_rputs("<tt>Merge Directory Configs</tt>", r); - comma = 1; - } - if (modp->create_server_config) { - if (comma) { - ap_rputs(", ", r); - } - ap_rputs("<tt>Create Server Config</tt>", r); - comma = 1; - } - if (modp->merge_server_config) { - if (comma) { - ap_rputs(", ", r); - } - ap_rputs("<tt>Merge Server Configs</tt>", r); - comma = 1; - } - if (!comma) - ap_rputs("<tt> <EM>none</EM></tt>", r); - comma = 0; - ap_rputs("<dt><strong>Module Directives:</strong> ", r); - cmd = modp->cmds; - if (cmd) { - while (cmd) { - if (cmd->name) { - ap_rprintf(r, "<dd><tt>%s - <i>", - mod_info_html_cmd_string(cmd->name, - buf, sizeof(buf), 0)); - if (cmd->errmsg) { - ap_rputs(cmd->errmsg, r); - } - ap_rputs("</i></tt>\n", r); - } - else { - break; - } - cmd++; - } - ap_rputs("<dt><strong>Current Configuration:</strong>\n", r); - mod_info_module_cmds(r, modp->cmds, ap_conftree); - } - else { - ap_rputs("<tt> none</tt>\n", r); - } - more_info = find_more_info(serv, modp->name); - if (more_info) { - ap_rputs("<dt><strong>Additional Information:</strong>\n<dd>", - r); - ap_rputs(more_info, r); - } - ap_rputs("<dt><hr>\n", r); - if (r->args) { - break; - } - } - } - if (!modp && r->args && strcasecmp(r->args, "server")) { - ap_rputs("<b>No such module</b>\n", r); - } - } - else { - for (modp = ap_top_module; modp; modp = modp->next) { - ap_rputs(modp->name, r); - if (modp->next) { - ap_rputs("<br>", r); - } - } - } - ap_rputs("</dl>\n", r); - ap_rputs(ap_psignature("",r), r); - ap_rputs("</body></html>\n", r); - /* Done, turn off timeout, close file and return */ - return 0; -} - -static const char *add_module_info(cmd_parms *cmd, void *dummy, - const char *name, const 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 = apr_array_push(conf->more_info); - - new->name = name; - new->info = info; - return NULL; -} - -static const command_rec info_cmds[] = -{ - AP_INIT_TAKE2("AddModuleInfo", add_module_info, NULL, RSRC_CONF, - "a module name and additional information on that module"), - {NULL} -}; - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_handler(display_info, NULL, NULL, APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA info_module = -{ - STANDARD20_MODULE_STUFF, - 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 apr_table_t */ - register_hooks -}; diff --git a/modules/generators/mod_info.dsp b/modules/generators/mod_info.dsp deleted file mode 100644 index e36e2df870..0000000000 --- a/modules/generators/mod_info.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_info" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_info - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_info.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_info.mak" CFG="mod_info - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_info - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_info - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_info - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_info" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_info.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_info -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_info.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_info - -!ELSEIF "$(CFG)" == "mod_info - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_info" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_info.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_info -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_info.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_info - -!ENDIF - -# Begin Target - -# Name "mod_info - Win32 Release" -# Name "mod_info - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_info.c -# End Source File -# End Target -# End Project diff --git a/modules/generators/mod_info.exp b/modules/generators/mod_info.exp deleted file mode 100644 index c304fa776d..0000000000 --- a/modules/generators/mod_info.exp +++ /dev/null @@ -1 +0,0 @@ -info_module diff --git a/modules/generators/mod_info.mak b/modules/generators/mod_info.mak deleted file mode 100644 index 0a1411ebbd..0000000000 --- a/modules/generators/mod_info.mak +++ /dev/null @@ -1,326 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_info.dsp -!IF "$(CFG)" == "" -CFG=mod_info - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_info - Win32 Release. -!ENDIF - -!IF "$(CFG)" != "mod_info - Win32 Release" && "$(CFG)" !=\ - "mod_info - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_info.mak" CFG="mod_info - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_info - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_info - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_info - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_info.so" - -!ELSE - -ALL : "libapr - Win32 Release" "libhttpd - Win32 Release"\ - "$(OUTDIR)\mod_info.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libhttpd - Win32 ReleaseCLEAN" "libapr - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_info.idb" - -@erase "$(INTDIR)\mod_info.obj" - -@erase "$(OUTDIR)\mod_info.exp" - -@erase "$(OUTDIR)\mod_info.lib" - -@erase "$(OUTDIR)\mod_info.map" - -@erase "$(OUTDIR)\mod_info.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_info" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_info.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_info.pdb" /map:"$(INTDIR)\mod_info.map" /machine:I386\ - /out:"$(OUTDIR)\mod_info.so" /implib:"$(OUTDIR)\mod_info.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_info -LINK32_OBJS= \ - "$(INTDIR)\mod_info.obj" \ - "..\..\Release\libhttpd.lib" \ - "..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_info.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_info - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_info.so" - -!ELSE - -ALL : "libapr - Win32 Debug" "libhttpd - Win32 Debug" "$(OUTDIR)\mod_info.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libhttpd - Win32 DebugCLEAN" "libapr - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_info.idb" - -@erase "$(INTDIR)\mod_info.obj" - -@erase "$(OUTDIR)\mod_info.exp" - -@erase "$(OUTDIR)\mod_info.lib" - -@erase "$(OUTDIR)\mod_info.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Od /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_info" /FD /ZI /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_info.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_info.pdb" /machine:I386 /out:"$(OUTDIR)\mod_info.so"\ - /implib:"$(OUTDIR)\mod_info.lib" /map/debug\ - /base:@..\..\os\win32\BaseAddr.ref,mod_info -LINK32_OBJS= \ - "$(INTDIR)\mod_info.obj" \ - "..\..\Debug\libhttpd.lib" \ - "..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_info.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_info - Win32 Release" || "$(CFG)" ==\ - "mod_info - Win32 Debug" - -!IF "$(CFG)" == "mod_info - Win32 Release" - -"libhttpd - Win32 Release" : - cd "\clean\httpd-2.0" - $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" - cd ".\modules\generators" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "\clean\httpd-2.0" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libhttpd.mak"\ - CFG="libhttpd - Win32 Release" RECURSE=1 - cd ".\modules\generators" - -!ELSEIF "$(CFG)" == "mod_info - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "\clean\httpd-2.0" - $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" - cd ".\modules\generators" - -"libhttpd - Win32 DebugCLEAN" : - cd "\clean\httpd-2.0" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\generators" - -!ENDIF - -!IF "$(CFG)" == "mod_info - Win32 Release" - -"libapr - Win32 Release" : - cd "\clean\httpd-2.0\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" - cd "..\..\modules\generators" - -"libapr - Win32 ReleaseCLEAN" : - cd "\clean\httpd-2.0\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libapr.mak" CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\generators" - -!ELSEIF "$(CFG)" == "mod_info - Win32 Debug" - -"libapr - Win32 Debug" : - cd "\clean\httpd-2.0\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" - cd "..\..\modules\generators" - -"libapr - Win32 DebugCLEAN" : - cd "\clean\httpd-2.0\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libapr.mak" CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\generators" - -!ENDIF - -SOURCE=.\mod_info.c -DEP_CPP_MOD_I=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_mpm.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_main.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_script.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\srclib\apr-util\include\apu.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_dso.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_lock.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\include\apr_user.h"\ - "..\..\srclib\apr\include\apr_want.h"\ - -NODEP_CPP_MOD_I=\ - "..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\mod_info.obj" : $(SOURCE) $(DEP_CPP_MOD_I) "$(INTDIR)" - - - -!ENDIF - diff --git a/modules/generators/mod_status.c b/modules/generators/mod_status.c deleted file mode 100644 index 17f07e888f..0000000000 --- a/modules/generators/mod_status.c +++ /dev/null @@ -1,787 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* Status Module. Display lots of internal data about how Apache is - * performing and the state of all children processes. - * - * To enable this, add the following lines into any config file: - * - * <Location /server-status> - * SetHandler server-status - * </Location> - * - * You may want to protect this location by password or domain so no one - * else can look at it. Then you can access the statistics with a URL like: - * - * http://your_server_name/server-status - * - * /server-status - Returns page using tables - * /server-status?notable - Returns page for browsers without table support - * /server-status?refresh - Returns page with 1 second refresh - * /server-status?refresh=6 - Returns page with refresh every 6 seconds - * /server-status?auto - Returns page with data for automatic parsing - * - * Mark Cox, mark@ukweb.com, November 1995 - * - * 12.11.95 Initial version for www.telescope.org - * 13.3.96 Updated to remove rprintf's [Mark] - * 18.3.96 Added CPU usage, process information, and tidied [Ben Laurie] - * 18.3.96 Make extra Scoreboard variables #definable - * 25.3.96 Make short report have full precision [Ben Laurie suggested] - * 25.3.96 Show uptime better [Mark/Ben Laurie] - * 29.3.96 Better HTML and explanation [Mark/Rob Hartill suggested] - * 09.4.96 Added message for non-STATUS compiled version - * 18.4.96 Added per child and per slot counters [Jim Jagielski] - * 01.5.96 Table format, cleanup, even more spiffy data [Chuck Murcko/Jim J.] - * 18.5.96 Adapted to use new rprintf() routine, incidentally fixing a missing - * piece in short reports [Ben Laurie] - * 21.5.96 Additional Status codes (DNS and LOGGING only enabled if - * extended STATUS is enabled) [George Burgyan/Jim J.] - * 10.8.98 Allow for extended status info at runtime (no more STATUS) - * [Jim J.] - */ - -#define CORE_PRIVATE -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_main.h" -#include "util_script.h" -#include <time.h> -#include "scoreboard.h" -#include "http_log.h" -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#ifdef NEXT -#if (NX_CURRENT_COMPILER_RELEASE == 410) -#ifdef m68k -#define HZ 64 -#else -#define HZ 100 -#endif -#else -#include <machine/param.h> -#endif -#endif /* NEXT */ - -#define STATUS_MAXLINE 64 - -#define KBYTE 1024 -#define MBYTE 1048576L -#define GBYTE 1073741824L - -#ifndef DEFAULT_TIME_FORMAT -#define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z" -#endif - -#define STATUS_MAGIC_TYPE "application/x-httpd-status" - -module AP_MODULE_DECLARE_DATA status_module; - -/* - *command-related code. This is here to prevent use of ExtendedStatus - * without status_module included. - */ -static const char *set_extended_status(cmd_parms *cmd, void *dummy, int arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - ap_extended_status = arg; - return NULL; -} - -static const command_rec status_module_cmds[] = -{ - AP_INIT_FLAG("ExtendedStatus", set_extended_status, NULL, RSRC_CONF, - "\"On\" to enable extended status information, \"Off\" to disable"), - {NULL} -}; - -/* Format the number of bytes nicely */ -static void format_byte_out(request_rec *r, unsigned long bytes) -{ - if (bytes < (5 * KBYTE)) - ap_rprintf(r, "%d B", (int) bytes); - else if (bytes < (MBYTE / 2)) - ap_rprintf(r, "%.1f kB", (float) bytes / KBYTE); - else if (bytes < (GBYTE / 2)) - ap_rprintf(r, "%.1f MB", (float) bytes / MBYTE); - else - ap_rprintf(r, "%.1f GB", (float) bytes / GBYTE); -} - -static void format_kbyte_out(request_rec *r, unsigned long kbytes) -{ - if (kbytes < KBYTE) - ap_rprintf(r, "%d kB", (int) kbytes); - else if (kbytes < MBYTE) - ap_rprintf(r, "%.1f MB", (float) kbytes / KBYTE); - else - ap_rprintf(r, "%.1f GB", (float) kbytes / MBYTE); -} - -static void show_time(request_rec *r, apr_interval_time_t tsecs) -{ - int days, hrs, mins, secs; - - secs = tsecs % 60; - tsecs /= 60; - mins = tsecs % 60; - tsecs /= 60; - hrs = tsecs % 24; - days = tsecs / 24; - if (days) - ap_rprintf(r, " %d day%s", days, days == 1 ? "" : "s"); - if (hrs) - ap_rprintf(r, " %d hour%s", hrs, hrs == 1 ? "" : "s"); - if (mins) - ap_rprintf(r, " %d minute%s", mins, mins == 1 ? "" : "s"); - if (secs) - ap_rprintf(r, " %d second%s", secs, secs == 1 ? "" : "s"); -} - -/* Main handler for x-httpd-status requests */ - -/* ID values for command table */ - -#define STAT_OPT_END -1 -#define STAT_OPT_REFRESH 0 -#define STAT_OPT_NOTABLE 1 -#define STAT_OPT_AUTO 2 - -struct stat_opt { - int id; - const char *form_data_str; - const char *hdr_out_str; -}; - -static const struct stat_opt status_options[] = /* see #defines above */ -{ - {STAT_OPT_REFRESH, "refresh", "Refresh"}, - {STAT_OPT_NOTABLE, "notable", NULL}, - {STAT_OPT_AUTO, "auto", NULL}, - {STAT_OPT_END, NULL, NULL} -}; - -static char status_flags[SERVER_NUM_STATUS]; - -static int status_handler(request_rec *r) -{ - const char *loc; - apr_time_t nowtime; - apr_interval_time_t up_time; - int j, i, res; - int ready = 0; - int busy = 0; - unsigned long count = 0; - unsigned long lres, bytes; - unsigned long my_lres, my_bytes, conn_bytes; - unsigned short conn_lres; - unsigned long bcount = 0; - unsigned long kbcount = 0; - long req_time; -#ifdef HAVE_TIMES -#ifdef _SC_CLK_TCK - float tick = sysconf(_SC_CLK_TCK); -#else - float tick = HZ; -#endif -#endif - int short_report = 0; - int no_table_report = 0; - short_score score_record; - parent_score ps_record; - char stat_buffer[HARD_SERVER_LIMIT * HARD_THREAD_LIMIT]; - int pid_buffer[HARD_SERVER_LIMIT * HARD_THREAD_LIMIT]; - clock_t tu, ts, tcu, tcs; - server_rec *vhost; - - if (strcmp(r->handler, STATUS_MAGIC_TYPE) && strcmp(r->handler, "server-status")) { - return DECLINED; - } - - nowtime = apr_time_now(); - tu = ts = tcu = tcs = 0; - - if (!ap_exists_scoreboard_image()) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Server status unavailable in inetd mode"); - return HTTP_INTERNAL_SERVER_ERROR; - } - r->allowed = (1 << M_GET); - if (r->method_number != M_GET) - return DECLINED; - - r->content_type = "text/html"; - - /* - * Simple table-driven form data set parser that lets you alter the header - */ - - if (r->args) { - i = 0; - while (status_options[i].id != STAT_OPT_END) { - if ((loc = ap_strstr_c(r->args, status_options[i].form_data_str)) != NULL) { - switch (status_options[i].id) { - case STAT_OPT_REFRESH: - if (*(loc + strlen(status_options[i].form_data_str)) == '=' - && atol(loc + strlen(status_options[i].form_data_str) - + 1) > 0) - apr_table_set(r->headers_out, - status_options[i].hdr_out_str, - loc + strlen(status_options[i].hdr_out_str) + 1); - else - apr_table_set(r->headers_out, - status_options[i].hdr_out_str, "1"); - break; - case STAT_OPT_NOTABLE: - no_table_report = 1; - break; - case STAT_OPT_AUTO: - r->content_type = "text/plain"; - short_report = 1; - break; - } - } - i++; - } - } - - if (r->header_only) - return 0; - -/* ap_sync_scoreboard_image(); */ - for (i = 0; i < HARD_SERVER_LIMIT; ++i) { - for (j = 0; j < HARD_THREAD_LIMIT; ++j) { - int indx = (i * HARD_THREAD_LIMIT) + j; - - score_record = ap_scoreboard_image->servers[i][j]; - ps_record = ap_scoreboard_image->parent[i]; - res = score_record.status; - stat_buffer[indx] = status_flags[res]; - pid_buffer[indx] = (int) ps_record.pid; - if (res == SERVER_READY) - ready++; - else if (res != SERVER_DEAD) - busy++; - if (ap_extended_status) { - lres = score_record.access_count; - bytes = score_record.bytes_served; - if (lres != 0 || (res != SERVER_READY && res != SERVER_DEAD)) { -#ifdef HAVE_TIMES - tu += score_record.times.tms_utime; - ts += score_record.times.tms_stime; - tcu += score_record.times.tms_cutime; - tcs += score_record.times.tms_cstime; -#endif /* HAVE_TIMES */ - count += lres; - bcount += bytes; - if (bcount >= KBYTE) { - kbcount += (bcount >> 10); - bcount = bcount & 0x3ff; - } - } - } - } - } - - /* up_time in seconds */ - up_time = (apr_uint32_t) ((nowtime - ap_restart_time)/1000000); - - if (!short_report) { - ap_rputs(DOCTYPE_HTML_3_2 - "<HTML><HEAD>\n<TITLE>Apache Status</TITLE>\n</HEAD><BODY>\n", - r); - ap_rputs("<H1>Apache Server Status for ", r); - ap_rvputs(r, ap_get_server_name(r), "</H1>\n\n", NULL); - ap_rvputs(r, "Server Version: ", - ap_get_server_version(), "<br>\n", NULL); - ap_rvputs(r, "Server Built: ", - ap_get_server_built(), "<br>\n<hr>\n", NULL); - ap_rvputs(r, "Current Time: ", - ap_ht_time(r->pool, nowtime, DEFAULT_TIME_FORMAT, 0), "<br>\n", NULL); - ap_rvputs(r, "Restart Time: ", - ap_ht_time(r->pool, ap_restart_time, DEFAULT_TIME_FORMAT, 0), - "<br>\n", NULL); - ap_rprintf(r, "Parent Server Generation: %d <br>\n", (int) ap_my_generation); - ap_rputs("Server uptime: ", r); - show_time(r, up_time); - ap_rputs("<br>\n", r); - } - - if (ap_extended_status) { - if (short_report) { - ap_rprintf(r, "Total Accesses: %lu\nTotal kBytes: %lu\n", - count, kbcount); - -#ifdef HAVE_TIMES - /* Allow for OS/2 not having CPU stats */ - if (ts || tu || tcu || tcs) - ap_rprintf(r, "CPULoad: %g\n", - (tu + ts + tcu + tcs) / tick / up_time * 100.); -#endif - - ap_rprintf(r, "Uptime: %ld\n", (long) (up_time)); - if (up_time > 0) - ap_rprintf(r, "ReqPerSec: %g\n", - (float) count / (float) up_time); - - if (up_time > 0) - ap_rprintf(r, "BytesPerSec: %g\n", - KBYTE * (float) kbcount / (float) up_time); - - if (count > 0) - ap_rprintf(r, "BytesPerReq: %g\n", - KBYTE * (float) kbcount / (float) count); - } - else { /* !short_report */ - ap_rprintf(r, "Total accesses: %lu - Total Traffic: ", count); - format_kbyte_out(r, kbcount); - -#ifdef HAVE_TIMES - /* Allow for OS/2 not having CPU stats */ - ap_rputs("<br>\n", r); - ap_rprintf(r, "CPU Usage: u%g s%g cu%g cs%g", - tu / tick, ts / tick, tcu / tick, tcs / tick); - - if (ts || tu || tcu || tcs) - ap_rprintf(r, " - %.3g%% CPU load", - (tu + ts + tcu + tcs) / tick / up_time * 100.); -#endif - - ap_rputs("<br>\n", r); - - if (up_time > 0) - ap_rprintf(r, "%.3g requests/sec - ", - (float) count / (float) up_time); - - if (up_time > 0) { - format_byte_out(r, KBYTE * (float) kbcount / (float) up_time); - ap_rputs("/second - ", r); - } - - if (count > 0) { - format_byte_out(r, KBYTE * (float) kbcount / (float) count); - ap_rputs("/request", r); - } - - ap_rputs("<br>\n", r); - } /* short_report */ - } /* ap_extended_status */ - - if (!short_report) - ap_rprintf(r, "\n%d requests currently being processed, %d idle servers\n" - ,busy, ready); - else - ap_rprintf(r, "BusyServers: %d\nIdleServers: %d\n", busy, ready); - - /* send the scoreboard 'table' out */ - - if (!short_report) - ap_rputs("<PRE>", r); - else - ap_rputs("Scoreboard: ", r); - - for (i = 0; i < HARD_SERVER_LIMIT; ++i) { - for (j = 0; j < HARD_THREAD_LIMIT; ++j) { - int indx = (i * HARD_THREAD_LIMIT) + j; - ap_rputc(stat_buffer[indx], r); - if ((indx % STATUS_MAXLINE == (STATUS_MAXLINE - 1)) && !short_report) - ap_rputs("\n", r); - } - } - - if (short_report) - ap_rputs("\n", r); - else { - ap_rputs("</PRE>\n", r); - ap_rputs("Scoreboard Key: <br>\n", r); - ap_rputs("\"<B><code>_</code></B>\" Waiting for Connection, \n", r); - ap_rputs("\"<B><code>S</code></B>\" Starting up, \n", r); - ap_rputs("\"<B><code>R</code></B>\" Reading Request,<BR>\n", r); - ap_rputs("\"<B><code>W</code></B>\" Sending Reply, \n", r); - ap_rputs("\"<B><code>K</code></B>\" Keepalive (read), \n", r); - ap_rputs("\"<B><code>D</code></B>\" DNS Lookup,<BR>\n", r); - ap_rputs("\"<B><code>L</code></B>\" Logging, \n", r); - ap_rputs("\"<B><code>G</code></B>\" Gracefully finishing, \n", r); - ap_rputs("\"<B><code>I</code></B>\" Idle cleanup of worker, \n", r); - ap_rputs("\"<B><code>.</code></B>\" Open slot with no current process<P>\n", r); - ap_rputs("<P>\n", r); - if (!ap_extended_status) { - int j; - int k = 0; - ap_rputs("PID Key: <br>\n", r); - ap_rputs("<PRE>\n", r); - for (i = 0; i < HARD_SERVER_LIMIT; ++i) { - for (j = 0; j < HARD_THREAD_LIMIT; ++j) { - int indx = (i * HARD_THREAD_LIMIT) + j; - - if (stat_buffer[indx] != '.') { - ap_rprintf(r, " %d in state: %c ", pid_buffer[i], - stat_buffer[indx]); - if (++k >= 3) { - ap_rputs("\n", r); - k = 0; - } else - ap_rputs(",", r); - } - } - } - ap_rputs("\n", r); - ap_rputs("</PRE>\n", r); - } - } - - if (ap_extended_status) { - if (!short_report) { - if (no_table_report) - ap_rputs("<p><hr><h2>Server Details</h2>\n\n", r); - else -#ifndef HAVE_TIMES - /* Allow for OS/2 not having CPU stats */ - ap_rputs("<p>\n\n<table border=0><tr><th>Srv<th>PID<th>Acc<th>M\n<th>SS<th>Req<th>Conn<th>Child<th>Slot<th>Client<th>VHost<th>Request</tr>\n\n", r); -#else - ap_rputs("<p>\n\n<table border=0><tr><th>Srv<th>PID<th>Acc<th>M<th>CPU\n<th>SS<th>Req<th>Conn<th>Child<th>Slot<th>Client<th>VHost<th>Request</tr>\n\n", r); -#endif - } - - for (i = 0; i < HARD_SERVER_LIMIT; ++i) { - for (j = 0; j < HARD_THREAD_LIMIT; ++j) { - score_record = ap_scoreboard_image->servers[i][j]; - ps_record = ap_scoreboard_image->parent[i]; - vhost = score_record.vhostrec; - if (ps_record.generation != ap_my_generation) { - vhost = NULL; - } - - -#if defined(NO_GETTIMEOFDAY) -#ifdef HAVE_TIMES - if (score_record.start_time == (clock_t) 0) -#endif /* HAVE_TIMES */ - req_time = 0L; -#ifdef HAVE_TIMES - else { - req_time = score_record.stop_time - score_record.start_time; - req_time = (req_time * 1000) / (int) tick; - } -#endif /* HAVE_TIMES */ -#else - if (score_record.start_time == 0L && - score_record.start_time == 0L) - req_time = 0L; - else - req_time = - ((score_record.stop_time - score_record.start_time) * 1000) + - ((score_record.stop_time - score_record.start_time) / 1000); -#endif - if (req_time < 0L) - req_time = 0L; - - lres = score_record.access_count; - my_lres = score_record.my_access_count; - conn_lres = score_record.conn_count; - bytes = score_record.bytes_served; - my_bytes = score_record.my_bytes_served; - conn_bytes = score_record.conn_bytes; - if (lres != 0 || (score_record.status != SERVER_READY - && score_record.status != SERVER_DEAD)) { - if (!short_report) { - if (no_table_report) { - if (score_record.status == SERVER_DEAD) - ap_rprintf(r, - "<b>Server %d-%d</b> (-): %d|%lu|%lu [", - i, (int) ps_record.generation, (int) conn_lres, - my_lres, lres); - else - ap_rprintf(r, - "<b>Server %d-%d</b> (%d): %d|%lu|%lu [", - i, (int) ps_record.generation, - (int) ps_record.pid, - (int) conn_lres, my_lres, lres); - - switch (score_record.status) { - case SERVER_READY: - ap_rputs("Ready", r); - break; - case SERVER_STARTING: - ap_rputs("Starting", r); - break; - case SERVER_BUSY_READ: - ap_rputs("<b>Read</b>", r); - break; - case SERVER_BUSY_WRITE: - ap_rputs("<b>Write</b>", r); - break; - case SERVER_BUSY_KEEPALIVE: - ap_rputs("<b>Keepalive</b>", r); - break; - case SERVER_BUSY_LOG: - ap_rputs("<b>Logging</b>", r); - break; - case SERVER_BUSY_DNS: - ap_rputs("<b>DNS lookup</b>", r); - break; - case SERVER_DEAD: - ap_rputs("Dead", r); - break; - case SERVER_GRACEFUL: - ap_rputs("Graceful", r); - break; - default: - ap_rputs("?STATE?", r); - break; - } -#ifndef HAVE_TIMES - /* Allow for OS/2 not having CPU stats */ - ap_rprintf(r, "]\n %.0f %ld (", -#else - - ap_rprintf(r, "] u%g s%g cu%g cs%g\n %.0f %ld (", - score_record.times.tms_utime / tick, - score_record.times.tms_stime / tick, - score_record.times.tms_cutime / tick, - score_record.times.tms_cstime / tick, -#endif -#ifdef OPTIMIZE_TIMEOUTS - difftime(nowtime, ps_record.last_rtime), -#else - difftime(nowtime, score_record.last_used), -#endif - (long) req_time); - format_byte_out(r, conn_bytes); - ap_rputs("|", r); - format_byte_out(r, my_bytes); - ap_rputs("|", r); - format_byte_out(r, bytes); - ap_rputs(")\n", r); - ap_rprintf(r, " <i>%s {%s}</i> <b>[%s]</b><br>\n\n", - ap_escape_html(r->pool, score_record.client), - ap_escape_html(r->pool, score_record.request), - vhost ? ap_escape_html(r->pool, - vhost->server_hostname) : "(unavailable)"); - } - else { /* !no_table_report */ - if (score_record.status == SERVER_DEAD) - ap_rprintf(r, - "<tr><td><b>%d-%d</b><td>-<td>%d/%lu/%lu", - i, (int) ps_record.generation, - (int) conn_lres, my_lres, lres); - else - ap_rprintf(r, - "<tr><td><b>%d-%d</b><td>%d<td>%d/%lu/%lu", - i, (int) ps_record.generation, - (int) ps_record.pid, (int) conn_lres, - my_lres, lres); - - switch (score_record.status) { - case SERVER_READY: - ap_rputs("<td>_", r); - break; - case SERVER_STARTING: - ap_rputs("<td><b>S</b>", r); - break; - case SERVER_BUSY_READ: - ap_rputs("<td><b>R</b>", r); - break; - case SERVER_BUSY_WRITE: - ap_rputs("<td><b>W</b>", r); - break; - case SERVER_BUSY_KEEPALIVE: - ap_rputs("<td><b>K</b>", r); - break; - case SERVER_BUSY_LOG: - ap_rputs("<td><b>L</b>", r); - break; - case SERVER_BUSY_DNS: - ap_rputs("<td><b>D</b>", r); - break; - case SERVER_DEAD: - ap_rputs("<td>.", r); - break; - case SERVER_GRACEFUL: - ap_rputs("<td>G", r); - break; - default: - ap_rputs("<td>?", r); - break; - } -#ifndef HAVE_TIMES - /* Allow for OS/2 not having CPU stats */ - ap_rprintf(r, "\n<td>%.0f<td>%ld", -#else - ap_rprintf(r, "\n<td>%.2f<td>%.0f<td>%ld", - (score_record.times.tms_utime + - score_record.times.tms_stime + - score_record.times.tms_cutime + - score_record.times.tms_cstime) / tick, -#endif -#ifdef OPTIMIZE_TIMEOUTS - difftime(nowtime, ps_record.last_rtime), -#else - difftime(nowtime, score_record.last_used), -#endif - (long) req_time); - ap_rprintf(r, "<td>%-1.1f<td>%-2.2f<td>%-2.2f\n", - (float) conn_bytes / KBYTE, (float) my_bytes / MBYTE, - (float) bytes / MBYTE); - if (score_record.status == SERVER_BUSY_READ) - ap_rprintf(r, - "<td>?<td nowrap>?<td nowrap>..reading.. </tr>\n\n"); - else - ap_rprintf(r, - "<td>%s<td nowrap>%s<td nowrap>%s</tr>\n\n", - ap_escape_html(r->pool, score_record.client), - vhost ? ap_escape_html(r->pool, - vhost->server_hostname) : "(unavailable)", - ap_escape_html(r->pool, score_record.request)); - } /* no_table_report */ - } /* !short_report */ - } /* if (<active child>) */ - } /* for () */ - } - - if (!(short_report || no_table_report)) { -#ifndef HAVE_TIMES - ap_rputs("</table>\n \ -<hr> \ -<table>\n \ -<tr><th>Srv<td>Child Server number - generation\n \ -<tr><th>PID<td>OS process ID\n \ -<tr><th>Acc<td>Number of accesses this connection / this child / this slot\n \ -<tr><th>M<td>Mode of operation\n \ -<tr><th>SS<td>Seconds since beginning of most recent request\n \ -<tr><th>Req<td>Milliseconds required to process most recent request\n \ -<tr><th>Conn<td>Kilobytes transferred this connection\n \ -<tr><th>Child<td>Megabytes transferred this child\n \ -<tr><th>Slot<td>Total megabytes transferred this slot\n \ -</table>\n", r); -#else - ap_rputs("</table>\n \ -<hr> \ -<table>\n \ -<tr><th>Srv<td>Child Server number - generation\n \ -<tr><th>PID<td>OS process ID\n \ -<tr><th>Acc<td>Number of accesses this connection / this child / this slot\n \ -<tr><th>M<td>Mode of operation\n \ -<tr><th>CPU<td>CPU usage, number of seconds\n \ -<tr><th>SS<td>Seconds since beginning of most recent request\n \ -<tr><th>Req<td>Milliseconds required to process most recent request\n \ -<tr><th>Conn<td>Kilobytes transferred this connection\n \ -<tr><th>Child<td>Megabytes transferred this child\n \ -<tr><th>Slot<td>Total megabytes transferred this slot\n \ -</table>\n", r); -#endif - } - - } else { - - if (!short_report) { - ap_rputs("<hr>To obtain a full report with current status information ", r); - ap_rputs("you need to use the <code>ExtendedStatus On</code> directive. \n", r); - } - - } - - if (!short_report) { - ap_rputs(ap_psignature("<HR>\n",r), r); - ap_rputs("</BODY></HTML>\n", r); - } - - return 0; -} - - -static void status_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - status_flags[SERVER_DEAD] = '.'; /* We don't want to assume these are in */ - status_flags[SERVER_READY] = '_'; /* any particular order in scoreboard.h */ - status_flags[SERVER_STARTING] = 'S'; - status_flags[SERVER_BUSY_READ] = 'R'; - status_flags[SERVER_BUSY_WRITE] = 'W'; - status_flags[SERVER_BUSY_KEEPALIVE] = 'K'; - status_flags[SERVER_BUSY_LOG] = 'L'; - status_flags[SERVER_BUSY_DNS] = 'D'; - status_flags[SERVER_GRACEFUL] = 'G'; - status_flags[SERVER_IDLE_KILL] = 'I'; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_handler(status_handler, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_config(status_init, NULL, NULL, APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA status_module = -{ - STANDARD20_MODULE_STUFF, - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - status_module_cmds, /* command table */ - register_hooks /* register_hooks */ -}; - diff --git a/modules/generators/mod_status.dsp b/modules/generators/mod_status.dsp deleted file mode 100644 index 01e117238b..0000000000 --- a/modules/generators/mod_status.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_status" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_status - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_status.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_status.mak" CFG="mod_status - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_status - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_status - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_status - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /I "../../server/mpm/winnt" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_status" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /map /machine:I386 /out:"Release/mod_status.so" /base:@..\..\os\win32\BaseAddr.ref,mod_status -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /map /machine:I386 /out:"Release/mod_status.so" /base:@..\..\os\win32\BaseAddr.ref,mod_status - -!ELSEIF "$(CFG)" == "mod_status - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /I "../../server/mpm/winnt" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_status" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:"Debug/mod_status.so" /base:@..\..\os\win32\BaseAddr.ref,mod_status -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:"Debug/mod_status.so" /base:@..\..\os\win32\BaseAddr.ref,mod_status - -!ENDIF - -# Begin Target - -# Name "mod_status - Win32 Release" -# Name "mod_status - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_status.c -# End Source File -# End Target -# End Project diff --git a/modules/generators/mod_status.exp b/modules/generators/mod_status.exp deleted file mode 100644 index 5438093686..0000000000 --- a/modules/generators/mod_status.exp +++ /dev/null @@ -1 +0,0 @@ -status_module diff --git a/modules/generators/mod_status.mak b/modules/generators/mod_status.mak deleted file mode 100644 index ec22087ff3..0000000000 --- a/modules/generators/mod_status.mak +++ /dev/null @@ -1,330 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_status.dsp -!IF "$(CFG)" == "" -CFG=mod_status - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_status - Win32 Release. -!ENDIF - -!IF "$(CFG)" != "mod_status - Win32 Release" && "$(CFG)" !=\ - "mod_status - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_status.mak" CFG="mod_status - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_status - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_status - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_status - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_status.so" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libapr - Win32 Release"\ - "$(OUTDIR)\mod_status.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_status.idb" - -@erase "$(INTDIR)\mod_status.obj" - -@erase "$(OUTDIR)\mod_status.exp" - -@erase "$(OUTDIR)\mod_status.lib" - -@erase "$(OUTDIR)\mod_status.map" - -@erase "$(OUTDIR)\mod_status.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /I\ - "../../server/mpm/winnt" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\"\ - /Fd"$(INTDIR)\mod_status" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_status.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_status.pdb" /map:"$(INTDIR)\mod_status.map" /machine:I386\ - /out:"$(OUTDIR)\mod_status.so" /implib:"$(OUTDIR)\mod_status.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_status -LINK32_OBJS= \ - "$(INTDIR)\mod_status.obj" \ - "..\..\Release\libhttpd.lib" \ - "..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_status.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_status - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_status.so" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_status.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_status.idb" - -@erase "$(INTDIR)\mod_status.obj" - -@erase "$(OUTDIR)\mod_status.exp" - -@erase "$(OUTDIR)\mod_status.lib" - -@erase "$(OUTDIR)\mod_status.map" - -@erase "$(OUTDIR)\mod_status.pdb" - -@erase "$(OUTDIR)\mod_status.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /I\ - "../../server/mpm/winnt" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\"\ - /Fd"$(INTDIR)\mod_status" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_status.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_status.pdb" /map:"$(INTDIR)\mod_status.map" /debug\ - /machine:I386 /out:"$(OUTDIR)\mod_status.so" /implib:"$(OUTDIR)\mod_status.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_status -LINK32_OBJS= \ - "$(INTDIR)\mod_status.obj" \ - "..\..\Debug\libhttpd.lib" \ - "..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_status.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_status - Win32 Release" || "$(CFG)" ==\ - "mod_status - Win32 Debug" - -!IF "$(CFG)" == "mod_status - Win32 Release" - -"libapr - Win32 Release" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Release" - cd "..\..\modules\generators" - -"libapr - Win32 ReleaseCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\generators" - -!ELSEIF "$(CFG)" == "mod_status - Win32 Debug" - -"libapr - Win32 Debug" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Debug" - cd "..\..\modules\generators" - -"libapr - Win32 DebugCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\generators" - -!ENDIF - -!IF "$(CFG)" == "mod_status - Win32 Release" - -"libhttpd - Win32 Release" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Release" - cd ".\modules\generators" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Release"\ - RECURSE=1 - cd ".\modules\generators" - -!ELSEIF "$(CFG)" == "mod_status - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Debug" - cd ".\modules\generators" - -"libhttpd - Win32 DebugCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\generators" - -!ENDIF - -SOURCE=.\mod_status.c -DEP_CPP_MOD_S=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_main.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\scoreboard.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_script.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\server\mpm\winnt\mpm_default.h"\ - "..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\srclib\apr-util\include\apu.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_dso.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lock.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\include\apr_user.h"\ - "..\..\srclib\apr\include\apr_want.h"\ - -NODEP_CPP_MOD_S=\ - "..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\mod_status.obj" : $(SOURCE) $(DEP_CPP_MOD_S) "$(INTDIR)" - - - -!ENDIF - diff --git a/modules/generators/mod_suexec.c b/modules/generators/mod_suexec.c deleted file mode 100644 index e902fd2b20..0000000000 --- a/modules/generators/mod_suexec.c +++ /dev/null @@ -1,155 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_request.h" -#include "apr_strings.h" -#include "unixd.h" -#include "mpm_common.h" -#include "mod_suexec.h" - -module AP_MODULE_DECLARE_DATA suexec_module; - -/* - * Create a configuration specific to this module for a server or directory - * location, and fill it with the default settings. - */ -static void *mkconfig(apr_pool_t *p) -{ - suexec_config_t *cfg = apr_palloc(p, sizeof(suexec_config_t)); - - cfg->active = 0; - return cfg; -} - -/* - * Respond to a callback to create configuration record for a server or - * vhost environment. - */ -static void *create_mconfig_for_server(apr_pool_t *p, server_rec *s) -{ - return mkconfig(p); -} - -/* - * Respond to a callback to create a config record for a specific directory. - */ -static void *create_mconfig_for_directory(apr_pool_t *p, char *dir) -{ - return mkconfig(p); -} - -static const char *set_suexec_ugid(cmd_parms *cmd, void *mconfig, - const char *uid, const char *gid) -{ - suexec_config_t *cfg = (suexec_config_t *) mconfig; - const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - - if (err != NULL) { - return err; - } - if (unixd_config.suexec_enabled) { - cfg->ugid.uid = ap_uname2id(uid); - cfg->ugid.gid = ap_gname2id(gid); - cfg->active = 1; - } - else { - fprintf(stderr, - "Warning: SuexecUserGroup directive requires SUEXEC wrapper.\n"); - } - return NULL; -} - -static ap_unix_identity_t *get_suexec_id_doer(const request_rec *r) -{ - suexec_config_t *cfg = - (suexec_config_t *) ap_get_module_config(r->per_dir_config, &suexec_module); - - return cfg->active ? &cfg->ugid : NULL; -} - -/* - * Define the directives specific to this module. This structure is referenced - * later by the 'module' structure. - */ -static const command_rec suexec_cmds[] = -{ - /* XXX - Another important reason not to allow this in .htaccess is that - * the ap_[ug]name2id() is not thread-safe */ - AP_INIT_TAKE2("SuexecUserGroup", set_suexec_ugid, NULL, RSRC_CONF, - "User and group for spawned processes"), - { NULL } -}; - -static void suexec_hooks(apr_pool_t *p) -{ - ap_hook_get_suexec_identity(get_suexec_id_doer,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA suexec_module = -{ - STANDARD20_MODULE_STUFF, - create_mconfig_for_directory, /* create per-dir config */ - NULL, /* merge per-dir config */ - create_mconfig_for_server, /* server config */ - NULL, /* merge server config */ - suexec_cmds, /* command table */ - suexec_hooks /* register hooks */ -}; diff --git a/modules/generators/mod_suexec.h b/modules/generators/mod_suexec.h deleted file mode 100644 index 87a77eaa24..0000000000 --- a/modules/generators/mod_suexec.h +++ /dev/null @@ -1,64 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ -#include "unixd.h" - -typedef struct { - ap_unix_identity_t ugid; - int active; -} suexec_config_t; - diff --git a/modules/http/.cvsignore b/modules/http/.cvsignore deleted file mode 100644 index 65f0cc30cf..0000000000 --- a/modules/http/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -.deps -.libs -*.la -modules.mk -Makefile -*.lo -*.slo -*.so -Debug -Release diff --git a/modules/http/.indent.pro b/modules/http/.indent.pro deleted file mode 100644 index a9fbe9f9a1..0000000000 --- a/modules/http/.indent.pro +++ /dev/null @@ -1,54 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 --TBUFF --TFILE --TTRANS --TUINT4 --T_trans --Tallow_options_t --Tapache_sfio --Tarray_header --Tbool_int --Tbuf_area --Tbuff_struct --Tbuffy --Tcmd_how --Tcmd_parms --Tcommand_rec --Tcommand_struct --Tconn_rec --Tcore_dir_config --Tcore_server_config --Tdir_maker_func --Tevent --Tglobals_s --Thandler_func --Thandler_rec --Tjoblist_s --Tlisten_rec --Tmerger_func --Tmode_t --Tmodule --Tmodule_struct --Tmutex --Tn_long --Tother_child_rec --Toverrides_t --Tparent_score --Tpid_t --Tpiped_log --Tpool --Trequest_rec --Trequire_line --Trlim_t --Tscoreboard --Tsemaphore --Tserver_addr_rec --Tserver_rec --Tserver_rec_chain --Tshort_score --Ttable --Ttable_entry --Tthread --Tu_wide_int --Tvtime_t --Twide_int diff --git a/modules/http/Makefile.in b/modules/http/Makefile.in deleted file mode 100644 index 167b343d0d..0000000000 --- a/modules/http/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ - -include $(top_srcdir)/build/special.mk - diff --git a/modules/http/config2.m4 b/modules/http/config2.m4 deleted file mode 100644 index 5fec30cc47..0000000000 --- a/modules/http/config2.m4 +++ /dev/null @@ -1,10 +0,0 @@ -dnl modules enabled in this directory by default - -APACHE_MODPATH_INIT(http) - -http_objects="http_core.lo http_protocol.lo http_request.lo" - -APACHE_MODULE(http, HTTP protocol handling, $http_objects, , yes) -APACHE_MODULE(mime, mapping of file-extension to MIME, , , yes) - -APACHE_MODPATH_FINISH diff --git a/modules/http/http_core.c b/modules/http/http_core.c deleted file mode 100644 index f5948973ab..0000000000 --- a/modules/http/http_core.c +++ /dev/null @@ -1,324 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr_strings.h" -#include "apr_thread_proc.h" /* for RLIMIT stuff */ - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#define CORE_PRIVATE -#include "httpd.h" -#include "http_config.h" -#include "http_connection.h" -#include "http_protocol.h" /* For index_of_response(). Grump. */ -#include "http_request.h" - -#include "util_filter.h" -#include "util_ebcdic.h" -#include "ap_mpm.h" -#include "scoreboard.h" - -#include "mod_core.h" - -static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - cmd->server->keep_alive_timeout = atoi(arg); - return NULL; -} - -static const char *set_keep_alive(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - /* We've changed it to On/Off, but used to use numbers - * so we accept anything but "Off" or "0" as "On" - */ - if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) { - cmd->server->keep_alive = 0; - } - else { - cmd->server->keep_alive = 1; - } - return NULL; -} - -static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - cmd->server->keep_alive_max = atoi(arg); - return NULL; -} - -static const command_rec http_cmds[] = { - AP_INIT_TAKE1("KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF, - "Keep-Alive timeout duration (sec)"), - AP_INIT_TAKE1("MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF, - "Maximum number of Keep-Alive requests per connection, or 0 for infinite"), - AP_INIT_TAKE1("KeepAlive", set_keep_alive, NULL, RSRC_CONF, - "Whether persistent connections should be On or Off"), - { NULL } -}; - -/* - * HTTP/1.1 chunked transfer encoding filter. - */ -static apr_status_t chunk_filter(ap_filter_t *f, apr_bucket_brigade *b) -{ -#define ASCII_CRLF "\015\012" -#define ASCII_ZERO "\060" - apr_bucket_brigade *more = NULL; - apr_bucket *e; - apr_status_t rv; - - for (more = NULL; b; b = more, more = NULL) { - apr_off_t bytes = 0; - apr_bucket *eos = NULL; - char chunk_hdr[20]; /* enough space for the snprintf below */ - - APR_BRIGADE_FOREACH(e, b) { - if (APR_BUCKET_IS_EOS(e)) { - /* there shouldn't be anything after the eos */ - eos = e; - break; - } - else if (e->length == -1) { - /* unknown amount of data (e.g. a pipe) */ - const char *data; - apr_size_t len; - - rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ); - if (rv != APR_SUCCESS) { - return rv; - } - if (len > 0) { - /* - * There may be a new next bucket representing the - * rest of the data stream on which a read() may - * block so we pass down what we have so far. - */ - bytes += len; - more = apr_brigade_split(b, APR_BUCKET_NEXT(e)); - break; - } - else { - /* If there was nothing in this bucket then we can - * safely move on to the next one without pausing - * to pass down what we have counted up so far. - */ - continue; - } - } - else { - bytes += e->length; - } - } - - /* - * XXX: if there aren't very many bytes at this point it may - * be a good idea to set them aside and return for more, - * unless we haven't finished counting this brigade yet. - */ - - /* if there are content bytes, then wrap them in a chunk */ - if (bytes > 0) { - apr_size_t hdr_len; - - /* - * Insert the chunk header, specifying the number of bytes in - * the chunk. - */ - /* XXX might be nice to have APR_OFF_T_FMT_HEX */ - hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr), - "%qx" CRLF, (apr_uint64_t)bytes); - ap_xlate_proto_to_ascii(chunk_hdr, hdr_len); - e = apr_bucket_transient_create(chunk_hdr, hdr_len); - APR_BRIGADE_INSERT_HEAD(b, e); - - /* - * Insert the end-of-chunk CRLF before the EOS bucket, or - * appended to the brigade - */ - e = apr_bucket_immortal_create(ASCII_CRLF, 2); - if (eos != NULL) { - APR_BUCKET_INSERT_BEFORE(eos, e); - } - else { - APR_BRIGADE_INSERT_TAIL(b, e); - } - } - - /* RFC 2616, Section 3.6.1 - * - * If there is an EOS bucket, then prefix it with: - * 1) the last-chunk marker ("0" CRLF) - * 2) the trailer - * 3) the end-of-chunked body CRLF - * - * If there is no EOS bucket, then do nothing. - * - * XXX: it would be nice to combine this with the end-of-chunk - * marker above, but this is a bit more straight-forward for - * now. - */ - if (eos != NULL) { - /* XXX: (2) trailers ... does not yet exist */ - e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF /* <trailers> */ ASCII_CRLF, 5); - APR_BUCKET_INSERT_BEFORE(eos, e); - } - - /* pass the brigade to the next filter. */ - rv = ap_pass_brigade(f->next, b); - if (rv != APR_SUCCESS || eos != NULL) { - return rv; - } - } - - return APR_SUCCESS; -} - -static const char *http_method(const request_rec *r) - { return "http"; } - -static unsigned short http_port(const request_rec *r) - { return DEFAULT_HTTP_PORT; } - -static int ap_pre_http_connection(conn_rec *c) -{ - ap_add_input_filter("HTTP_IN", NULL, NULL, c); - ap_add_input_filter("CORE_IN", NULL, NULL, c); - ap_add_output_filter("CORE", NULL, NULL, c); - return OK; -} - -static int ap_process_http_connection(conn_rec *c) -{ - request_rec *r; - - /* - * Read and process each request found on our connection - * until no requests are left or we decide to close. - */ - - ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_READ, NULL); - while ((r = ap_read_request(c)) != NULL) { - - /* process the request if it was read without error */ - - ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_WRITE, NULL); - if (r->status == HTTP_OK) - ap_process_request(r); - - if (ap_extended_status) - ap_increment_counts(AP_CHILD_THREAD_FROM_ID(c->id), r); - - if (!c->keepalive || c->aborted) - break; - - ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_KEEPALIVE, NULL); - apr_pool_destroy(r->pool); - - if (ap_graceful_stop_signalled()) - break; - } - - return OK; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_pre_connection(ap_pre_http_connection,NULL,NULL, - APR_HOOK_REALLY_LAST); - ap_hook_process_connection(ap_process_http_connection,NULL,NULL, - APR_HOOK_REALLY_LAST); - ap_hook_http_method(http_method,NULL,NULL,APR_HOOK_REALLY_LAST); - ap_hook_default_port(http_port,NULL,NULL,APR_HOOK_REALLY_LAST); - - ap_register_input_filter("HTTP_IN", ap_http_filter, AP_FTYPE_CONNECTION); - ap_register_input_filter("DECHUNK", ap_dechunk_filter, AP_FTYPE_TRANSCODE); - ap_register_output_filter("HTTP_HEADER", ap_http_header_filter, - AP_FTYPE_HTTP_HEADER); - ap_register_output_filter("CHUNK", chunk_filter, AP_FTYPE_TRANSCODE); - ap_register_output_filter("BYTERANGE", ap_byterange_filter, - AP_FTYPE_HTTP_HEADER); -} - -AP_DECLARE_DATA module http_module = { - STANDARD20_MODULE_STUFF, - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - http_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c deleted file mode 100644 index a4426466be..0000000000 --- a/modules/http/http_protocol.c +++ /dev/null @@ -1,2439 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_protocol.c --- routines which directly communicate with the client. - * - * Code originally by Rob McCool; much redone by Robert S. Thau - * and the Apache Software Foundation. - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_buckets.h" -#include "apr_lib.h" -#include "apr_signal.h" - -#define APR_WANT_STDIO /* for sscanf */ -#define APR_WANT_STRFUNC -#define APR_WANT_MEMFUNC -#include "apr_want.h" - -#define CORE_PRIVATE -#include "util_filter.h" -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_main.h" -#include "http_request.h" -#include "http_vhost.h" -#include "http_log.h" /* For errors detected in basic auth common - * support code... */ -#include "util_date.h" /* For parseHTTPdate and BAD_DATE */ -#include "util_charset.h" -#include "util_ebcdic.h" - -#include "mod_core.h" - -#if APR_HAVE_STDARG_H -#include <stdarg.h> -#endif -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif - - -AP_DECLARE(int) ap_set_keepalive(request_rec *r) -{ - int ka_sent = 0; - int wimpy = ap_find_token(r->pool, - apr_table_get(r->headers_out, "Connection"), "close"); - const char *conn = apr_table_get(r->headers_in, "Connection"); - - /* The following convoluted conditional determines whether or not - * the current connection should remain persistent after this response - * (a.k.a. HTTP Keep-Alive) and whether or not the output message - * body should use the HTTP/1.1 chunked transfer-coding. In English, - * - * IF we have not marked this connection as errored; - * and the response body has a defined length due to the status code - * being 304 or 204, the request method being HEAD, already - * having defined Content-Length or Transfer-Encoding: chunked, or - * the request version being HTTP/1.1 and thus capable of being set - * as chunked [we know the (r->chunked = 1) side-effect is ugly]; - * and the server configuration enables keep-alive; - * and the server configuration has a reasonable inter-request timeout; - * and there is no maximum # requests or the max hasn't been reached; - * and the response status does not require a close; - * and the response generator has not already indicated close; - * and the client did not request non-persistence (Connection: close); - * and we haven't been configured to ignore the buggy twit - * or they're a buggy twit coming through a HTTP/1.1 proxy - * and the client is requesting an HTTP/1.0-style keep-alive - * or the client claims to be HTTP/1.1 compliant (perhaps a proxy); - * THEN we can be persistent, which requires more headers be output. - * - * Note that the condition evaluation order is extremely important. - */ - if ((r->connection->keepalive != -1) - && ((r->status == HTTP_NOT_MODIFIED) - || (r->status == HTTP_NO_CONTENT) - || r->header_only - || apr_table_get(r->headers_out, "Content-Length") - || ap_find_last_token(r->pool, - apr_table_get(r->headers_out, - "Transfer-Encoding"), - "chunked") - || ((r->proto_num >= HTTP_VERSION(1,1)) - && (r->chunked = 1))) /* THIS CODE IS CORRECT, see comment above. */ - && r->server->keep_alive - && (r->server->keep_alive_timeout > 0) - && ((r->server->keep_alive_max == 0) - || (r->server->keep_alive_max > r->connection->keepalives)) - && !ap_status_drops_connection(r->status) - && !wimpy - && !ap_find_token(r->pool, conn, "close") - && (!apr_table_get(r->subprocess_env, "nokeepalive") - || apr_table_get(r->headers_in, "Via")) - && ((ka_sent = ap_find_token(r->pool, conn, "keep-alive")) - || (r->proto_num >= HTTP_VERSION(1,1)))) { - int left = r->server->keep_alive_max - r->connection->keepalives; - - r->connection->keepalive = 1; - r->connection->keepalives++; - - /* If they sent a Keep-Alive token, send one back */ - if (ka_sent) { - if (r->server->keep_alive_max) - apr_table_setn(r->headers_out, "Keep-Alive", - apr_psprintf(r->pool, "timeout=%d, max=%d", - r->server->keep_alive_timeout, left)); - else - apr_table_setn(r->headers_out, "Keep-Alive", - apr_psprintf(r->pool, "timeout=%d", - r->server->keep_alive_timeout)); - apr_table_mergen(r->headers_out, "Connection", "Keep-Alive"); - } - - return 1; - } - - /* Otherwise, we need to indicate that we will be closing this - * connection immediately after the current response. - * - * We only really need to send "close" to HTTP/1.1 clients, but we - * always send it anyway, because a broken proxy may identify itself - * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag - * to a HTTP/1.1 client. Better safe than sorry. - */ - if (!wimpy) - apr_table_mergen(r->headers_out, "Connection", "close"); - - r->connection->keepalive = 0; - - return 0; -} - -AP_DECLARE(int) ap_meets_conditions(request_rec *r) -{ - const char *etag = apr_table_get(r->headers_out, "ETag"); - const char *if_match, *if_modified_since, *if_unmodified, *if_nonematch; - apr_time_t mtime; - - /* Check for conditional requests --- note that we only want to do - * this if we are successful so far and we are not processing a - * subrequest or an ErrorDocument. - * - * The order of the checks is important, since ETag checks are supposed - * to be more accurate than checks relative to the modification time. - * However, not all documents are guaranteed to *have* ETags, and some - * might have Last-Modified values w/o ETags, so this gets a little - * complicated. - */ - - if (!ap_is_HTTP_SUCCESS(r->status) || r->no_local_copy) { - return OK; - } - - /* XXX: we should define a "time unset" constant */ - mtime = (r->mtime != 0) ? r->mtime : apr_time_now(); - - /* If an If-Match request-header field was given - * AND the field value is not "*" (meaning match anything) - * AND if our strong ETag does not match any entity tag in that field, - * respond with a status of 412 (Precondition Failed). - */ - if ((if_match = apr_table_get(r->headers_in, "If-Match")) != NULL) { - if (if_match[0] != '*' - && (etag == NULL || etag[0] == 'W' - || !ap_find_list_item(r->pool, if_match, etag))) { - return HTTP_PRECONDITION_FAILED; - } - } - else { - /* Else if a valid If-Unmodified-Since request-header field was given - * AND the requested resource has been modified since the time - * specified in this field, then the server MUST - * respond with a status of 412 (Precondition Failed). - */ - if_unmodified = apr_table_get(r->headers_in, "If-Unmodified-Since"); - if (if_unmodified != NULL) { - apr_time_t ius = ap_parseHTTPdate(if_unmodified); - - if ((ius != BAD_DATE) && (mtime > ius)) { - return HTTP_PRECONDITION_FAILED; - } - } - } - - /* If an If-None-Match request-header field was given - * AND the field value is "*" (meaning match anything) - * OR our ETag matches any of the entity tags in that field, fail. - * - * If the request method was GET or HEAD, failure means the server - * SHOULD respond with a 304 (Not Modified) response. - * For all other request methods, failure means the server MUST - * respond with a status of 412 (Precondition Failed). - * - * GET or HEAD allow weak etag comparison, all other methods require - * strong comparison. We can only use weak if it's not a range request. - */ - if_nonematch = apr_table_get(r->headers_in, "If-None-Match"); - if (if_nonematch != NULL) { - if (r->method_number == M_GET) { - if (if_nonematch[0] == '*') { - return HTTP_NOT_MODIFIED; - } - if (etag != NULL) { - if (apr_table_get(r->headers_in, "Range")) { - if (etag[0] != 'W' - && ap_find_list_item(r->pool, if_nonematch, etag)) { - return HTTP_NOT_MODIFIED; - } - } - else if (ap_strstr_c(if_nonematch, etag)) { - return HTTP_NOT_MODIFIED; - } - } - } - else if (if_nonematch[0] == '*' - || (etag != NULL - && ap_find_list_item(r->pool, if_nonematch, etag))) { - return HTTP_PRECONDITION_FAILED; - } - } - /* Else if a valid If-Modified-Since request-header field was given - * AND it is a GET or HEAD request - * AND the requested resource has not been modified since the time - * specified in this field, then the server MUST - * respond with a status of 304 (Not Modified). - * A date later than the server's current request time is invalid. - */ - else if ((r->method_number == M_GET) - && ((if_modified_since = - apr_table_get(r->headers_in, - "If-Modified-Since")) != NULL)) { - apr_time_t ims = ap_parseHTTPdate(if_modified_since); - - if ((ims >= mtime) && (ims <= r->request_time)) { - return HTTP_NOT_MODIFIED; - } - } - return OK; -} - -/* Get the method number associated with the given string, assumed to - * contain an HTTP method. Returns M_INVALID if not recognized. - * - * This is the first step toward placing method names in a configurable - * list. Hopefully it (and other routines) can eventually be moved to - * something like a mod_http_methods.c, complete with config stuff. - */ -AP_DECLARE(int) ap_method_number_of(const char *method) -{ - switch (*method) { - case 'H': - if (strcmp(method, "HEAD") == 0) - return M_GET; /* see header_only in request_rec */ - break; - case 'G': - if (strcmp(method, "GET") == 0) - return M_GET; - break; - case 'P': - if (strcmp(method, "POST") == 0) - return M_POST; - if (strcmp(method, "PUT") == 0) - return M_PUT; - if (strcmp(method, "PATCH") == 0) - return M_PATCH; - if (strcmp(method, "PROPFIND") == 0) - return M_PROPFIND; - if (strcmp(method, "PROPPATCH") == 0) - return M_PROPPATCH; - break; - case 'D': - if (strcmp(method, "DELETE") == 0) - return M_DELETE; - break; - case 'C': - if (strcmp(method, "CONNECT") == 0) - return M_CONNECT; - if (strcmp(method, "COPY") == 0) - return M_COPY; - break; - case 'M': - if (strcmp(method, "MKCOL") == 0) - return M_MKCOL; - if (strcmp(method, "MOVE") == 0) - return M_MOVE; - break; - case 'O': - if (strcmp(method, "OPTIONS") == 0) - return M_OPTIONS; - break; - case 'T': - if (strcmp(method, "TRACE") == 0) - return M_TRACE; - break; - case 'L': - if (strcmp(method, "LOCK") == 0) - return M_LOCK; - break; - case 'U': - if (strcmp(method, "UNLOCK") == 0) - return M_UNLOCK; - break; - } - return M_INVALID; -} - -/* - * Turn a known method number into a name. Doesn't work for - * extension methods, obviously. - */ -AP_DECLARE(const char *) ap_method_name_of(int methnum) -{ - static const char *AP_HTTP_METHODS[METHODS] = { NULL }; - - /* - * This is ugly, but the previous incantation made Windows C - * varf. I'm not even sure it was ANSI C. However, ugly as it - * is, this works, and we only have to do it once. - */ - if (AP_HTTP_METHODS[0] == NULL) { - AP_HTTP_METHODS[M_GET] = "GET"; - AP_HTTP_METHODS[M_PUT] = "PUT"; - AP_HTTP_METHODS[M_POST] = "POST"; - AP_HTTP_METHODS[M_DELETE] = "DELETE"; - AP_HTTP_METHODS[M_CONNECT] = "CONNECT"; - AP_HTTP_METHODS[M_OPTIONS] = "OPTIONS"; - AP_HTTP_METHODS[M_TRACE] = "TRACE"; - AP_HTTP_METHODS[M_PATCH] = "PATCH"; - AP_HTTP_METHODS[M_PROPFIND] = "PROPFIND"; - AP_HTTP_METHODS[M_PROPPATCH] = "PROPPATCH"; - AP_HTTP_METHODS[M_MKCOL] = "MKCOL"; - AP_HTTP_METHODS[M_COPY] = "COPY"; - AP_HTTP_METHODS[M_MOVE] = "MOVE"; - AP_HTTP_METHODS[M_LOCK] = "LOCK"; - AP_HTTP_METHODS[M_UNLOCK] = "UNLOCK"; - AP_HTTP_METHODS[M_INVALID] = NULL; - /* - * Since we're using symbolic names, make sure we only do - * this once by forcing a value into the first slot IFF it's - * still NULL. - */ - if (AP_HTTP_METHODS[0] == NULL) { - AP_HTTP_METHODS[0] = "INVALID"; - } - } - - if ((methnum == M_INVALID) || (methnum >= METHODS)) { - return NULL; - } - return AP_HTTP_METHODS[methnum]; -} - -struct dechunk_ctx { - apr_size_t chunk_size; - apr_size_t bytes_delivered; - enum {WANT_HDR /* must have value zero */, WANT_BODY, WANT_TRL} state; -}; - -static long get_chunk_size(char *); - -apr_status_t ap_dechunk_filter(ap_filter_t *f, apr_bucket_brigade *bb, - ap_input_mode_t mode, apr_size_t *readbytes) -{ - apr_status_t rv; - struct dechunk_ctx *ctx = f->ctx; - apr_bucket *b; - const char *buf; - apr_size_t len; - - if (!ctx) { - f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(struct dechunk_ctx)); - } - - do { - if (ctx->chunk_size == ctx->bytes_delivered) { - /* Time to read another chunk header or trailer... ap_http_filter() is - * the next filter in line and it knows how to return a brigade with - * one line. - */ - char line[30]; - - if ((rv = ap_getline(line, sizeof(line), f->r, 0)) < 0) { - return rv; - } - switch(ctx->state) { - case WANT_HDR: - ctx->chunk_size = get_chunk_size(line); - ctx->bytes_delivered = 0; - if (ctx->chunk_size == 0) { - ctx->state = WANT_TRL; - } - else { - ctx->state = WANT_BODY; - } - break; - case WANT_TRL: - /* XXX sanity check end chunk here */ - if (strlen(line)) { - /* bad trailer */ - } - if (ctx->chunk_size == 0) { /* we just finished the last chunk? */ - /* append eos bucket and get out */ - b = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - return APR_SUCCESS; - } - ctx->state = WANT_HDR; - break; - default: - ap_assert(ctx->state == WANT_HDR || ctx->state == WANT_TRL); - } - } - } while (ctx->state != WANT_BODY); - - if (ctx->state == WANT_BODY) { - /* Tell ap_http_filter() how many bytes to deliver. */ - apr_size_t readbytes = ctx->chunk_size - ctx->bytes_delivered; - if ((rv = ap_get_brigade(f->next, bb, mode, &readbytes)) != APR_SUCCESS) { - return rv; - } - /* Walk through the body, accounting for bytes, and removing an eos bucket if - * ap_http_filter() delivered the entire chunk. - */ - b = APR_BRIGADE_FIRST(bb); - while (b != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(b)) { - apr_bucket_read(b, &buf, &len, mode); - AP_DEBUG_ASSERT(len <= ctx->chunk_size - ctx->bytes_delivered); - ctx->bytes_delivered += len; - b = APR_BUCKET_NEXT(b); - } - if (ctx->bytes_delivered == ctx->chunk_size) { - AP_DEBUG_ASSERT(APR_BUCKET_IS_EOS(b)); - apr_bucket_delete(b); - ctx->state = WANT_TRL; - } - } - - return APR_SUCCESS; -} - -typedef struct http_filter_ctx { - apr_bucket_brigade *b; -} http_ctx_t; - -apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_size_t *readbytes) -{ - apr_bucket *e; - char *buff; - apr_size_t len; - char *pos; - http_ctx_t *ctx = f->ctx; - apr_status_t rv; - - if (!ctx) { - f->ctx = ctx = apr_pcalloc(f->c->pool, sizeof(*ctx)); - ctx->b = apr_brigade_create(f->c->pool); - } - - if (mode == AP_MODE_PEEK) { - apr_bucket *e; - const char *str; - apr_size_t length; - - /* The purpose of this loop is to ignore any CRLF (or LF) at the end - * of a request. Many browsers send extra lines at the end of POST - * requests. We use the PEEK method to determine if there is more - * data on the socket, so that we know if we should delay sending the - * end of one request until we have served the second request in a - * pipelined situation. We don't want to actually delay sending a - * response if the server finds a CRLF (or LF), becuause that doesn't - * mean that there is another request, just a blank line. - */ - while (1) { - if (APR_BRIGADE_EMPTY(ctx->b)) { - e = NULL; - } - else { - e = APR_BRIGADE_FIRST(ctx->b); - } - if (!e || apr_bucket_read(e, &str, &length, APR_NONBLOCK_READ) != APR_SUCCESS) { - return APR_EOF; - } - else { - const char *c = str; - while (c - str < length) { - if (*c == APR_ASCII_LF) - c++; - else if (*c == APR_ASCII_CR && *(c + 1) == APR_ASCII_LF) - c += 2; - else return APR_SUCCESS; - } - apr_bucket_delete(e); - } - } - } - - if (APR_BRIGADE_EMPTY(ctx->b)) { - if ((rv = ap_get_brigade(f->next, ctx->b, mode, readbytes)) != APR_SUCCESS) { - return rv; - } - } - - if (*readbytes) { - while (!APR_BRIGADE_EMPTY(ctx->b)) { - const char *ignore; - - e = APR_BRIGADE_FIRST(ctx->b); - if ((rv = apr_bucket_read(e, &ignore, &len, mode)) != APR_SUCCESS) { - /* probably APR_IS_EAGAIN(rv); socket state isn't correct; - * remove log once we get this squared away */ - ap_log_error(APLOG_MARK, APLOG_ERR, rv, f->c->base_server, - "apr_bucket_read"); - return rv; - } - - if (len) { - /* note: this can sometimes insert empty buckets into the - * brigade, or the data might come in a few characters at - * a time - don't assume that one call to apr_bucket_read() - * will return the full string. - */ - if (*readbytes < len) { - apr_bucket_split(e, *readbytes); - *readbytes = 0; - } - else { - *readbytes -= len; - } - APR_BUCKET_REMOVE(e); - APR_BRIGADE_INSERT_TAIL(b, e); - break; /* once we've gotten some data, deliver it to caller */ - } - apr_bucket_delete(e); - } - if (*readbytes == 0) { - apr_bucket *eos = apr_bucket_eos_create(); - - APR_BRIGADE_INSERT_TAIL(b, eos); - } - return APR_SUCCESS; - } - - while (!APR_BRIGADE_EMPTY(ctx->b)) { - e = APR_BRIGADE_FIRST(ctx->b); - if ((rv = apr_bucket_read(e, (const char **)&buff, &len, mode)) != APR_SUCCESS) { - return rv; - } - - pos = memchr(buff, APR_ASCII_LF, len); - if (pos != NULL) { - apr_bucket_split(e, pos - buff + 1); - APR_BUCKET_REMOVE(e); - APR_BRIGADE_INSERT_TAIL(b, e); - return APR_SUCCESS; - } - APR_BUCKET_REMOVE(e); - APR_BRIGADE_INSERT_TAIL(b, e); - } - return APR_SUCCESS; -} - -/* New Apache routine to map status codes into array indicies - * e.g. 100 -> 0, 101 -> 1, 200 -> 2 ... - * The number of status lines must equal the value of RESPONSE_CODES (httpd.h) - * and must be listed in order. - */ - -#ifdef UTS21 -/* The second const triggers an assembler bug on UTS 2.1. - * Another workaround is to move some code out of this file into another, - * but this is easier. Dave Dykstra, 3/31/99 - */ -static const char * status_lines[RESPONSE_CODES] = -#else -static const char * const status_lines[RESPONSE_CODES] = -#endif -{ - "100 Continue", - "101 Switching Protocols", - "102 Processing", -#define LEVEL_200 3 - "200 OK", - "201 Created", - "202 Accepted", - "203 Non-Authoritative Information", - "204 No Content", - "205 Reset Content", - "206 Partial Content", - "207 Multi-Status", -#define LEVEL_300 11 - "300 Multiple Choices", - "301 Moved Permanently", - "302 Found", - "303 See Other", - "304 Not Modified", - "305 Use Proxy", - "306 unused", - "307 Temporary Redirect", -#define LEVEL_400 19 - "400 Bad Request", - "401 Authorization Required", - "402 Payment Required", - "403 Forbidden", - "404 Not Found", - "405 Method Not Allowed", - "406 Not Acceptable", - "407 Proxy Authentication Required", - "408 Request Time-out", - "409 Conflict", - "410 Gone", - "411 Length Required", - "412 Precondition Failed", - "413 Request Entity Too Large", - "414 Request-URI Too Large", - "415 Unsupported Media Type", - "416 Requested Range Not Satisfiable", - "417 Expectation Failed", - "418 unused", - "419 unused", - "420 unused", - "421 unused", - "422 Unprocessable Entity", - "423 Locked", - "424 Failed Dependency", -#define LEVEL_500 44 - "500 Internal Server Error", - "501 Method Not Implemented", - "502 Bad Gateway", - "503 Service Temporarily Unavailable", - "504 Gateway Time-out", - "505 HTTP Version Not Supported", - "506 Variant Also Negotiates", - "507 Insufficient Storage", - "508 unused", - "509 unused", - "510 Not Extended" -}; - -/* The index is found by its offset from the x00 code of each level. - * Although this is fast, it will need to be replaced if some nutcase - * decides to define a high-numbered code before the lower numbers. - * If that sad event occurs, replace the code below with a linear search - * from status_lines[shortcut[i]] to status_lines[shortcut[i+1]-1]; - */ -AP_DECLARE(int) ap_index_of_response(int status) -{ - static int shortcut[6] = {0, LEVEL_200, LEVEL_300, LEVEL_400, - LEVEL_500, RESPONSE_CODES}; - int i, pos; - - if (status < 100) /* Below 100 is illegal for HTTP status */ - return LEVEL_500; - - for (i = 0; i < 5; i++) { - status -= 100; - if (status < 100) { - pos = (status + shortcut[i]); - if (pos < shortcut[i + 1]) { - return pos; - } - else { - return LEVEL_500; /* status unknown (falls in gap) */ - } - } - } - return LEVEL_500; /* 600 or above is also illegal */ -} - -AP_DECLARE(const char *) ap_get_status_line(int status) -{ - return status_lines[ap_index_of_response(status)]; -} - -typedef struct header_struct { - apr_pool_t *pool; - apr_bucket_brigade *bb; -} header_struct; - -/* Send a single HTTP header field to the client. Note that this function - * is used in calls to table_do(), so their interfaces are co-dependent. - * In other words, don't change this one without checking table_do in alloc.c. - * It returns true unless there was a write error of some kind. - */ -static int form_header_field(header_struct *h, - const char *fieldname, const char *fieldval) -{ - char *headfield; - - headfield = apr_pstrcat(h->pool, fieldname, ": ", fieldval, CRLF, NULL); - ap_xlate_proto_to_ascii(headfield, strlen(headfield)); - apr_brigade_puts(h->bb, NULL, NULL, headfield); - return 1; -} - -/* - * Determine the protocol to use for the response. Potentially downgrade - * to HTTP/1.0 in some situations and/or turn off keepalives. - * - * also prepare r->status_line. - */ -static void basic_http_header_check(request_rec *r, - const char **protocol) -{ - if (r->assbackwards) { - /* no such thing as a response protocol */ - return; - } - - if (!r->status_line) - r->status_line = status_lines[ap_index_of_response(r->status)]; - - /* kluge around broken browsers when indicated by force-response-1.0 - */ - if (r->proto_num == HTTP_VERSION(1,0) - && apr_table_get(r->subprocess_env, "force-response-1.0")) { - - *protocol = "HTTP/1.0"; - r->connection->keepalive = -1; - } - else { - *protocol = AP_SERVER_PROTOCOL; - } -} - -/* fill "bb" with a barebones/initial HTTP response header */ -static void basic_http_header(request_rec *r, apr_bucket_brigade *bb, - const char *protocol) -{ - char *date = NULL; - char *tmp; - header_struct h; - - if (r->assbackwards) { - /* there are no headers to send */ - return; - } - - /* Output the HTTP/1.x Status-Line and the Date and Server fields */ - - tmp = apr_pstrcat(r->pool, protocol, " ", r->status_line, CRLF, NULL); - ap_xlate_proto_to_ascii(tmp, strlen(tmp)); - apr_brigade_puts(bb, NULL, NULL, tmp); - - date = apr_palloc(r->pool, APR_RFC822_DATE_LEN); - apr_rfc822_date(date, r->request_time); - - h.pool = r->pool; - h.bb = bb; - form_header_field(&h, "Date", date); - form_header_field(&h, "Server", ap_get_server_version()); - - apr_table_unset(r->headers_out, "Date"); /* Avoid bogosity */ - apr_table_unset(r->headers_out, "Server"); -} - -AP_DECLARE(void) ap_basic_http_header(request_rec *r, apr_bucket_brigade *bb) -{ - const char *protocol; - - basic_http_header_check(r, &protocol); - basic_http_header(r, bb, protocol); -} - -/* Navigator versions 2.x, 3.x and 4.0 betas up to and including 4.0b2 - * have a header parsing bug. If the terminating \r\n occur starting - * at offset 256, 257 or 258 of output then it will not properly parse - * the headers. Curiously it doesn't exhibit this problem at 512, 513. - * We are guessing that this is because their initial read of a new request - * uses a 256 byte buffer, and subsequent reads use a larger buffer. - * So the problem might exist at different offsets as well. - * - * This should also work on keepalive connections assuming they use the - * same small buffer for the first read of each new request. - * - * At any rate, we check the bytes written so far and, if we are about to - * tickle the bug, we instead insert a bogus padding header. Since the bug - * manifests as a broken image in Navigator, users blame the server. :( - * It is more expensive to check the User-Agent than it is to just add the - * bytes, so we haven't used the BrowserMatch feature here. - */ -static void terminate_header(apr_bucket_brigade *bb) -{ - char tmp[] = "X-Pad: avoid browser bug" CRLF; - char crlf[] = CRLF; - apr_ssize_t len; - - (void) apr_brigade_length(bb, 1, &len); - - if (len >= 255 && len <= 257) { - ap_xlate_proto_to_ascii(tmp, strlen(tmp)); - apr_brigade_puts(bb, NULL, NULL, tmp); - } - ap_xlate_proto_to_ascii(crlf, strlen(crlf)); - apr_brigade_puts(bb, NULL, NULL, crlf); -} - -/* Build the Allow field-value from the request handler method mask. - * Note that we always allow TRACE, since it is handled below. - */ -static char *make_allow(request_rec *r) -{ - char *list; - int mask; - - mask = r->allowed_methods->method_mask; - list = apr_pstrcat(r->pool, - (mask & (1 << M_GET)) ? ", GET, HEAD" : "", - (mask & (1 << M_POST)) ? ", POST" : "", - (mask & (1 << M_PUT)) ? ", PUT" : "", - (mask & (1 << M_DELETE)) ? ", DELETE" : "", - (mask & (1 << M_CONNECT)) ? ", CONNECT" : "", - (mask & (1 << M_OPTIONS)) ? ", OPTIONS" : "", - (mask & (1 << M_PATCH)) ? ", PATCH" : "", - (mask & (1 << M_PROPFIND)) ? ", PROPFIND" : "", - (mask & (1 << M_PROPPATCH)) ? ", PROPPATCH" : "", - (mask & (1 << M_MKCOL)) ? ", MKCOL" : "", - (mask & (1 << M_COPY)) ? ", COPY" : "", - (mask & (1 << M_MOVE)) ? ", MOVE" : "", - (mask & (1 << M_LOCK)) ? ", LOCK" : "", - (mask & (1 << M_UNLOCK)) ? ", UNLOCK" : "", - ", TRACE", - NULL); - if ((mask & (1 << M_INVALID)) - && (r->allowed_methods->method_list != NULL) - && (r->allowed_methods->method_list->nelts != 0)) { - int i; - char **xmethod = (char **) r->allowed_methods->method_list->elts; - - /* - * Append all of the elements of r->allowed_methods->method_list - */ - for (i = 0; i < r->allowed_methods->method_list->nelts; ++i) { - list = apr_pstrcat(r->pool, list, ", ", xmethod[i], NULL); - } - } - /* - * Space past the leading ", ". Wastes two bytes, but that's better - * than futzing around to find the actual length. - */ - return list + 2; -} - -AP_DECLARE(int) ap_send_http_trace(request_rec *r) -{ - int rv; - - /* Get the original request */ - while (r->prev) - r = r->prev; - - if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY))) - return rv; - - r->content_type = "message/http"; - - /* Now we recreate the request, and echo it back */ - - ap_rvputs(r, r->the_request, CRLF, NULL); - - apr_table_do((int (*) (void *, const char *, const char *)) - form_header_field, (void *) r, r->headers_in, NULL); - ap_rputs(CRLF, r); - - return OK; -} - -int ap_send_http_options(request_rec *r) -{ - if (r->assbackwards) - return DECLINED; - - apr_table_setn(r->headers_out, "Allow", make_allow(r)); - - /* the request finalization will send an EOS, which will flush all - the headers out (including the Allow header) */ - - return OK; -} - -/* This routine is called by apr_table_do and merges all instances of - * the passed field values into a single array that will be further - * processed by some later routine. Originally intended to help split - * and recombine multiple Vary fields, though it is generic to any field - * consisting of comma/space-separated tokens. - */ -static int uniq_field_values(void *d, const char *key, const char *val) -{ - apr_array_header_t *values; - char *start; - char *e; - char **strpp; - int i; - - values = (apr_array_header_t *)d; - - e = apr_pstrdup(values->cont, val); - - do { - /* Find a non-empty fieldname */ - - while (*e == ',' || apr_isspace(*e)) { - ++e; - } - if (*e == '\0') { - break; - } - start = e; - while (*e != '\0' && *e != ',' && !apr_isspace(*e)) { - ++e; - } - if (*e != '\0') { - *e++ = '\0'; - } - - /* Now add it to values if it isn't already represented. - * Could be replaced by a ap_array_strcasecmp() if we had one. - */ - for (i = 0, strpp = (char **) values->elts; i < values->nelts; - ++i, ++strpp) { - if (*strpp && strcasecmp(*strpp, start) == 0) { - break; - } - } - if (i == values->nelts) { /* if not found */ - *(char **)apr_array_push(values) = start; - } - } while (*e != '\0'); - - return 1; -} - -/* - * Since some clients choke violently on multiple Vary fields, or - * Vary fields with duplicate tokens, combine any multiples and remove - * any duplicates. - */ -static void fixup_vary(request_rec *r) -{ - apr_array_header_t *varies; - - varies = apr_array_make(r->pool, 5, sizeof(char *)); - - /* Extract all Vary fields from the headers_out, separate each into - * its comma-separated fieldname values, and then add them to varies - * if not already present in the array. - */ - apr_table_do((int (*)(void *, const char *, const char *))uniq_field_values, - (void *) varies, r->headers_out, "Vary", NULL); - - /* If we found any, replace old Vary fields with unique-ified value */ - - if (varies->nelts > 0) { - apr_table_setn(r->headers_out, "Vary", - apr_array_pstrcat(r->pool, varies, ',')); - } -} - -AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter( - ap_filter_t *f, - apr_bucket_brigade *b) -{ - int i; - char *date = NULL; - request_rec *r = f->r; - const char *clheader; - const char *protocol; - apr_bucket *e; - apr_bucket_brigade *b2; - header_struct h; - - AP_DEBUG_ASSERT(!r->main); - - APR_BRIGADE_FOREACH(e, b) { - if (e->type == &ap_bucket_type_error) { - ap_bucket_error *eb = e->data; - - ap_die(eb->status, r); - return AP_FILTER_ERROR; - } - } - - if (r->assbackwards) { - r->bytes_sent = 0; - r->sent_bodyct = 1; - ap_remove_output_filter(f); - return ap_pass_brigade(f->next, b); - } - - /* - * Now that we are ready to send a response, we need to combine the two - * header field tables into a single table. If we don't do this, our - * later attempts to set or unset a given fieldname might be bypassed. - */ - if (!apr_is_empty_table(r->err_headers_out)) - r->headers_out = apr_table_overlay(r->pool, r->err_headers_out, - r->headers_out); - - /* - * Remove the 'Vary' header field if the client can't handle it. - * Since this will have nasty effects on HTTP/1.1 caches, force - * the response into HTTP/1.0 mode. - * - * Note: the force-response-1.0 should come before the call to - * basic_http_header_check() - */ - if (apr_table_get(r->subprocess_env, "force-no-vary") != NULL) { - apr_table_unset(r->headers_out, "Vary"); - r->proto_num = HTTP_VERSION(1,0); - apr_table_set(r->subprocess_env, "force-response-1.0", "1"); - } - else { - fixup_vary(r); - } - - /* determine the protocol and whether we should use keepalives. */ - basic_http_header_check(r, &protocol); - ap_set_keepalive(r); - - if (r->chunked) { - apr_table_mergen(r->headers_out, "Transfer-Encoding", "chunked"); - apr_table_unset(r->headers_out, "Content-Length"); - - } - - apr_table_setn(r->headers_out, "Content-Type", ap_make_content_type(r, - r->content_type)); - - if (r->content_encoding) { - apr_table_setn(r->headers_out, "Content-Encoding", - r->content_encoding); - } - - if (r->content_languages && r->content_languages->nelts) { - for (i = 0; i < r->content_languages->nelts; ++i) { - apr_table_mergen(r->headers_out, "Content-Language", - ((char **) (r->content_languages->elts))[i]); - } - } - else if (r->content_language) { - apr_table_setn(r->headers_out, "Content-Language", - r->content_language); - } - - /* - * Control cachability for non-cachable responses if not already set by - * some other part of the server configuration. - */ - if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) { - date = apr_palloc(r->pool, APR_RFC822_DATE_LEN); - apr_rfc822_date(date, r->request_time); - apr_table_addn(r->headers_out, "Expires", date); - } - - /* This is a hack, but I can't find anyway around it. The idea is that - * we don't want to send out 0 Content-Lengths if it is a head request. - * This happens when modules try to outsmart the server, and return - * if they see a HEAD request. Apache 1.3 handlers were supposed to - * just return in that situation, and the core handled the HEAD. In - * 2.0, if a handler returns, then the core sends an EOS bucket down - * the filter stack, and the content-length filter computes a C-L of - * zero and that gets put in the headers, and we end up sending a - * zero C-L to the client. We can't just remove the C-L filter, - * because well behaved 2.0 handlers will send their data down the stack, - * and we will compute a real C-L for the head request. RBB - */ - if (r->header_only && - (clheader = apr_table_get(r->headers_out, "Content-Length")) && - !strcmp(clheader, "0")) { - apr_table_unset(r->headers_out, "Content-Length"); - } - - b2 = apr_brigade_create(r->pool); - basic_http_header(r, b2, protocol); - - h.pool = r->pool; - h.bb = b2; - - if (r->status == HTTP_NOT_MODIFIED) { - apr_table_do((int (*)(void *, const char *, const char *)) form_header_field, - (void *) &h, r->headers_out, - "Connection", - "Keep-Alive", - "ETag", - "Content-Location", - "Expires", - "Cache-Control", - "Vary", - "Warning", - "WWW-Authenticate", - "Proxy-Authenticate", - NULL); - } - else { - apr_table_do((int (*) (void *, const char *, const char *)) form_header_field, - (void *) &h, r->headers_out, NULL); - } - - terminate_header(b2); - - r->sent_bodyct = 1; /* Whatever follows is real body stuff... */ - - ap_pass_brigade(f->next, b2); - - if (r->header_only) { - apr_brigade_destroy(b); - return OK; - } - - if (r->chunked) { - /* We can't add this filter until we have already sent the headers. - * If we add it before this point, then the headers will be chunked - * as well, and that is just wrong. - */ - ap_add_output_filter("CHUNK", NULL, r, r->connection); - } - - /* Don't remove this filter until after we have added the CHUNK filter. - * Otherwise, f->next won't be the CHUNK filter and thus the first - * brigade won't be chunked properly. - */ - ap_remove_output_filter(f); - return ap_pass_brigade(f->next, b); -} - -/* Here we deal with getting the request message body from the client. - * Whether or not the request contains a body is signaled by the presence - * of a non-zero Content-Length or by a Transfer-Encoding: chunked. - * - * Note that this is more complicated than it was in Apache 1.1 and prior - * versions, because chunked support means that the module does less. - * - * The proper procedure is this: - * - * 1. Call setup_client_block() near the beginning of the request - * handler. This will set up all the necessary properties, and will - * return either OK, or an error code. If the latter, the module should - * return that error code. The second parameter selects the policy to - * apply if the request message indicates a body, and how a chunked - * transfer-coding should be interpreted. Choose one of - * - * REQUEST_NO_BODY Send 413 error if message has any body - * REQUEST_CHUNKED_ERROR Send 411 error if body without Content-Length - * REQUEST_CHUNKED_DECHUNK If chunked, remove the chunks for me. - * - * In order to use the last two options, the caller MUST provide a buffer - * large enough to hold a chunk-size line, including any extensions. - * - * 2. When you are ready to read a body (if any), call should_client_block(). - * This will tell the module whether or not to read input. If it is 0, - * the module should assume that there is no message body to read. - * This step also sends a 100 Continue response to HTTP/1.1 clients, - * so should not be called until the module is *definitely* ready to - * read content. (otherwise, the point of the 100 response is defeated). - * Never call this function more than once. - * - * 3. Finally, call get_client_block in a loop. Pass it a buffer and its size. - * It will put data into the buffer (not necessarily a full buffer), and - * return the length of the input block. When it is done reading, it will - * return 0 if EOF, or -1 if there was an error. - * If an error occurs on input, we force an end to keepalive. - */ - -AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) -{ - const char *tenc = apr_table_get(r->headers_in, "Transfer-Encoding"); - const char *lenp = apr_table_get(r->headers_in, "Content-Length"); - long max_body; - - r->read_body = read_policy; - r->read_chunked = 0; - r->remaining = 0; - - if (tenc) { - if (strcasecmp(tenc, "chunked")) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Unknown Transfer-Encoding %s", tenc); - return HTTP_NOT_IMPLEMENTED; - } - if (r->read_body == REQUEST_CHUNKED_ERROR) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "chunked Transfer-Encoding forbidden: %s", r->uri); - return (lenp) ? HTTP_BAD_REQUEST : HTTP_LENGTH_REQUIRED; - } - - r->read_chunked = 1; - ap_add_input_filter("DECHUNK", NULL, r, r->connection); - } - else if (lenp) { - const char *pos = lenp; - - while (apr_isdigit(*pos) || apr_isspace(*pos)) { - ++pos; - } - if (*pos != '\0') { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid Content-Length %s", lenp); - return HTTP_BAD_REQUEST; - } - - r->remaining = atol(lenp); - } - - if ((r->read_body == REQUEST_NO_BODY) && - (r->read_chunked || (r->remaining > 0))) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "%s with body is not allowed for %s", r->method, r->uri); - return HTTP_REQUEST_ENTITY_TOO_LARGE; - } - - max_body = ap_get_limit_req_body(r); - if (max_body && (r->remaining > max_body)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Request content-length of %s is larger than " - "the configured limit of %lu", lenp, max_body); - return HTTP_REQUEST_ENTITY_TOO_LARGE; - } - -#ifdef AP_DEBUG - { - /* Make sure ap_getline() didn't leave any droppings. */ - core_request_config *req_cfg = - (core_request_config *)ap_get_module_config(r->request_config, - &core_module); - AP_DEBUG_ASSERT(APR_BRIGADE_EMPTY(req_cfg->bb)); - } -#endif - - return OK; -} - -AP_DECLARE(int) ap_should_client_block(request_rec *r) -{ - /* First check if we have already read the request body */ - - if (r->read_length || (!r->read_chunked && (r->remaining <= 0))) - return 0; - - if (r->expecting_100 && r->proto_num >= HTTP_VERSION(1,1)) { - char *tmp; - apr_bucket *e; - apr_bucket_brigade *bb; - - /* sending 100 Continue interim response */ - tmp = apr_pstrcat(r->pool, AP_SERVER_PROTOCOL, " ", status_lines[0], - CRLF CRLF, NULL); - bb = apr_brigade_create(r->pool); - e = apr_bucket_pool_create(tmp, strlen(tmp), r->pool); - APR_BRIGADE_INSERT_HEAD(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - - ap_pass_brigade(r->connection->output_filters, bb); - } - - return 1; -} - -static long get_chunk_size(char *b) -{ - long chunksize = 0; - - while (apr_isxdigit(*b)) { - int xvalue = 0; - - if (*b >= '0' && *b <= '9') { - xvalue = *b - '0'; - } - else if (*b >= 'A' && *b <= 'F') { - xvalue = *b - 'A' + 0xa; - } - else if (*b >= 'a' && *b <= 'f') { - xvalue = *b - 'a' + 0xa; - } - - chunksize = (chunksize << 4) | xvalue; - ++b; - } - - return chunksize; -} - -/* get_client_block is called in a loop to get the request message body. - * This is quite simple if the client includes a content-length - * (the normal case), but gets messy if the body is chunked. Note that - * r->remaining is used to maintain state across calls and that - * r->read_length is the total number of bytes given to the caller - * across all invocations. It is messy because we have to be careful not - * to read past the data provided by the client, since these reads block. - * Returns 0 on End-of-body, -1 on error or premature chunk end. - * - * Reading the chunked encoding requires a buffer size large enough to - * hold a chunk-size line, including any extensions. For now, we'll leave - * that to the caller, at least until we can come up with a better solution. - */ -AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz) -{ - apr_size_t len_read, total; - apr_status_t rv; - apr_bucket *b, *old; - const char *tempbuf; - core_request_config *req_cfg = - (core_request_config *)ap_get_module_config(r->request_config, - &core_module); - apr_bucket_brigade *bb = req_cfg->bb; - - do { - if (APR_BRIGADE_EMPTY(bb)) { - if (ap_get_brigade(r->input_filters, bb, AP_MODE_BLOCKING, &r->remaining) != APR_SUCCESS) { - /* if we actually fail here, we want to just return and - * stop trying to read data from the client. - */ - r->connection->keepalive = -1; - apr_brigade_destroy(bb); - return -1; - } - } - b = APR_BRIGADE_FIRST(bb); - } while (APR_BRIGADE_EMPTY(bb)); - - if (APR_BUCKET_IS_EOS(b)) { /* reached eos on previous invocation */ - apr_bucket_delete(b); - return 0; - } - - total = 0; - while (total < bufsiz && b != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(b)) { - if ((rv = apr_bucket_read(b, &tempbuf, &len_read, APR_BLOCK_READ)) != APR_SUCCESS) { - return -1; - } - if (total + len_read > bufsiz) { - apr_bucket_split(b, bufsiz - total); - len_read = bufsiz - total; - } - memcpy(buffer, tempbuf, len_read); - buffer += len_read; - total += len_read; - /* XXX the next two fields shouldn't be mucked with here, as they are in terms - * of bytes in the unfiltered body; gotta see if anybody else actually uses - * these - */ - r->read_length += len_read; /* XXX yank me? */ - r->remaining -= len_read; /* XXX yank me? */ - old = b; - b = APR_BUCKET_NEXT(b); - apr_bucket_delete(old); - } - - return total; -} - -/* In HTTP/1.1, any method can have a body. However, most GET handlers - * wouldn't know what to do with a request body if they received one. - * This helper routine tests for and reads any message body in the request, - * simply discarding whatever it receives. We need to do this because - * failing to read the request body would cause it to be interpreted - * as the next request on a persistent connection. - * - * Since we return an error status if the request is malformed, this - * routine should be called at the beginning of a no-body handler, e.g., - * - * if ((retval = ap_discard_request_body(r)) != OK) - * return retval; - */ -AP_DECLARE(int) ap_discard_request_body(request_rec *r) -{ - int rv; - - if (r->read_length == 0) { /* if not read already */ - if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) - return rv; - } - - /* In order to avoid sending 100 Continue when we already know the - * final response status, and yet not kill the connection if there is - * no request body to be read, we need to duplicate the test from - * ap_should_client_block() here negated rather than call it directly. - */ - if ((r->read_length == 0) && (r->read_chunked || (r->remaining > 0))) { - char dumpbuf[HUGE_STRING_LEN]; - - if (r->expecting_100) { - r->connection->keepalive = -1; - return OK; - } - - while ((rv = ap_get_client_block(r, dumpbuf, HUGE_STRING_LEN)) > 0) - continue; - - if (rv < 0) - return HTTP_BAD_REQUEST; - } - return OK; -} - -static const char *add_optional_notes(request_rec *r, - const char *prefix, - const char *key, - const char *suffix) -{ - const char *notes, *result; - - if ((notes = apr_table_get(r->notes, key)) == NULL) { - result = prefix; - } - else { - result = apr_pstrcat(r->pool, prefix, notes, suffix, NULL); - } - - return result; -} - -static const char *get_canned_error_string(int status, - request_rec *r, - const char *location) - -/* construct and return the default error message for a given - * HTTP defined error code - */ -{ - apr_pool_t *p = r->pool; - const char *error_notes, *h1, *s1; - - switch (status) { - case HTTP_MOVED_PERMANENTLY: - case HTTP_MOVED_TEMPORARILY: - case HTTP_TEMPORARY_REDIRECT: - return(apr_pstrcat(p, - "The document has moved <A HREF=\"", - ap_escape_html(r->pool, location), - "\">here</A>.<P>\n", - NULL)); - case HTTP_SEE_OTHER: - return(apr_pstrcat(p, - "The answer to your request is located <A HREF=\"", - ap_escape_html(r->pool, location), - "\">here</A>.<P>\n", - NULL)); - case HTTP_USE_PROXY: - return(apr_pstrcat(p, - "This resource is only accessible " - "through the proxy\n", - ap_escape_html(r->pool, location), - "<BR>\nYou will need to " - "configure your client to use that proxy.<P>\n", - NULL)); - case HTTP_PROXY_AUTHENTICATION_REQUIRED: - case HTTP_UNAUTHORIZED: - return("This server could not verify that you\n" - "are authorized to access the document\n" - "requested. Either you supplied the wrong\n" - "credentials (e.g., bad password), or your\n" - "browser doesn't understand how to supply\n" - "the credentials required.<P>\n"); - case HTTP_BAD_REQUEST: - return(add_optional_notes(r, - "Your browser sent a request that " - "this server could not understand.<P>\n", - "error-notes", - "<P>\n")); - case HTTP_FORBIDDEN: - return(apr_pstrcat(p, - "You don't have permission to access ", - ap_escape_html(r->pool, r->uri), - "\non this server.<P>\n", - NULL)); - case HTTP_NOT_FOUND: - return(apr_pstrcat(p, - "The requested URL ", - ap_escape_html(r->pool, r->uri), - " was not found on this server.<P>\n", - NULL)); - case HTTP_METHOD_NOT_ALLOWED: - return(apr_pstrcat(p, - "The requested method ", r->method, - " is not allowed for the URL ", - ap_escape_html(r->pool, r->uri), - ".<P>\n", - NULL)); - case HTTP_NOT_ACCEPTABLE: - s1 = apr_pstrcat(p, - "An appropriate representation of the " - "requested resource ", - ap_escape_html(r->pool, r->uri), - " could not be found on this server.<P>\n", - NULL); - return(add_optional_notes(r, s1, "variant-list", "")); - case HTTP_MULTIPLE_CHOICES: - return(add_optional_notes(r, "", "variant-list", "")); - case HTTP_LENGTH_REQUIRED: - s1 = apr_pstrcat(p, - "A request of the requested method ", - r->method, - " requires a valid Content-length.<P>\n", - NULL); - return(add_optional_notes(r, s1, "error-notes", "<P>\n")); - case HTTP_PRECONDITION_FAILED: - return(apr_pstrcat(p, - "The precondition on the request for the URL ", - ap_escape_html(r->pool, r->uri), - " evaluated to false.<P>\n", - NULL)); - case HTTP_NOT_IMPLEMENTED: - s1 = apr_pstrcat(p, - ap_escape_html(r->pool, r->method), " to ", - ap_escape_html(r->pool, r->uri), - " not supported.<P>\n", - NULL); - return(add_optional_notes(r, s1, "error-notes", "<P>\n")); - case HTTP_BAD_GATEWAY: - s1 = "The proxy server received an invalid" CRLF - "response from an upstream server.<P>" CRLF; - return(add_optional_notes(r, s1, "error-notes", "<P>\n")); - case HTTP_VARIANT_ALSO_VARIES: - return(apr_pstrcat(p, - "A variant for the requested resource\n<PRE>\n", - ap_escape_html(r->pool, r->uri), - "\n</PRE>\nis itself a negotiable resource. " - "This indicates a configuration error.<P>\n", - NULL)); - case HTTP_REQUEST_TIME_OUT: - return("I'm tired of waiting for your request.\n"); - case HTTP_GONE: - return(apr_pstrcat(p, - "The requested resource<BR>", - ap_escape_html(r->pool, r->uri), - "<BR>\nis no longer available on this server " - "and there is no forwarding address.\n" - "Please remove all references to this resource.\n", - NULL)); - case HTTP_REQUEST_ENTITY_TOO_LARGE: - return(apr_pstrcat(p, - "The requested resource<BR>", - ap_escape_html(r->pool, r->uri), "<BR>\n", - "does not allow request data with ", - r->method, - " requests, or the amount of data provided in\n" - "the request exceeds the capacity limit.\n", - NULL)); - case HTTP_REQUEST_URI_TOO_LARGE: - s1 = "The requested URL's length exceeds the capacity\n" - "limit for this server.<P>\n"; - return(add_optional_notes(r, s1, "error-notes", "<P>\n")); - case HTTP_UNSUPPORTED_MEDIA_TYPE: - return("The supplied request data is not in a format\n" - "acceptable for processing by this resource.\n"); - case HTTP_RANGE_NOT_SATISFIABLE: - return("None of the range-specifier values in the Range\n" - "request-header field overlap the current extent\n" - "of the selected resource.\n"); - case HTTP_EXPECTATION_FAILED: - return(apr_pstrcat(p, - "The expectation given in the Expect request-header" - "\nfield could not be met by this server.<P>\n" - "The client sent<PRE>\n Expect: ", - apr_table_get(r->headers_in, "Expect"), "\n</PRE>\n" - "but we only allow the 100-continue expectation.\n", - NULL)); - case HTTP_UNPROCESSABLE_ENTITY: - return("The server understands the media type of the\n" - "request entity, but was unable to process the\n" - "contained instructions.\n"); - case HTTP_LOCKED: - return("The requested resource is currently locked.\n" - "The lock must be released or proper identification\n" - "given before the method can be applied.\n"); - case HTTP_FAILED_DEPENDENCY: - return("The method could not be performed on the resource\n" - "because the requested action depended on another\n" - "action and that other action failed.\n"); - case HTTP_INSUFFICIENT_STORAGE: - return("The method could not be performed on the resource\n" - "because the server is unable to store the\n" - "representation needed to successfully complete the\n" - "request. There is insufficient free space left in\n" - "your storage allocation.\n"); - case HTTP_SERVICE_UNAVAILABLE: - return("The server is temporarily unable to service your\n" - "request due to maintenance downtime or capacity\n" - "problems. Please try again later.\n"); - case HTTP_GATEWAY_TIME_OUT: - return("The proxy server did not receive a timely response\n" - "from the upstream server.\n"); - case HTTP_NOT_EXTENDED: - return("A mandatory extension policy in the request is not\n" - "accepted by the server for this resource.\n"); - default: /* HTTP_INTERNAL_SERVER_ERROR */ - /* - * This comparison to expose error-notes could be modified to - * use a configuration directive and export based on that - * directive. For now "*" is used to designate an error-notes - * that is totally safe for any user to see (ie lacks paths, - * database passwords, etc.) - */ - if (((error_notes = apr_table_get(r->notes, "error-notes")) != NULL) - && (h1 = apr_table_get(r->notes, "verbose-error-to")) != NULL - && (strcmp(h1, "*") == 0)) { - return(apr_pstrcat(p, error_notes, "<P>\n", NULL)); - } - else { - return(apr_pstrcat(p, - "The server encountered an internal error or\n" - "misconfiguration and was unable to complete\n" - "your request.<P>\n" - "Please contact the server administrator,\n ", - ap_escape_html(r->pool, r->server->server_admin), - " and inform them of the time the error occurred,\n" - "and anything you might have done that may have\n" - "caused the error.<P>\n" - "More information about this error may be available\n" - "in the server error log.<P>\n", - NULL)); - } - /* - * It would be nice to give the user the information they need to - * fix the problem directly since many users don't have access to - * the error_log (think University sites) even though they can easily - * get this error by misconfiguring an htaccess file. However, the - e error notes tend to include the real file pathname in this case, - * which some people consider to be a breach of privacy. Until we - * can figure out a way to remove the pathname, leave this commented. - * - * if ((error_notes = apr_table_get(r->notes, "error-notes")) != NULL) { - * return(apr_pstrcat(p, error_notes, "<P>\n", NULL); - * } - * else { - * return ""; - * } - */ - } -} - -static void reset_filters(request_rec *r) -{ - ap_filter_t *f = r->output_filters; - - while (f) { - if (!strcasecmp(f->frec->name, "CORE") || - !strcasecmp(f->frec->name, "CONTENT_LENGTH") || - !strcasecmp(f->frec->name, "HTTP_HEADER")) { - f = f->next; - continue; - } - else { - ap_remove_output_filter(f); - f = f->next; - } - } -} - -/* We should have named this send_canned_response, since it is used for any - * response that can be generated by the server from the request record. - * This includes all 204 (no content), 3xx (redirect), 4xx (client error), - * and 5xx (server error) messages that have not been redirected to another - * handler via the ErrorDocument feature. - */ -AP_DECLARE(void) ap_send_error_response(request_rec *r, int recursive_error) -{ - int status = r->status; - int idx = ap_index_of_response(status); - char *custom_response; - const char *location = apr_table_get(r->headers_out, "Location"); - - /* At this point, we are starting the response over, so we have to reset - * this value. - */ - r->eos_sent = 0; - reset_filters(r); - - /* - * It's possible that the Location field might be in r->err_headers_out - * instead of r->headers_out; use the latter if possible, else the - * former. - */ - if (location == NULL) { - location = apr_table_get(r->err_headers_out, "Location"); - } - /* We need to special-case the handling of 204 and 304 responses, - * since they have specific HTTP requirements and do not include a - * message body. Note that being assbackwards here is not an option. - */ - if (status == HTTP_NOT_MODIFIED) { - ap_finalize_request_protocol(r); - return; - } - - if (status == HTTP_NO_CONTENT) { - ap_finalize_request_protocol(r); - return; - } - - if (!r->assbackwards) { - apr_table_t *tmp = r->headers_out; - - /* For all HTTP/1.x responses for which we generate the message, - * we need to avoid inheriting the "normal status" header fields - * that may have been set by the request handler before the - * error or redirect, except for Location on external redirects. - */ - r->headers_out = r->err_headers_out; - r->err_headers_out = tmp; - apr_table_clear(r->err_headers_out); - - if (ap_is_HTTP_REDIRECT(status) || (status == HTTP_CREATED)) { - if ((location != NULL) && *location) { - apr_table_setn(r->headers_out, "Location", location); - } - else { - location = ""; /* avoids coredump when printing, below */ - } - } - - r->content_language = NULL; - r->content_languages = NULL; - r->content_encoding = NULL; - r->clength = 0; - r->content_type = "text/html; charset=iso-8859-1"; - - if ((status == HTTP_METHOD_NOT_ALLOWED) - || (status == HTTP_NOT_IMPLEMENTED)) { - apr_table_setn(r->headers_out, "Allow", make_allow(r)); - } - - if (r->header_only) { - ap_finalize_request_protocol(r); - return; - } - } - - if ((custom_response = ap_response_code_string(r, idx))) { - /* - * We have a custom response output. This should only be - * a text-string to write back. But if the ErrorDocument - * was a local redirect and the requested resource failed - * for any reason, the custom_response will still hold the - * redirect URL. We don't really want to output this URL - * as a text message, so first check the custom response - * string to ensure that it is a text-string (using the - * same test used in ap_die(), i.e. does it start with a "). - * If it doesn't, we've got a recursive error, so find - * the original error and output that as well. - */ - if (custom_response[0] == '\"') { - ap_rputs(custom_response + 1, r); - ap_finalize_request_protocol(r); - return; - } - /* - * Redirect failed, so get back the original error - */ - while (r->prev && (r->prev->status != HTTP_OK)) - r = r->prev; - } - { - const char *title = status_lines[idx]; - const char *h1; - - /* XXX This is a major hack that should be fixed cleanly. The - * problem is that we have the information we need in a previous - * request, but the text of the page must be sent down the last - * request_rec's filter stack. rbb - */ - request_rec *rlast = r; - while (rlast->next) { - rlast = rlast->next; - } - - /* Accept a status_line set by a module, but only if it begins - * with the 3 digit status code - */ - if (r->status_line != NULL - && strlen(r->status_line) > 4 /* long enough */ - && apr_isdigit(r->status_line[0]) - && apr_isdigit(r->status_line[1]) - && apr_isdigit(r->status_line[2]) - && apr_isspace(r->status_line[3]) - && apr_isalnum(r->status_line[4])) { - title = r->status_line; - } - - /* folks decided they didn't want the error code in the H1 text */ - h1 = &title[4]; - - /* can't count on a charset filter being in place here, - * so do ebcdic->ascii translation explicitly (if needed) - */ - - ap_rvputs_proto_in_ascii(rlast, - DOCTYPE_HTML_2_0 - "<HTML><HEAD>\n<TITLE>", title, - "</TITLE>\n</HEAD><BODY>\n<H1>", h1, "</H1>\n", - NULL); - - ap_rvputs_proto_in_ascii(rlast, - get_canned_error_string(status, r, location), - NULL); - - if (recursive_error) { - ap_rvputs_proto_in_ascii(rlast, "<P>Additionally, a ", - status_lines[ap_index_of_response(recursive_error)], - "\nerror was encountered while trying to use an " - "ErrorDocument to handle the request.\n", NULL); - } - ap_rvputs_proto_in_ascii(rlast, ap_psignature("<HR>\n", r), NULL); - ap_rvputs_proto_in_ascii(rlast, "</BODY></HTML>\n", NULL); - } - ap_finalize_request_protocol(r); -} - -/* - * Create a new method list with the specified number of preallocated - * extension slots. - */ -AP_DECLARE(ap_method_list_t *) ap_make_method_list(apr_pool_t *p, int nelts) -{ - ap_method_list_t *ml; - - ml = (ap_method_list_t *) apr_palloc(p, sizeof(ap_method_list_t)); - ml->method_mask = 0; - ml->method_list = apr_array_make(p, sizeof(char *), nelts); - return ml; -} - -/* - * Make a copy of a method list (primarily for subrequests that may - * subsequently change it; don't want them changing the parent's, too!). - */ -AP_DECLARE(void) ap_copy_method_list(ap_method_list_t *dest, - ap_method_list_t *src) -{ - int i; - char **imethods; - char **omethods; - - dest->method_mask = src->method_mask; - imethods = (char **) src->method_list->elts; - for (i = 0; i < src->method_list->nelts; ++i) { - omethods = (char **) apr_array_push(dest->method_list); - *omethods = apr_pstrdup(dest->method_list->cont, imethods[i]); - } -} - -/* - * Invoke a callback routine for each method in the specified list. - */ -AP_DECLARE_NONSTD(void) ap_method_list_do(int (*comp) (void *urec, const char *mname, - int mnum), - void *rec, - const ap_method_list_t *ml, ...) -{ - va_list vp; - va_start(vp, ml); - ap_method_list_vdo(comp, rec, ml, vp); - va_end(vp); -} - -AP_DECLARE(void) ap_method_list_vdo(int (*comp) (void *mrec, - const char *mname, - int mnum), - void *rec, const ap_method_list_t *ml, - va_list vp) -{ - -} - -/* - * Return true if the specified HTTP method is in the provided - * method list. - */ -AP_DECLARE(int) ap_method_in_list(ap_method_list_t *l, const char *method) -{ - int methnum; - int i; - char **methods; - - /* - * If it's one of our known methods, use the shortcut and check the - * bitmask. - */ - methnum = ap_method_number_of(method); - if (methnum != M_INVALID) { - return (l->method_mask & (1 << methnum)); - } - /* - * Otherwise, see if the method name is in the array or string names - */ - if ((l->method_list == NULL) || (l->method_list->nelts == 0)) { - return 0; - } - methods = (char **)l->method_list->elts; - for (i = 0; i < l->method_list->nelts; ++i) { - if (strcmp(method, methods[i]) == 0) { - return 1; - } - } - return 0; -} - -/* - * Add the specified method to a method list (if it isn't already there). - */ -AP_DECLARE(void) ap_method_list_add(ap_method_list_t *l, const char *method) -{ - int methnum; - int i; - const char **xmethod; - char **methods; - - /* - * If it's one of our known methods, use the shortcut and use the - * bitmask. - */ - methnum = ap_method_number_of(method); - l->method_mask |= (1 << methnum); - if (methnum != M_INVALID) { - return; - } - /* - * Otherwise, see if the method name is in the array of string names. - */ - if (l->method_list->nelts != 0) { - methods = (char **)l->method_list->elts; - for (i = 0; i < l->method_list->nelts; ++i) { - if (strcmp(method, methods[i]) == 0) { - return; - } - } - } - xmethod = (const char **) apr_array_push(l->method_list); - *xmethod = method; -} - -/* - * Remove the specified method from a method list. - */ -AP_DECLARE(void) ap_method_list_remove(ap_method_list_t *l, - const char *method) -{ - int methnum; - char **methods; - - /* - * If it's one of our known methods, use the shortcut and use the - * bitmask. - */ - methnum = ap_method_number_of(method); - l->method_mask |= ~(1 << methnum); - if (methnum != M_INVALID) { - return; - } - /* - * Otherwise, see if the method name is in the array of string names. - */ - if (l->method_list->nelts != 0) { - register int i, j, k; - methods = (char **)l->method_list->elts; - for (i = 0; i < l->method_list->nelts; ) { - if (strcmp(method, methods[i]) == 0) { - for (j = i, k = i + 1; k < l->method_list->nelts; ++j, ++k) { - methods[j] = methods[k]; - } - --l->method_list->nelts; - } - else { - ++i; - } - } - } -} - -/* - * Reset a method list to be completely empty. - */ -AP_DECLARE(void) ap_clear_method_list(ap_method_list_t *l) -{ - l->method_mask = 0; - l->method_list->nelts = 0; -} - -/* - * Construct an entity tag (ETag) from resource information. If it's a real - * file, build in some of the file characteristics. If the modification time - * is newer than (request-time minus 1 second), mark the ETag as weak - it - * could be modified again in as short an interval. We rationalize the - * modification time we're given to keep it from being in the future. - */ -AP_DECLARE(char *) ap_make_etag(request_rec *r, int force_weak) -{ - char *etag; - char *weak; - - /* - * Make an ETag header out of various pieces of information. We use - * the last-modified date and, if we have a real file, the - * length and inode number - note that this doesn't have to match - * the content-length (i.e. includes), it just has to be unique - * for the file. - * - * If the request was made within a second of the last-modified date, - * we send a weak tag instead of a strong one, since it could - * be modified again later in the second, and the validation - * would be incorrect. - */ - - weak = ((r->request_time - r->mtime > APR_USEC_PER_SEC) - && !force_weak) ? "" : "W/"; - - if (r->finfo.filetype != 0) { - etag = apr_psprintf(r->pool, - "%s\"%lx-%lx-%lx\"", weak, - (unsigned long) r->finfo.inode, - (unsigned long) r->finfo.size, - (unsigned long) r->mtime); - } - else { - etag = apr_psprintf(r->pool, "%s\"%lx\"", weak, - (unsigned long) r->mtime); - } - - return etag; -} - -AP_DECLARE(void) ap_set_etag(request_rec *r) -{ - char *etag; - char *variant_etag, *vlv; - int vlv_weak; - - if (!r->vlist_validator) { - etag = ap_make_etag(r, 0); - } - else { - /* If we have a variant list validator (vlv) due to the - * response being negotiated, then we create a structured - * entity tag which merges the variant etag with the variant - * list validator (vlv). This merging makes revalidation - * somewhat safer, ensures that caches which can deal with - * Vary will (eventually) be updated if the set of variants is - * changed, and is also a protocol requirement for transparent - * content negotiation. - */ - - /* if the variant list validator is weak, we make the whole - * structured etag weak. If we would not, then clients could - * have problems merging range responses if we have different - * variants with the same non-globally-unique strong etag. - */ - - vlv = r->vlist_validator; - vlv_weak = (vlv[0] == 'W'); - - variant_etag = ap_make_etag(r, vlv_weak); - - /* merge variant_etag and vlv into a structured etag */ - - variant_etag[strlen(variant_etag) - 1] = '\0'; - if (vlv_weak) - vlv += 3; - else - vlv++; - etag = apr_pstrcat(r->pool, variant_etag, ";", vlv, NULL); - } - - apr_table_setn(r->headers_out, "ETag", etag); -} - -static int parse_byterange(char *range, apr_off_t clength, - apr_off_t *start, apr_off_t *end) -{ - char *dash = strchr(range, '-'); - - if (!dash) - return 0; - - if ((dash == range)) { - /* In the form "-5" */ - *start = clength - atol(dash + 1); - *end = clength - 1; - } - else { - *dash = '\0'; - dash++; - *start = atol(range); - if (*dash) - *end = atol(dash); - else /* "5-" */ - *end = clength - 1; - } - - if (*start < 0) - *start = 0; - - if (*end >= clength) - *end = clength - 1; - - if (*start > *end) - return -1; - - return (*start > 0 || *end < clength); -} - -static int ap_set_byterange(request_rec *r); - -typedef struct byterange_ctx { - apr_bucket_brigade *bb; - int num_ranges; - const char *orig_ct; -} byterange_ctx; - -/* - * Here we try to be compatible with clients that want multipart/x-byteranges - * instead of multipart/byteranges (also see above), as per HTTP/1.1. We - * look for the Request-Range header (e.g. Netscape 2 and 3) as an indication - * that the browser supports an older protocol. We also check User-Agent - * for Microsoft Internet Explorer 3, which needs this as well. - */ -static int use_range_x(request_rec *r) -{ - const char *ua; - return (apr_table_get(r->headers_in, "Request-Range") || - ((ua = apr_table_get(r->headers_in, "User-Agent")) - && ap_strstr_c(ua, "MSIE 3"))); -} - -#define BYTERANGE_FMT "%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT "/%" APR_OFF_T_FMT - -AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter( - ap_filter_t *f, - apr_bucket_brigade *bb) -{ -#define MIN_LENGTH(len1, len2) ((len1 > len2) ? len2 : len1) - request_rec *r = f->r; - byterange_ctx *ctx = f->ctx; - apr_bucket *e; - apr_bucket_brigade *bsend; - apr_off_t range_start; - apr_off_t range_end; - char *current; - char *bound_head; - apr_ssize_t bb_length; - apr_off_t clength = 0; - apr_status_t rv; - int found = 0; - - if (!ctx) { - int num_ranges = ap_set_byterange(r); - - if (num_ranges == -1) { - ap_remove_output_filter(f); - bsend = apr_brigade_create(r->pool); - e = ap_bucket_error_create(HTTP_RANGE_NOT_SATISFIABLE, NULL, r->pool); - APR_BRIGADE_INSERT_TAIL(bsend, e); - e = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bsend, e); - return ap_pass_brigade(f->next, bsend); - } - if (num_ranges == 0) { - ap_remove_output_filter(f); - return ap_pass_brigade(f->next, bb); - } - - ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx)); - ctx->num_ranges = num_ranges; - - if (num_ranges > 1) { - ctx->orig_ct = r->content_type; - r->content_type = - apr_pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/", - "byteranges; boundary=", r->boundary, NULL); - } - - /* create a brigade in case we never call ap_save_brigade() */ - ctx->bb = apr_brigade_create(r->pool); - } - - /* We can't actually deal with byte-ranges until we have the whole brigade - * because the byte-ranges can be in any order, and according to the RFC, - * we SHOULD return the data in the same order it was requested. - */ - if (!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) { - ap_save_brigade(f, &ctx->bb, &bb); - return APR_SUCCESS; - } - - /* compute this once (it is an invariant) */ - bound_head = apr_pstrcat(r->pool, - CRLF "--", r->boundary, - CRLF "Content-type: ", - ap_make_content_type(r, ctx->orig_ct), - CRLF "Content-range: bytes ", - NULL); - ap_xlate_proto_to_ascii(bound_head, strlen(bound_head)); - - /* If we have a saved brigade from a previous run, concat the passed - * brigade with our saved brigade. Otherwise just continue. - */ - if (ctx->bb) { - APR_BRIGADE_CONCAT(ctx->bb, bb); - bb = ctx->bb; - ctx->bb = NULL; /* ### strictly necessary? call brigade_destroy? */ - } - - /* It is possible that we won't have a content length yet, so we have to - * compute the length before we can actually do the byterange work. - */ - (void) apr_brigade_length(bb, 1, &bb_length); - clength = (apr_off_t)bb_length; - - /* this brigade holds what we will be sending */ - bsend = apr_brigade_create(r->pool); - - while ((current = ap_getword(r->pool, &r->range, ',')) && - (rv = parse_byterange(current, clength, &range_start, &range_end))) { - apr_bucket *e2; - apr_bucket *ec; - - if (rv == -1) { - continue; - } - else { - found = 1; - } - - if (ctx->num_ranges > 1) { - char *ts; - - e = apr_bucket_pool_create(bound_head, - strlen(bound_head), r->pool); - APR_BRIGADE_INSERT_TAIL(bsend, e); - - ts = apr_psprintf(r->pool, BYTERANGE_FMT CRLF CRLF, - range_start, range_end, clength); - ap_xlate_proto_to_ascii(ts, strlen(ts)); - e = apr_bucket_pool_create(ts, strlen(ts), r->pool); - APR_BRIGADE_INSERT_TAIL(bsend, e); - } - - e = apr_brigade_partition(bb, range_start); - e2 = apr_brigade_partition(bb, range_end + 1); - - ec = e; - do { - apr_bucket *foo; - const char *str; - apr_size_t len; - - if (apr_bucket_copy(ec, &foo) != APR_SUCCESS) { - apr_bucket_read(ec, &str, &len, APR_BLOCK_READ); - foo = apr_bucket_heap_create(str, len, 0, NULL); - } - APR_BRIGADE_INSERT_TAIL(bsend, foo); - ec = APR_BUCKET_NEXT(ec); - } while (ec != e2); - } - - if (found == 0) { - ap_remove_output_filter(f); - r->status = HTTP_OK; - return HTTP_RANGE_NOT_SATISFIABLE; - } - - if (ctx->num_ranges > 1) { - char *end; - - /* add the final boundary */ - end = apr_pstrcat(r->pool, CRLF "--", r->boundary, "--" CRLF, NULL); - ap_xlate_proto_to_ascii(end, strlen(end)); - e = apr_bucket_pool_create(end, strlen(end), r->pool); - APR_BRIGADE_INSERT_TAIL(bsend, e); - } - - e = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bsend, e); - - /* we're done with the original content */ - apr_brigade_destroy(bb); - - /* send our multipart output */ - return ap_pass_brigade(f->next, bsend); -} - -static int ap_set_byterange(request_rec *r) -{ - const char *range; - const char *if_range; - const char *match; - const char *ct; - apr_off_t range_start; - apr_off_t range_end; - int num_ranges; - - if (r->assbackwards) - return 0; - - /* is content already a single range? */ - if (apr_table_get(r->headers_out, "Content-Range")) { - return 0; - } - - /* is content already a multiple range? */ - if ((ct = apr_table_get(r->headers_out, "Content-Type")) && - (!strncasecmp(ct, "multipart/byteranges", 20) || - !strncasecmp(ct, "multipart/x-byteranges", 22))) { - return 0; - } - - /* Check for Range request-header (HTTP/1.1) or Request-Range for - * backwards-compatibility with second-draft Luotonen/Franks - * byte-ranges (e.g. Netscape Navigator 2-3). - * - * We support this form, with Request-Range, and (farther down) we - * send multipart/x-byteranges instead of multipart/byteranges for - * Request-Range based requests to work around a bug in Netscape - * Navigator 2-3 and MSIE 3. - */ - - if (!(range = apr_table_get(r->headers_in, "Range"))) - range = apr_table_get(r->headers_in, "Request-Range"); - - if (!range || strncasecmp(range, "bytes=", 6)) { - return 0; - } - - /* Check the If-Range header for Etag or Date. - * Note that this check will return false (as required) if either - * of the two etags are weak. - */ - if ((if_range = apr_table_get(r->headers_in, "If-Range"))) { - if (if_range[0] == '"') { - if (!(match = apr_table_get(r->headers_out, "Etag")) || - (strcmp(if_range, match) != 0)) - return 0; - } - else if (!(match = apr_table_get(r->headers_out, "Last-Modified")) || - (strcmp(if_range, match) != 0)) - return 0; - } - - /* would be nice to pick this up from f->ctx */ - ct = ap_make_content_type(r, r->content_type); - - if (!ap_strchr_c(range, ',')) { - int rv; - /* A single range */ - - /* rvarse_byterange() modifies the contents, so make a copy */ - if ((rv = parse_byterange(apr_pstrdup(r->pool, range + 6), r->clength, - &range_start, &range_end)) <= 0) { - return rv; - } - apr_table_setn(r->headers_out, "Content-Range", - apr_psprintf(r->pool, "bytes " BYTERANGE_FMT, - range_start, range_end, r->clength)); - apr_table_setn(r->headers_out, "Content-Type", ct); - - num_ranges = 1; - } - else { - /* a multiple range */ - - num_ranges = 2; - - /* ### it would be nice if r->boundary was in f->ctx */ - r->boundary = apr_psprintf(r->pool, "%qx%lx", - r->request_time, (long) getpid()); - - apr_table_setn(r->headers_out, "Content-Type", - apr_pstrcat(r->pool, - "multipart", use_range_x(r) ? "/x-" : "/", - "byteranges; boundary=", r->boundary, - NULL)); - } - - r->status = HTTP_PARTIAL_CONTENT; - r->range = range + 6; - - return num_ranges; -} - diff --git a/modules/http/http_request.c b/modules/http/http_request.c deleted file mode 100644 index 56064c451b..0000000000 --- a/modules/http/http_request.c +++ /dev/null @@ -1,574 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_request.c: functions to get and process requests - * - * Rob McCool 3/21/93 - * - * Thoroughly revamped by rst for Apache. NB this file reads - * best from the bottom up. - * - */ - -#include "apr_strings.h" -#include "apr_file_io.h" -#include "apr_fnmatch.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#define CORE_PRIVATE -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_log.h" -#include "http_main.h" -#include "util_filter.h" -#include "util_charset.h" - -#include "mod_core.h" - -#if APR_HAVE_STDARG_H -#include <stdarg.h> -#endif - -/***************************************************************** - * - * Mainline request processing... - */ - -AP_DECLARE(void) ap_die(int type, request_rec *r) -{ - int error_index = ap_index_of_response(type); - char *custom_response = ap_response_code_string(r, error_index); - int recursive_error = 0; - - if (type == AP_FILTER_ERROR) { - return; - } - - if (type == DONE) { - ap_finalize_request_protocol(r); - return; - } - - /* - * The following takes care of Apache redirects to custom response URLs - * Note that if we are already dealing with the response to some other - * error condition, we just report on the original error, and give up on - * any attempt to handle the other thing "intelligently"... - */ - - if (r->status != HTTP_OK) { - recursive_error = type; - - while (r->prev && (r->prev->status != HTTP_OK)) - r = r->prev; /* Get back to original error */ - - type = r->status; - custom_response = NULL; /* Do NOT retry the custom thing! */ - } - - r->status = type; - - /* - * This test is done here so that none of the auth modules needs to know - * about proxy authentication. They treat it like normal auth, and then - * we tweak the status. - */ - if (HTTP_UNAUTHORIZED == r->status && PROXYREQ_PROXY == r->proxyreq) { - r->status = HTTP_PROXY_AUTHENTICATION_REQUIRED; - } - - /* - * If we want to keep the connection, be sure that the request body - * (if any) has been read. - */ - if ((r->status != HTTP_NOT_MODIFIED) && (r->status != HTTP_NO_CONTENT) - && !ap_status_drops_connection(r->status) - && r->connection && (r->connection->keepalive != -1)) { - - (void) ap_discard_request_body(r); - } - - /* - * Two types of custom redirects --- plain text, and URLs. Plain text has - * a leading '"', so the URL code, here, is triggered on its absence - */ - - if (custom_response && custom_response[0] != '"') { - - if (ap_is_url(custom_response)) { - /* - * The URL isn't local, so lets drop through the rest of this - * apache code, and continue with the usual REDIRECT handler. - * But note that the client will ultimately see the wrong - * status... - */ - r->status = HTTP_MOVED_TEMPORARILY; - apr_table_setn(r->headers_out, "Location", custom_response); - } - else if (custom_response[0] == '/') { - const char *error_notes; - r->no_local_copy = 1; /* Do NOT send HTTP_NOT_MODIFIED for - * error documents! */ - /* - * This redirect needs to be a GET no matter what the original - * method was. - */ - apr_table_setn(r->subprocess_env, "REQUEST_METHOD", r->method); - - /* - * Provide a special method for modules to communicate - * more informative (than the plain canned) messages to us. - * Propagate them to ErrorDocuments via the ERROR_NOTES variable: - */ - if ((error_notes = apr_table_get(r->notes, "error-notes")) != NULL) { - apr_table_setn(r->subprocess_env, "ERROR_NOTES", error_notes); - } - r->method = apr_pstrdup(r->pool, "GET"); - r->method_number = M_GET; - ap_internal_redirect(custom_response, r); - return; - } - else { - /* - * Dumb user has given us a bad url to redirect to --- fake up - * dying with a recursive server error... - */ - recursive_error = HTTP_INTERNAL_SERVER_ERROR; - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid error redirection directive: %s", - custom_response); - } - } - ap_send_error_response(r, recursive_error); -} - -static void decl_die(int status, char *phase, request_rec *r) -{ - if (status == DECLINED) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, 0, r, - "configuration error: couldn't %s: %s", phase, r->uri); - ap_die(HTTP_INTERNAL_SERVER_ERROR, r); - } - else - ap_die(status, r); -} - -static void process_request_internal(request_rec *r) -{ - int access_status; - - /* Ignore embedded %2F's in path for proxy requests */ - if (!r->proxyreq && r->parsed_uri.path) { - access_status = ap_unescape_url(r->parsed_uri.path); - if (access_status) { - ap_die(access_status, r); - return; - } - } - - ap_getparents(r->uri); /* OK --- shrinking transformations... */ - - if ((access_status = location_walk(r))) { - ap_die(access_status, r); - return; - } - - if ((access_status = ap_run_translate_name(r))) { - decl_die(access_status, "translate", r); - return; - } - - if (!r->proxyreq) { - /* - * We don't want TRACE to run through the normal handler set, we - * handle it specially. - */ - if (r->method_number == M_TRACE) { - if ((access_status = ap_send_http_trace(r))) - ap_die(access_status, r); - else - ap_finalize_request_protocol(r); - return; - } - } - - if (r->proto_num > HTTP_VERSION(1,0) && apr_table_get(r->subprocess_env, "downgrade-1.0")) { - r->proto_num = HTTP_VERSION(1,0); - } - - /* - * NB: directory_walk() clears the per_dir_config, so we don't inherit - * from location_walk() above - */ - - if ((access_status = directory_walk(r))) { - ap_die(access_status, r); - return; - } - - if ((access_status = file_walk(r))) { - ap_die(access_status, r); - return; - } - - if ((access_status = location_walk(r))) { - ap_die(access_status, r); - return; - } - - if ((access_status = ap_run_header_parser(r))) { - ap_die(access_status, r); - return; - } - - switch (ap_satisfies(r)) { - case SATISFY_ALL: - case SATISFY_NOSPEC: - if ((access_status = ap_run_access_checker(r)) != 0) { - decl_die(access_status, "check access", r); - return; - } - if (ap_some_auth_required(r)) { - if (((access_status = ap_run_check_user_id(r)) != 0) || !ap_auth_type(r)) { - decl_die(access_status, ap_auth_type(r) - ? "check user. No user file?" - : "perform authentication. AuthType not set!", r); - return; - } - if (((access_status = ap_run_auth_checker(r)) != 0) || !ap_auth_type(r)) { - decl_die(access_status, ap_auth_type(r) - ? "check access. No groups file?" - : "perform authentication. AuthType not set!", r); - return; - } - } - break; - case SATISFY_ANY: - if (((access_status = ap_run_access_checker(r)) != 0) || !ap_auth_type(r)) { - if (!ap_some_auth_required(r)) { - decl_die(access_status, ap_auth_type(r) - ? "check access" - : "perform authentication. AuthType not set!", r); - return; - } - if (((access_status = ap_run_check_user_id(r)) != 0) || !ap_auth_type(r)) { - decl_die(access_status, ap_auth_type(r) - ? "check user. No user file?" - : "perform authentication. AuthType not set!", r); - return; - } - if (((access_status = ap_run_auth_checker(r)) != 0) || !ap_auth_type(r)) { - decl_die(access_status, ap_auth_type(r) - ? "check access. No groups file?" - : "perform authentication. AuthType not set!", r); - return; - } - } - break; - } - - if (! (r->proxyreq - && r->parsed_uri.scheme != NULL - && strcmp(r->parsed_uri.scheme, "http") == 0) ) { - if ((access_status = ap_run_type_checker(r)) != 0) { - decl_die(access_status, "find types", r); - return; - } - } - - if ((access_status = ap_run_fixups(r)) != 0) { - ap_die(access_status, r); - return; - } - - /* The new insert_filter stage makes sense here IMHO. We are sure that - * we are going to run the request now, so we may as well insert filters - * if any are available. Since the goal of this phase is to allow all - * modules to insert a filter if they want to, this filter returns - * void. I just can't see any way that this filter can reasonably - * fail, either your modules inserts something or it doesn't. rbb - */ - ap_run_insert_filter(r); - - if ((access_status = ap_invoke_handler(r)) != 0) { - ap_die(access_status, r); - return; - } - - /* Take care of little things that need to happen when we're done */ - ap_finalize_request_protocol(r); -} - -static void check_pipeline_flush(request_rec *r) -{ - /* ### if would be nice if we could PEEK without a brigade. that would - ### allow us to defer creation of the brigade to when we actually - ### need to send a FLUSH. */ - apr_bucket_brigade *bb = apr_brigade_create(r->pool); - apr_size_t zero = 0; - - /* Flush the filter contents if: - * - * 1) the connection will be closed - * 2) there isn't a request ready to be read - */ - /* ### shouldn't this read from the connection input filters? */ - if (!r->connection->keepalive || - ap_get_brigade(r->input_filters, bb, AP_MODE_PEEK, &zero) != APR_SUCCESS) { - apr_bucket *e = apr_bucket_flush_create(); - - /* We just send directly to the connection based filters. At - * this point, we know that we have seen all of the data - * (request finalization sent an EOS bucket, which empties all - * of the request filters). We just want to flush the buckets - * if something hasn't been sent to the network yet. - */ - APR_BRIGADE_INSERT_HEAD(bb, e); - ap_pass_brigade(r->connection->output_filters, bb); - } -} - -void ap_process_request(request_rec *r) -{ - int access_status; - - /* Give quick handlers a shot at serving the request on the fast - * path, bypassing all of the other Apache hooks. - * - * This hook was added to enable serving files out of a URI keyed - * content cache ( e.g., Mike Abbott's Quick Shortcut Cache, - * described here: http://oss.sgi.com/projects/apache/mod_qsc.html ) - * - * It may have other uses as well, such as routing requests directly to - * content handlers that have the ability to grok HTTP and do their - * own access checking, etc (e.g. servlet engines). - * - * Use this hook with extreme care and only if you know what you are - * doing. - * - * Consider moving this hook to after the first location_walk in order - * to enable the quick handler to make decisions based on config - * directives in Location blocks. - */ - access_status = ap_run_quick_handler(r); - if (access_status == OK) { - ap_finalize_request_protocol(r); - } - else if (access_status == DECLINED) { - process_request_internal(r); - } - else { - ap_die(access_status, r); - } - - /* - * We want to flush the last packet if this isn't a pipelining connection - * *before* we start into logging. Suppose that the logging causes a DNS - * lookup to occur, which may have a high latency. If we hold off on - * this packet, then it'll appear like the link is stalled when really - * it's the application that's stalled. - */ - check_pipeline_flush(r); - ap_run_log_transaction(r); -} - -static apr_table_t *rename_original_env(apr_pool_t *p, apr_table_t *t) -{ - apr_array_header_t *env_arr = apr_table_elts(t); - apr_table_entry_t *elts = (apr_table_entry_t *) env_arr->elts; - apr_table_t *new = apr_table_make(p, env_arr->nalloc); - int i; - - for (i = 0; i < env_arr->nelts; ++i) { - if (!elts[i].key) - continue; - apr_table_setn(new, apr_pstrcat(p, "REDIRECT_", elts[i].key, NULL), - elts[i].val); - } - - return new; -} - -static request_rec *internal_internal_redirect(const char *new_uri, - request_rec *r) { - int access_status; - request_rec *new = (request_rec *) apr_pcalloc(r->pool, - sizeof(request_rec)); - - new->connection = r->connection; - new->server = r->server; - new->pool = r->pool; - - /* - * A whole lot of this really ought to be shared with http_protocol.c... - * another missing cleanup. It's particularly inappropriate to be - * setting header_only, etc., here. - */ - - new->method = r->method; - new->method_number = r->method_number; - new->allowed_methods = ap_make_method_list(new->pool, 2); - ap_parse_uri(new, new_uri); - - new->request_config = ap_create_request_config(r->pool); - - new->per_dir_config = r->server->lookup_defaults; - - new->prev = r; - r->next = new; - - /* Must have prev and next pointers set before calling create_request - * hook. - */ - ap_run_create_request(new); - - /* Inherit the rest of the protocol info... */ - - new->the_request = r->the_request; - - new->allowed = r->allowed; - - new->status = r->status; - new->assbackwards = r->assbackwards; - new->header_only = r->header_only; - new->protocol = r->protocol; - new->proto_num = r->proto_num; - new->hostname = r->hostname; - new->request_time = r->request_time; - new->main = r->main; - - new->headers_in = r->headers_in; - new->headers_out = apr_table_make(r->pool, 12); - new->err_headers_out = r->err_headers_out; - new->subprocess_env = rename_original_env(r->pool, r->subprocess_env); - new->notes = apr_table_make(r->pool, 5); - new->allowed_methods = ap_make_method_list(new->pool, 2); - - new->htaccess = r->htaccess; - new->no_cache = r->no_cache; - new->expecting_100 = r->expecting_100; - new->no_local_copy = r->no_local_copy; - new->read_length = r->read_length; /* We can only read it once */ - new->vlist_validator = r->vlist_validator; - - new->output_filters = r->connection->output_filters; - new->input_filters = r->connection->input_filters; - - ap_add_output_filter("BYTERANGE", NULL, new, new->connection); - ap_add_output_filter("CONTENT_LENGTH", NULL, new, new->connection); - ap_add_output_filter("HTTP_HEADER", NULL, new, new->connection); - - apr_table_setn(new->subprocess_env, "REDIRECT_STATUS", - apr_psprintf(r->pool, "%d", r->status)); - - /* - * XXX: hmm. This is because mod_setenvif and mod_unique_id really need - * to do their thing on internal redirects as well. Perhaps this is a - * misnamed function. - */ - if ((access_status = ap_run_post_read_request(new))) { - ap_die(access_status, new); - return NULL; - } - - return new; -} - -AP_DECLARE(void) ap_internal_redirect(const char *new_uri, request_rec *r) -{ - request_rec *new = internal_internal_redirect(new_uri, r); - process_request_internal(new); -} - -/* This function is designed for things like actions or CGI scripts, when - * using AddHandler, and you want to preserve the content type across - * an internal redirect. - */ -AP_DECLARE(void) ap_internal_redirect_handler(const char *new_uri, request_rec *r) -{ - request_rec *new = internal_internal_redirect(new_uri, r); - if (r->handler) - new->content_type = r->content_type; - process_request_internal(new); -} - -AP_DECLARE(void) ap_allow_methods(request_rec *r, int reset, ...) -{ - const char *method; - va_list methods; - - /* - * Get rid of any current settings if requested; not just the - * well-known methods but any extensions as well. - */ - if (reset) { - ap_clear_method_list(r->allowed_methods); - } - - va_start(methods, reset); - while ((method = va_arg(methods, const char *)) != NULL) { - ap_method_list_add(r->allowed_methods, method); - } -} diff --git a/modules/http/mod_core.h b/modules/http/mod_core.h deleted file mode 100644 index 29fef07b65..0000000000 --- a/modules/http/mod_core.h +++ /dev/null @@ -1,99 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef MOD_CORE_H -#define MOD_CORE_H - -#include "apr.h" -#include "apr_buckets.h" - -#include "httpd.h" -#include "util_filter.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @package mod_core private header file - */ - -/* - * These (input) filters are internal to the mod_core operation. - */ -apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_size_t *readbytes); -apr_status_t ap_dechunk_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_size_t *readbytes); - -char *ap_response_code_string(request_rec *r, int error_index); - -/** - * Send the minimal part of an HTTP response header. - * @param r The current request - * @param bb The brigade to add the header to. - * @warning Modules should be very careful about using this, and should - * the default behavior. Much of the HTTP/1.1 implementation - * correctness depends on the full headers. - * @deffunc void ap_basic_http_header(request_rec *r, apr_bucket_brigade *bb) - */ -AP_DECLARE(void) ap_basic_http_header(request_rec *r, apr_bucket_brigade *bb); - -AP_DECLARE(int) ap_send_http_trace(request_rec *r); -int ap_send_http_options(request_rec *r); - -#ifdef __cplusplus -} -#endif - -#endif /* !MOD_CORE_H */ diff --git a/modules/http/mod_mime.c b/modules/http/mod_mime.c deleted file mode 100644 index bbeee8fe3d..0000000000 --- a/modules/http/mod_mime.c +++ /dev/null @@ -1,823 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_mime.c: Sends/gets MIME headers for requests - * - * Rob McCool - * - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "http_request.h" - - -/* XXXX - fix me / EBCDIC - * there was a cludge here which would use its - * own version apr_isascii(). Indicating that - * on some platforms that might be needed. - * - * #define OS_ASC(c) (c) -- for mere mortals - * or - * #define OS_ASC(c) (ebcdic2ascii[c]) -- for dino's - * - * #define apr_isascii(c) ((OS_ASC(c) & 0x80) == 0) - */ - -/* XXXXX - fix me - See note with NOT_PROXY - */ - -typedef struct attrib_info { - char *name; -} attrib_info; - -typedef struct { - apr_table_t *forced_types; /* Additional AddTyped stuff */ - apr_table_t *encoding_types; /* Added with AddEncoding... */ - apr_table_t *language_types; /* Added with AddLanguage... */ - apr_table_t *handlers; /* Added with AddHandler... */ - apr_table_t *charset_types; /* Added with AddCharset... */ - apr_array_header_t *handlers_remove; /* List of handlers to remove */ - apr_array_header_t *types_remove; /* List of MIME types to remove */ - apr_array_header_t *encodings_remove; /* List of encodings to remove */ - - char *type; /* Type forced with ForceType */ - char *handler; /* Handler forced with SetHandler */ - char *default_language; /* Language if no AddLanguage ext found */ - /* Due to the FUD about JS and charsets - * default_charset is actually in src/main */ -} mime_dir_config; - -typedef struct param_s { - char *attr; - char *val; - struct param_s *next; -} param; - -typedef struct { - char *type; - char *subtype; - param *param; -} content_type; - -static char tspecial[] = { - '(', ')', '<', '>', '@', ',', ';', ':', - '\\', '"', '/', '[', ']', '?', '=', - '\0' -}; - -module AP_MODULE_DECLARE_DATA mime_module; - -static void *create_mime_dir_config(apr_pool_t *p, char *dummy) -{ - mime_dir_config *new = - (mime_dir_config *) apr_palloc(p, sizeof(mime_dir_config)); - - new->forced_types = apr_table_make(p, 4); - new->encoding_types = apr_table_make(p, 4); - new->charset_types = apr_table_make(p, 4); - new->language_types = apr_table_make(p, 4); - new->handlers = apr_table_make(p, 4); - new->handlers_remove = apr_array_make(p, 4, sizeof(attrib_info)); - new->types_remove = apr_array_make(p, 4, sizeof(attrib_info)); - new->encodings_remove = apr_array_make(p, 4, sizeof(attrib_info)); - - new->type = NULL; - new->handler = NULL; - new->default_language = NULL; - - return new; -} - -static void *merge_mime_dir_configs(apr_pool_t *p, void *basev, void *addv) -{ - mime_dir_config *base = (mime_dir_config *) basev; - mime_dir_config *add = (mime_dir_config *) addv; - mime_dir_config *new = - (mime_dir_config *) apr_palloc(p, sizeof(mime_dir_config)); - int i; - attrib_info *suffix; - - new->forced_types = apr_table_overlay(p, add->forced_types, - base->forced_types); - new->encoding_types = apr_table_overlay(p, add->encoding_types, - base->encoding_types); - new->charset_types = apr_table_overlay(p, add->charset_types, - base->charset_types); - new->language_types = apr_table_overlay(p, add->language_types, - base->language_types); - new->handlers = apr_table_overlay(p, add->handlers, - base->handlers); - - suffix = (attrib_info *) add->handlers_remove->elts; - for (i = 0; i < add->handlers_remove->nelts; i++) { - apr_table_unset(new->handlers, suffix[i].name); - } - - suffix = (attrib_info *) add->types_remove->elts; - for (i = 0; i < add->types_remove->nelts; i++) { - apr_table_unset(new->forced_types, suffix[i].name); - } - - suffix = (attrib_info *) add->encodings_remove->elts; - for (i = 0; i < add->encodings_remove->nelts; i++) { - apr_table_unset(new->encoding_types, suffix[i].name); - } - - - new->type = add->type ? add->type : base->type; - new->handler = add->handler ? add->handler : base->handler; - new->default_language = add->default_language ? - add->default_language : base->default_language; - - return new; -} - -static const char *add_type(cmd_parms *cmd, void *m_, const char *ct_, - const char *ext) -{ - mime_dir_config *m=m_; - char *ct=apr_pstrdup(cmd->pool,ct_); - - if (*ext == '.') - ++ext; - - ap_str_tolower(ct); - apr_table_setn(m->forced_types, ext, ct); - return NULL; -} - -static const char *add_encoding(cmd_parms *cmd, void *m_, const char *enc_, - const char *ext) -{ - mime_dir_config *m=m_; - char *enc=apr_pstrdup(cmd->pool,enc_); - - if (*ext == '.') - ++ext; - ap_str_tolower(enc); - apr_table_setn(m->encoding_types, ext, enc); - return NULL; -} - -static const char *add_charset(cmd_parms *cmd, void *m_, const char *charset_, - const char *ext) -{ - mime_dir_config *m=m_; - char *charset=apr_pstrdup(cmd->pool,charset_); - - if (*ext == '.') { - ++ext; - } - ap_str_tolower(charset); - apr_table_setn(m->charset_types, ext, charset); - return NULL; -} - -static const char *add_language(cmd_parms *cmd, void *m_, const char *lang_, - const char *ext) -{ - mime_dir_config *m=m_; - char *lang=apr_pstrdup(cmd->pool,lang_); - - if (*ext == '.') { - ++ext; - } - ap_str_tolower(lang); - apr_table_setn(m->language_types, ext, lang); - return NULL; -} - -static const char *add_handler(cmd_parms *cmd, void *m_, const char *hdlr_, - const char *ext) -{ - mime_dir_config *m=m_; - char *hdlr=apr_pstrdup(cmd->pool,hdlr_); - - if (*ext == '.') - ++ext; - ap_str_tolower(hdlr); - apr_table_setn(m->handlers, ext, hdlr); - return NULL; -} - -/* - * Note handler names that should be un-added for this location. This - * will keep the association from being inherited, as well, but not - * from being re-added at a subordinate level. - */ -static const char *remove_handler(cmd_parms *cmd, void *m, const char *ext) -{ - mime_dir_config *mcfg = (mime_dir_config *) m; - attrib_info *suffix; - - if (*ext == '.') { - ++ext; - } - suffix = (attrib_info *) apr_array_push(mcfg->handlers_remove); - suffix->name = apr_pstrdup(cmd->pool, ext); - return NULL; -} - -/* - * Just like the previous function, except that it records encoding - * associations to be undone. - */ -static const char *remove_encoding(cmd_parms *cmd, void *m, const char *ext) -{ - mime_dir_config *mcfg = (mime_dir_config *) m; - attrib_info *suffix; - - if (*ext == '.') { - ++ext; - } - suffix = (attrib_info *) apr_array_push(mcfg->encodings_remove); - suffix->name = apr_pstrdup(cmd->pool, ext); - return NULL; -} - -/* - * Similar to the previous functions, except that it deals with filename - * suffix/MIME-type associations. - */ -static const char *remove_type(cmd_parms *cmd, void *m, const char *ext) -{ - mime_dir_config *mcfg = (mime_dir_config *) m; - attrib_info *suffix; - - if (*ext == '.') { - ++ext; - } - suffix = (attrib_info *) apr_array_push(mcfg->types_remove); - suffix->name = apr_pstrdup(cmd->pool, ext); - return NULL; -} - -/* The sole bit of server configuration that the MIME module has is - * the name of its config file, so... - */ - -static const char *set_types_config(cmd_parms *cmd, void *dummy, - const char *arg) -{ - ap_set_module_config(cmd->server->module_config, &mime_module, - (void *)arg); - return NULL; -} - -static const command_rec mime_cmds[] = -{ -AP_INIT_ITERATE2("AddType", add_type, NULL, OR_FILEINFO, - "a mime type followed by one or more file extensions"), -AP_INIT_ITERATE2("AddEncoding", add_encoding, NULL, OR_FILEINFO, - "an encoding (e.g., gzip), followed by one or more file extensions"), -AP_INIT_ITERATE2("AddCharset", add_charset, NULL, OR_FILEINFO, - "a charset (e.g., iso-2022-jp), followed by one or more file extensions"), -AP_INIT_ITERATE2("AddLanguage", add_language, NULL, OR_FILEINFO, - "a language (e.g., fr), followed by one or more file extensions"), -AP_INIT_ITERATE2("AddHandler", add_handler, NULL, OR_FILEINFO, - "a handler name followed by one or more file extensions"), -AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower, - (void *)XtOffsetOf(mime_dir_config, type), OR_FILEINFO, - "a media type"), -AP_INIT_ITERATE("RemoveHandler", remove_handler, NULL, OR_FILEINFO, - "one or more file extensions"), -AP_INIT_ITERATE("RemoveEncoding", remove_encoding, NULL, OR_FILEINFO, - "one or more file extensions"), -AP_INIT_ITERATE("RemoveType", remove_type, NULL, OR_FILEINFO, - "one or more file extensions"), -AP_INIT_TAKE1("SetHandler", ap_set_string_slot_lower, - (void *)XtOffsetOf(mime_dir_config, handler), OR_FILEINFO, - "a handler name"), -AP_INIT_TAKE1("TypesConfig", set_types_config, NULL, RSRC_CONF, - "the MIME types config file"), -AP_INIT_TAKE1("DefaultLanguage", ap_set_string_slot, - (void*)XtOffsetOf(mime_dir_config, default_language), OR_FILEINFO, - "language to use for documents with no other language file extension"), - {NULL} -}; - -/* Hash apr_table_t --- only one of these per daemon; virtual hosts can - * get private versions through AddType... - */ - -#define MIME_HASHSIZE (32) -#define hash(i) (apr_tolower(i) % MIME_HASHSIZE) - -static apr_table_t *hash_buckets[MIME_HASHSIZE]; - -static void mime_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - ap_configfile_t *f; - char l[MAX_STRING_LEN]; - int x; - const char *types_confname = ap_get_module_config(s->module_config, &mime_module); - apr_status_t status; - - if (!types_confname) - types_confname = AP_TYPES_CONFIG_FILE; - - types_confname = ap_server_root_relative(p, types_confname); - - if ((status = ap_pcfg_openfile(&f, p, types_confname)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, status, s, - "could not open mime types config file %s.", types_confname); - exit(1); - } - - for (x = 0; x < MIME_HASHSIZE; x++) - hash_buckets[x] = apr_table_make(p, 10); - - while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) { - const char *ll = l, *ct; - - if (l[0] == '#') - continue; - ct = ap_getword_conf(p, &ll); - - while (ll[0]) { - char *ext = ap_getword_conf(p, &ll); - ap_str_tolower(ext); /* ??? */ - apr_table_setn(hash_buckets[hash(ext[0])], ext, ct); - } - } - ap_cfg_closefile(f); -} - -static char *zap_sp(char *s) -{ - char *tp; - - if (s == NULL) { - return (NULL); - } - if (*s == '\0') { - return (s); - } - - /* delete prefixed white space */ - for (; *s == ' ' || *s == '\t' || *s == '\n'; s++); - - /* delete postfixed white space */ - for (tp = s; *tp != '\0'; tp++); - for (tp--; tp != s && (*tp == ' ' || *tp == '\t' || *tp == '\n'); tp--) { - *tp = '\0'; - } - return (s); -} - -static int is_token(char c) -{ - int res; - - res = (apr_isascii(c) && apr_isgraph(c) - && (strchr(tspecial, c) == NULL)) ? 1 : -1; - return res; -} - -static int is_qtext(char c) -{ - int res; - - res = (apr_isascii(c) && (c != '"') && (c != '\\') && (c != '\n')) - ? 1 : -1; - return res; -} - -static int is_quoted_pair(char *s) -{ - int res = -1; - int c; - - if (((s + 1) != NULL) && (*s == '\\')) { - c = (int) *(s + 1); - if (apr_isascii(c)) { - res = 1; - } - } - return (res); -} - -static content_type *analyze_ct(request_rec *r, char *s) -{ - char *tp, *mp, *cp; - char *attribute, *value; - int quoted = 0; - server_rec * ss = r->server; - apr_pool_t * p = r->pool; - - content_type *ctp; - param *pp, *npp; - - /* initialize ctp */ - ctp = (content_type *) apr_palloc(p, sizeof(content_type)); - ctp->type = NULL; - ctp->subtype = NULL; - ctp->param = NULL; - - tp = apr_pstrdup(p, s); - - mp = tp; - cp = mp; - - /* getting a type */ - if (!(cp = strchr(mp, '/'))) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, - "mod_mime: analyze_ct: cannot get media type from '%s'", - (const char *) mp); - return (NULL); - } - ctp->type = apr_pstrndup(p, mp, cp - mp); - ctp->type = zap_sp(ctp->type); - if (ctp->type == NULL || *(ctp->type) == '\0' || - strchr(ctp->type, ';') || strchr(ctp->type, ' ') || - strchr(ctp->type, '\t')) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, - "Cannot get media subtype."); - return (NULL); - } - - /* getting a subtype */ - cp++; - mp = cp; - - for (; *cp != ';' && *cp != '\0'; cp++) - continue; - ctp->subtype = apr_pstrndup(p, mp, cp - mp); - ctp->subtype = zap_sp(ctp->subtype); - if ((ctp->subtype == NULL) || (*(ctp->subtype) == '\0') || - strchr(ctp->subtype, ' ') || strchr(ctp->subtype, '\t')) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, - "Cannot get media subtype."); - return (NULL); - } - cp = zap_sp(cp); - if (cp == NULL || *cp == '\0') { - return (ctp); - } - - /* getting parameters */ - cp++; - cp = zap_sp(cp); - if (cp == NULL || *cp == '\0') { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, - "Cannot get media parameter."); - return (NULL); - } - mp = cp; - attribute = NULL; - value = NULL; - - while (cp != NULL && *cp != '\0') { - if (attribute == NULL) { - if (is_token(*cp) > 0) { - cp++; - continue; - } - else if (*cp == ' ' || *cp == '\t' || *cp == '\n') { - cp++; - continue; - } - else if (*cp == '=') { - attribute = apr_pstrndup(p, mp, cp - mp); - attribute = zap_sp(attribute); - if (attribute == NULL || *attribute == '\0') { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, - "Cannot get media parameter."); - return (NULL); - } - cp++; - cp = zap_sp(cp); - if (cp == NULL || *cp == '\0') { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, - "Cannot get media parameter."); - return (NULL); - } - mp = cp; - continue; - } - else { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, - "Cannot get media parameter."); - return (NULL); - } - } - else { - if (mp == cp) { - if (*cp == '"') { - quoted = 1; - cp++; - } - else { - quoted = 0; - } - } - if (quoted > 0) { - while (quoted && *cp != '\0') { - if (is_qtext(*cp) > 0) { - cp++; - } - else if (is_quoted_pair(cp) > 0) { - cp += 2; - } - else if (*cp == '"') { - cp++; - while (*cp == ' ' || *cp == '\t' || *cp == '\n') { - cp++; - } - if (*cp != ';' && *cp != '\0') { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, - "Cannot get media parameter."); - return(NULL); - } - quoted = 0; - } - else { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, - "Cannot get media parameter."); - return (NULL); - } - } - } - else { - while (1) { - if (is_token(*cp) > 0) { - cp++; - } - else if (*cp == '\0' || *cp == ';') { - break; - } - else { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, - "Cannot get media parameter."); - return (NULL); - } - } - } - value = apr_pstrndup(p, mp, cp - mp); - value = zap_sp(value); - if (value == NULL || *value == '\0') { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, - "Cannot get media parameter."); - return (NULL); - } - - pp = apr_palloc(p, sizeof(param)); - pp->attr = attribute; - pp->val = value; - pp->next = NULL; - - if (ctp->param == NULL) { - ctp->param = pp; - } - else { - npp = ctp->param; - while (npp->next) { - npp = npp->next; - } - npp->next = pp; - } - quoted = 0; - attribute = NULL; - value = NULL; - if (*cp == '\0') { - break; - } - cp++; - mp = cp; - } - } - return (ctp); -} - -static int find_ct(request_rec *r) -{ - const char *fn = strrchr(r->filename, '/'); - mime_dir_config *conf = - (mime_dir_config *) ap_get_module_config(r->per_dir_config, &mime_module); - char *ext; - const char *orighandler = r->handler; - const char *type; - const char *charset = NULL; - - if (r->finfo.filetype == APR_DIR) { - r->content_type = DIR_MAGIC_TYPE; - return OK; - } - - /* TM -- FIXME - * if r->filename does not contain a '/', the following passes a null - * pointer to getword, causing a SEGV .. - */ - - if (fn == NULL) { - fn = r->filename; - } - - /* Parse filename extensions, which can be in any order */ - while ((ext = ap_getword(r->pool, &fn, '.')) && *ext) { - int found = 0; - - /* Check for Content-Type */ - if ((type = apr_table_get(conf->forced_types, ext)) - || (type = apr_table_get(hash_buckets[hash(*ext)], ext))) { - r->content_type = type; - found = 1; - } - - /* Add charset to Content-Type */ - if ((type = apr_table_get(conf->charset_types, ext))) { - charset = type; - found = 1; - } - - /* Check for Content-Language */ - if ((type = apr_table_get(conf->language_types, ext))) { - const char **new; - - r->content_language = type; /* back compat. only */ - if (!r->content_languages) - r->content_languages = apr_array_make(r->pool, 2, sizeof(char *)); - new = (const char **) apr_array_push(r->content_languages); - *new = type; - found = 1; - } - - /* Check for Content-Encoding */ - if ((type = apr_table_get(conf->encoding_types, ext))) { - if (!r->content_encoding) - r->content_encoding = type; - else - r->content_encoding = apr_pstrcat(r->pool, r->content_encoding, - ", ", type, NULL); - found = 1; - } - - /* Check for a special handler, but not for proxy request */ - if ((type = apr_table_get(conf->handlers, ext)) - && (PROXYREQ_NONE == r->proxyreq) - ) { - r->handler = type; - found = 1; - } - - /* This is to deal with cases such as foo.gif.bak, which we want - * to not have a type. So if we find an unknown extension, we - * zap the type/language/encoding and reset the handler - */ - - if (!found) { - r->content_type = NULL; - r->content_language = NULL; - r->content_languages = NULL; - r->content_encoding = NULL; - r->handler = orighandler; - charset = NULL; - } - } - - if (r->content_type) { - content_type *ctp; - char *ct; - int override = 0; - - ct = (char *) apr_palloc(r->pool, - sizeof(char) * (strlen(r->content_type) + 1)); - strcpy(ct, r->content_type); - - if ((ctp = analyze_ct(r, ct))) { - param *pp = ctp->param; - r->content_type = apr_pstrcat(r->pool, ctp->type, "/", - ctp->subtype, NULL); - while (pp != NULL) { - if (charset && !strcmp(pp->attr, "charset")) { - if (!override) { - r->content_type = apr_pstrcat(r->pool, r->content_type, - "; charset=", charset, - NULL); - override = 1; - } - } - else { - r->content_type = apr_pstrcat(r->pool, r->content_type, - "; ", pp->attr, - "=", pp->val, - NULL); - } - pp = pp->next; - } - if (charset && !override) { - r->content_type = apr_pstrcat(r->pool, r->content_type, - "; charset=", charset, - NULL); - } - } - } - - /* Set default language, if none was specified by the extensions - * and we have a DefaultLanguage setting in force - */ - - if (!r->content_languages && conf->default_language) { - const char **new; - - r->content_language = conf->default_language; /* back compat. only */ - if (!r->content_languages) - r->content_languages = apr_array_make(r->pool, 2, sizeof(char *)); - new = (const char **) apr_array_push(r->content_languages); - *new = conf->default_language; - } - - /* Check for overrides with ForceType/SetHandler */ - - if (conf->type && strcmp(conf->type, "none")) - r->content_type = conf->type; - if (conf->handler && strcmp(conf->handler, "none")) - r->handler = conf->handler; - - if (!r->content_type) - return DECLINED; - - return OK; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_type_checker(find_ct,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_post_config(mime_post_config,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA mime_module = { - STANDARD20_MODULE_STUFF, - create_mime_dir_config, /* create per-directory config structure */ - merge_mime_dir_configs, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - mime_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/http/mod_mime.exp b/modules/http/mod_mime.exp deleted file mode 100644 index f2e38dbdda..0000000000 --- a/modules/http/mod_mime.exp +++ /dev/null @@ -1 +0,0 @@ -mime_module diff --git a/modules/loggers/.cvsignore b/modules/loggers/.cvsignore deleted file mode 100644 index 65f0cc30cf..0000000000 --- a/modules/loggers/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -.deps -.libs -*.la -modules.mk -Makefile -*.lo -*.slo -*.so -Debug -Release diff --git a/modules/loggers/.indent.pro b/modules/loggers/.indent.pro deleted file mode 100644 index a9fbe9f9a1..0000000000 --- a/modules/loggers/.indent.pro +++ /dev/null @@ -1,54 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 --TBUFF --TFILE --TTRANS --TUINT4 --T_trans --Tallow_options_t --Tapache_sfio --Tarray_header --Tbool_int --Tbuf_area --Tbuff_struct --Tbuffy --Tcmd_how --Tcmd_parms --Tcommand_rec --Tcommand_struct --Tconn_rec --Tcore_dir_config --Tcore_server_config --Tdir_maker_func --Tevent --Tglobals_s --Thandler_func --Thandler_rec --Tjoblist_s --Tlisten_rec --Tmerger_func --Tmode_t --Tmodule --Tmodule_struct --Tmutex --Tn_long --Tother_child_rec --Toverrides_t --Tparent_score --Tpid_t --Tpiped_log --Tpool --Trequest_rec --Trequire_line --Trlim_t --Tscoreboard --Tsemaphore --Tserver_addr_rec --Tserver_rec --Tserver_rec_chain --Tshort_score --Ttable --Ttable_entry --Tthread --Tu_wide_int --Tvtime_t --Twide_int diff --git a/modules/loggers/Makefile.in b/modules/loggers/Makefile.in deleted file mode 100644 index 167b343d0d..0000000000 --- a/modules/loggers/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ - -include $(top_srcdir)/build/special.mk - diff --git a/modules/loggers/config.m4 b/modules/loggers/config.m4 deleted file mode 100644 index 8d4304abc4..0000000000 --- a/modules/loggers/config.m4 +++ /dev/null @@ -1,9 +0,0 @@ -dnl modules enabled in this directory by default - -dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]]) - -APACHE_MODPATH_INIT(loggers) - -APACHE_MODULE(log_config, logging configuration, , , yes) - -APACHE_MODPATH_FINISH diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c deleted file mode 100644 index c2b655c455..0000000000 --- a/modules/loggers/mod_log_config.c +++ /dev/null @@ -1,1229 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * Modified by djm@va.pubnix.com: - * If no TransferLog is given explicitly, decline to log. - * - * This is module implements the TransferLog directive (same as the - * common log module), and additional directives, LogFormat and CustomLog. - * - * - * Syntax: - * - * TransferLog fn Logs transfers to fn in standard log format, unless - * a custom format is set with LogFormat - * LogFormat format Set a log format from TransferLog files - * CustomLog fn format - * Log to file fn with format given by the format - * argument - * - * CookieLog fn For backwards compatability with old Cookie - * logging module - now deprecated. - * - * There can be any number of TransferLog and CustomLog - * commands. Each request will be logged to _ALL_ the - * named files, in the appropriate format. - * - * If no TransferLog or CustomLog directive appears in a VirtualHost, - * the request will be logged to the log file(s) defined outside - * the virtual host section. If a TransferLog or CustomLog directive - * appears in the VirtualHost section, the log files defined outside - * the VirtualHost will _not_ be used. This makes this module compatable - * with the CLF and config log modules, where the use of TransferLog - * inside the VirtualHost section overrides its use outside. - * - * Examples: - * - * TransferLog logs/access_log - * <VirtualHost> - * LogFormat "... custom format ..." - * TransferLog log/virtual_only - * CustomLog log/virtual_useragents "%t %{user-agent}i" - * </VirtualHost> - * - * This will log using CLF to access_log any requests handled by the - * main server, while any requests to the virtual host will be logged - * with the "... custom format..." to virtual_only _AND_ using - * the custom user-agent log to virtual_useragents. - * - * Note that the NCSA referer and user-agent logs are easily added with - * CustomLog: - * CustomLog logs/referer "%{referer}i -> %U" - * CustomLog logs/agent "%{user-agent}i" - * - * RefererIgnore functionality can be obtained with conditional - * logging (SetEnvIf and CustomLog ... env=!VAR). - * - * But using this method allows much easier modification of the - * log format, e.g. to log hosts along with UA: - * CustomLog logs/referer "%{referer}i %U %h" - * - * The argument to LogFormat and CustomLog is a string, which can include - * literal characters copied into the log files, and '%' directives as - * follows: - * - * %...B: bytes sent, excluding HTTP headers. - * %...b: bytes sent, excluding HTTP headers in CLF format, i.e. a '-' - * when no bytes where sent (rather than a '0'. - * %...c: Status of the connection. - * 'X' = connection aborted before the response completed. - * '+' = connection may be kept alive after the response is sent. - * '-' = connection will be closed after the response is sent. - * %...{FOOBAR}C: The contents of the HTTP cookie FOOBAR - * %...{FOOBAR}e: The contents of the environment variable FOOBAR - * %...f: filename - * %...h: remote host - * %...a: remote IP-address - * %...A: local IP-address - * %...{Foobar}i: The contents of Foobar: header line(s) in the request - * sent to the client. - * %...l: remote logname (from identd, if supplied) - * %...{Foobar}n: The contents of note "Foobar" from another module. - * %...{Foobar}o: The contents of Foobar: header line(s) in the reply. - * %...p: the port the request was served to - * %...P: the process ID of the child that serviced the request. - * %...r: first line of request - * %...s: status. For requests that got internally redirected, this - * is status of the *original* request --- %...>s for the last. - * %...t: time, in common log format time format - * %...{format}t: The time, in the form given by format, which should - * be in strftime(3) format. - * %...T: the time taken to serve the request, in seconds. - * %...D: the time taken to serve the request, in micro seconds. - * %...u: remote user (from auth; may be bogus if return status (%s) is 401) - * %...U: the URL path requested. - * %...v: the configured name of the server (i.e. which virtual host?) - * %...V: the server name according to the UseCanonicalName setting - * %...m: the request method - * %...H: the request protocol - * %...q: the query string prepended by "?", or empty if no query string - * - * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can - * indicate conditions for inclusion of the item (which will cause it - * to be replaced with '-' if the condition is not met). Note that - * there is no escaping performed on the strings from %r, %...i and - * %...o; some with long memories may remember that I thought this was - * a bad idea, once upon a time, and I'm still not comfortable with - * it, but it is difficult to see how to "do the right thing" with all - * of '%..i', unless we URL-escape everything and break with CLF. - * - * The forms of condition are a list of HTTP status codes, which may - * or may not be preceded by '!'. Thus, '%400,501{User-agent}i' logs - * User-agent: on 400 errors and 501 errors (Bad Request, Not - * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all - * requests which did *not* return some sort of normal status. - * - * The default LogFormat reproduces CLF; see below. - * - * The way this is supposed to work with virtual hosts is as follows: - * a virtual host can have its own LogFormat, or its own TransferLog. - * If it doesn't have its own LogFormat, it inherits from the main - * server. If it doesn't have its own TransferLog, it writes to the - * same descriptor (meaning the same process for "| ..."). - * - * --- rst */ - -#include "apr_strings.h" -#include "apr_lib.h" -#include "apr_hash.h" -#include "apr_optional.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "ap_config.h" -#include "mod_log_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" /* For REMOTE_NAME */ -#include "http_log.h" -#include "http_protocol.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_LIMITS_H -#include <limits.h> -#endif - -#define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b" - -module AP_MODULE_DECLARE_DATA log_config_module; - -static int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE); -static apr_fileperms_t xfer_perms = APR_OS_DEFAULT; -static apr_hash_t *log_hash; - -/* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is - * guaranteed to be atomic when writing a pipe. And PIPE_BUF >= 512 - * is guaranteed. So we'll just guess 512 in the event the system - * doesn't have this. Now, for file writes there is actually no limit, - * the entire write is atomic. Whether all systems implement this - * correctly is another question entirely ... so we'll just use PIPE_BUF - * because it's probably a good guess as to what is implemented correctly - * everywhere. - */ -#ifdef PIPE_BUF -#define LOG_BUFSIZE PIPE_BUF -#else -#define LOG_BUFSIZE (512) -#endif - -/* - * multi_log_state is our per-(virtual)-server configuration. We store - * an array of the logs we are going to use, each of type config_log_state. - * If a default log format is given by LogFormat, store in default_format - * (backward compat. with mod_log_config). We also store for each virtual - * server a pointer to the logs specified for the main server, so that if this - * vhost has no logs defined, we can use the main server's logs instead. - * - * So, for the main server, config_logs contains a list of the log files - * and server_config_logs in empty. For a vhost, server_config_logs - * points to the same array as config_logs in the main server, and - * config_logs points to the array of logs defined inside this vhost, - * which might be empty. - */ - -typedef struct { - const char *default_format_string; - apr_array_header_t *default_format; - apr_array_header_t *config_logs; - apr_array_header_t *server_config_logs; - apr_table_t *formats; -} multi_log_state; - -/* - * config_log_state holds the status of a single log file. fname might - * be NULL, which means this module does no logging for this - * request. format might be NULL, in which case the default_format - * from the multi_log_state should be used, or if that is NULL as - * well, use the CLF. log_fd is NULL before the log file is opened and - * set to a valid fd after it is opened. - */ - -typedef struct { - const char *fname; - const char *format_string; - apr_array_header_t *format; - apr_file_t *log_fd; - char *condition_var; -#ifdef BUFFERED_LOGS - apr_size_t outcnt; - char outbuf[LOG_BUFSIZE]; -#endif -} config_log_state; - -/* - * Format items... - * Note that many of these could have ap_sprintfs replaced with static buffers. - */ - -typedef struct { - ap_log_handler_fn_t *func; - char *arg; - int condition_sense; - int want_orig; - apr_array_header_t *conditions; -} log_format_item; - -static char *format_integer(apr_pool_t *p, int i) -{ - return apr_psprintf(p, "%d", i); -} - -static char *pfmt(apr_pool_t *p, int i) -{ - if (i <= 0) { - return "-"; - } - else { - return format_integer(p, i); - } -} - -static const char *constant_item(request_rec *dummy, char *stuff) -{ - return stuff; -} - -static const char *log_remote_host(request_rec *r, char *a) -{ - return ap_get_remote_host(r->connection, r->per_dir_config, - REMOTE_NAME, NULL); -} - -static const char *log_remote_address(request_rec *r, char *a) -{ - return r->connection->remote_ip; -} - -static const char *log_local_address(request_rec *r, char *a) -{ - return r->connection->local_ip; -} - -static const char *log_remote_logname(request_rec *r, char *a) -{ - return ap_get_remote_logname(r); -} - -static const char *log_remote_user(request_rec *r, char *a) -{ - char *rvalue = r->user; - - if (rvalue == NULL) { - rvalue = "-"; - } - else if (strlen(rvalue) == 0) { - rvalue = "\"\""; - } - return rvalue; -} - -static const char *log_request_line(request_rec *r, char *a) -{ - /* NOTE: If the original request contained a password, we - * re-write the request line here to contain XXXXXX instead: - * (note the truncation before the protocol string for HTTP/0.9 requests) - * (note also that r->the_request contains the unmodified request) - */ - return (r->parsed_uri.password) ? apr_pstrcat(r->pool, r->method, " ", - ap_unparse_uri_components(r->pool, &r->parsed_uri, 0), - r->assbackwards ? NULL : " ", r->protocol, NULL) - : r->the_request; -} - -static const char *log_request_file(request_rec *r, char *a) -{ - return r->filename; -} -static const char *log_request_uri(request_rec *r, char *a) -{ - return r->uri; -} -static const char *log_request_method(request_rec *r, char *a) -{ - return r->method; -} -static const char *log_request_protocol(request_rec *r, char *a) -{ - return r->protocol; -} -static const char *log_request_query(request_rec *r, char *a) -{ - return (r->args != NULL) ? apr_pstrcat(r->pool, "?", r->args, NULL) - : ""; -} -static const char *log_status(request_rec *r, char *a) -{ - return pfmt(r->pool, r->status); -} - -static const char *clf_log_bytes_sent(request_rec *r, char *a) -{ - if (!r->sent_bodyct) { - return "-"; - } - else { - return apr_psprintf(r->pool, "%ld", r->bytes_sent); - } -} - -static const char *log_bytes_sent(request_rec *r, char *a) -{ - if (!r->sent_bodyct) { - return "0"; - } - else { - return apr_psprintf(r->pool, "%ld", r->bytes_sent); - } -} - - -static const char *log_header_in(request_rec *r, char *a) -{ - return apr_table_get(r->headers_in, a); -} - -static const char *log_header_out(request_rec *r, char *a) -{ - const char *cp = apr_table_get(r->headers_out, a); - if (!strcasecmp(a, "Content-type") && r->content_type) { - cp = ap_field_noparam(r->pool, r->content_type); - } - if (cp) { - return cp; - } - return apr_table_get(r->err_headers_out, a); -} - -static const char *log_note(request_rec *r, char *a) -{ - return apr_table_get(r->notes, a); -} -static const char *log_env_var(request_rec *r, char *a) -{ - return apr_table_get(r->subprocess_env, a); -} - -static const char *log_cookie(request_rec *r, char *a) -{ - const char *cookies; - const char *start_cookie; - - if ((cookies = apr_table_get(r->headers_in, "Cookie"))) { - if ((start_cookie = ap_strstr_c(cookies,a))) { - char *cookie, *end_cookie; - start_cookie += strlen(a) + 1; /* cookie_name + '=' */ - cookie = apr_pstrdup(r->pool, start_cookie); - /* kill everything in cookie after ';' */ - end_cookie = strchr(cookie, ';'); - if (end_cookie) { - *end_cookie = '\0'; - } - return cookie; - } - } - return NULL; -} - -static const char *log_request_time(request_rec *r, char *a) -{ - apr_exploded_time_t xt; - apr_size_t retcode; - char tstr[MAX_STRING_LEN]; - - /* - hi. i think getting the time again at the end of the request - just for logging is dumb. i know it's "required" for CLF. - folks writing log parsing tools don't realise that out of order - times have always been possible (consider what happens if one - process calculates the time to log, but then there's a context - switch before it writes and before that process is run again the - log rotation occurs) and they should just fix their tools rather - than force the server to pay extra cpu cycles. if you've got - a problem with this, you can set the define. -djg - */ -#ifdef I_INSIST_ON_EXTRA_CYCLES_FOR_CLF_COMPLIANCE - apr_explode_localtime(&xt, apr_time_now()); -#else - apr_explode_localtime(&xt, r->request_time); -#endif - if (a && *a) { /* Custom format */ - apr_strftime(tstr, &retcode, MAX_STRING_LEN, a, &xt); - } - else { /* CLF format */ - char sign; - int timz; - - timz = xt.tm_gmtoff; - if (timz < 0) { - timz = -timz; - sign = '-'; - } - else { - sign = '+'; - } - - apr_snprintf(tstr, sizeof(tstr), "[%02d/%s/%d:%02d:%02d:%02d %c%.2d%.2d]", - xt.tm_mday, apr_month_snames[xt.tm_mon], xt.tm_year+1900, - xt.tm_hour, xt.tm_min, xt.tm_sec, - sign, timz / (60*60), timz % (60*60)); - } - - return apr_pstrdup(r->pool, tstr); -} - -static const char *log_request_duration(request_rec *r, char *a) -{ - return apr_psprintf(r->pool, "%qd", (apr_time_now() - r->request_time) - / APR_USEC_PER_SEC); -} - -static const char *log_request_duration_microseconds(request_rec *r, char *a) -{ - return apr_psprintf(r->pool, "%qd", (apr_time_now() - r->request_time)); -} - -/* These next two routines use the canonical name:port so that log - * parsers don't need to duplicate all the vhost parsing crud. - */ -static const char *log_virtual_host(request_rec *r, char *a) -{ - return r->server->server_hostname; -} - -static const char *log_server_port(request_rec *r, char *a) -{ - return apr_psprintf(r->pool, "%u", - r->server->port ? r->server->port : ap_default_port(r)); -} - -/* This respects the setting of UseCanonicalName so that - * the dynamic mass virtual hosting trick works better. - */ -static const char *log_server_name(request_rec *r, char *a) -{ - return ap_get_server_name(r); -} - -static const char *log_child_pid(request_rec *r, char *a) -{ - return apr_psprintf(r->pool, "%ld", (long) getpid()); -} - -static const char *log_connection_status(request_rec *r, char *a) -{ - if (r->connection->aborted) - return "X"; - - if (r->connection->keepalive && - (!r->server->keep_alive_max || - (r->server->keep_alive_max - r->connection->keepalives) > 0)) { - return "+"; - } - return "-"; -} - -/***************************************************************** - * - * Parsing the log format string - */ - -static char *parse_log_misc_string(apr_pool_t *p, log_format_item *it, - const char **sa) -{ - const char *s; - char *d; - - it->func = constant_item; - it->conditions = NULL; - - s = *sa; - while (*s && *s != '%') { - s++; - } - /* - * This might allocate a few chars extra if there's a backslash - * escape in the format string. - */ - it->arg = apr_palloc(p, s - *sa + 1); - - d = it->arg; - s = *sa; - while (*s && *s != '%') { - if (*s != '\\') { - *d++ = *s++; - } - else { - s++; - switch (*s) { - case '\\': - *d++ = '\\'; - s++; - break; - case 'r': - *d++ = '\r'; - s++; - break; - case 'n': - *d++ = '\n'; - s++; - break; - case 't': - *d++ = '\t'; - s++; - break; - default: - /* copy verbatim */ - *d++ = '\\'; - /* - * Allow the loop to deal with this *s in the normal - * fashion so that it handles end of string etc. - * properly. - */ - break; - } - } - } - *d = '\0'; - - *sa = s; - return NULL; -} - -static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa) -{ - const char *s = *sa; - ap_log_handler *handler; - - if (*s != '%') { - return parse_log_misc_string(p, it, sa); - } - - ++s; - it->condition_sense = 0; - it->conditions = NULL; - it->want_orig = -1; - it->arg = ""; /* For safety's sake... */ - - while (*s) { - int i; - - switch (*s) { - case '!': - ++s; - it->condition_sense = !it->condition_sense; - break; - - case '<': - ++s; - it->want_orig = 1; - break; - - case '>': - ++s; - it->want_orig = 0; - break; - - case ',': - ++s; - break; - - case '{': - ++s; - it->arg = ap_getword(p, &s, '}'); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - i = *s - '0'; - while (apr_isdigit(*++s)) { - i = i * 10 + (*s) - '0'; - } - if (!it->conditions) { - it->conditions = apr_array_make(p, 4, sizeof(int)); - } - *(int *) apr_array_push(it->conditions) = i; - break; - - default: - handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1); - if (!handler) { - char dummy[2]; - - dummy[0] = s[-1]; - dummy[1] = '\0'; - return apr_pstrcat(p, "Unrecognized LogFormat directive %", - dummy, NULL); - } - it->func = handler->func; - if (it->want_orig == -1) { - it->want_orig = handler->want_orig_default; - } - *sa = s; - return NULL; - } - } - - return "Ran off end of LogFormat parsing args to some directive"; -} - -static apr_array_header_t *parse_log_string(apr_pool_t *p, const char *s, const char **err) -{ - apr_array_header_t *a = apr_array_make(p, 30, sizeof(log_format_item)); - char *res; - - while (*s) { - if ((res = parse_log_item(p, (log_format_item *) apr_array_push(a), &s))) { - *err = res; - return NULL; - } - } - - s = APR_EOL_STR; - parse_log_item(p, (log_format_item *) apr_array_push(a), &s); - return a; -} - -/***************************************************************** - * - * Actually logging. - */ - -static const char *process_item(request_rec *r, request_rec *orig, - log_format_item *item) -{ - const char *cp; - - /* First, see if we need to process this thing at all... */ - - if (item->conditions && item->conditions->nelts != 0) { - int i; - int *conds = (int *) item->conditions->elts; - int in_list = 0; - - for (i = 0; i < item->conditions->nelts; ++i) { - if (r->status == conds[i]) { - in_list = 1; - break; - } - } - - if ((item->condition_sense && in_list) - || (!item->condition_sense && !in_list)) { - return "-"; - } - } - - /* We do. Do it... */ - - cp = (*item->func) (item->want_orig ? orig : r, item->arg); - return cp ? cp : "-"; -} - -#ifdef BUFFERED_LOGS -static void flush_log(config_log_state *cls) -{ - if (cls->outcnt && cls->log_fd != NULL) { - apr_file_write(cls->log_fd, cls->outbuf, &cls->outcnt); - cls->outcnt = 0; - } -} -#endif - -static int config_log_transaction(request_rec *r, config_log_state *cls, - apr_array_header_t *default_format) -{ - log_format_item *items; - char *str, *s; - const char **strs; - int *strl; - request_rec *orig; - int i; - apr_size_t len = 0; - apr_array_header_t *format; - char *envar; - - if (cls->fname == NULL) { - return DECLINED; - } - - /* - * See if we've got any conditional envariable-controlled logging decisions - * to make. - */ - if (cls->condition_var != NULL) { - envar = cls->condition_var; - if (*envar != '!') { - if (apr_table_get(r->subprocess_env, envar) == NULL) { - return DECLINED; - } - } - else { - if (apr_table_get(r->subprocess_env, &envar[1]) != NULL) { - return DECLINED; - } - } - } - - format = cls->format ? cls->format : default_format; - - strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts)); - strl = apr_palloc(r->pool, sizeof(int) * (format->nelts)); - items = (log_format_item *) format->elts; - - orig = r; - while (orig->prev) { - orig = orig->prev; - } - while (r->next) { - r = r->next; - } - - for (i = 0; i < format->nelts; ++i) { - strs[i] = process_item(r, orig, &items[i]); - } - - for (i = 0; i < format->nelts; ++i) { - len += strl[i] = strlen(strs[i]); - } - -#ifdef BUFFERED_LOGS - if (len + cls->outcnt > LOG_BUFSIZE) { - flush_log(cls); - } - if (len >= LOG_BUFSIZE) { - apr_size_t w; - - str = apr_palloc(r->pool, len + 1); - for (i = 0, s = str; i < format->nelts; ++i) { - memcpy(s, strs[i], strl[i]); - s += strl[i]; - } - w = len; - apr_file_write(cls->log_fd, str, &w); - } - else { - for (i = 0, s = &cls->outbuf[cls->outcnt]; i < format->nelts; ++i) { - memcpy(s, strs[i], strl[i]); - s += strl[i]; - } - cls->outcnt += len; - } -#else - str = apr_palloc(r->pool, len + 1); - - for (i = 0, s = str; i < format->nelts; ++i) { - memcpy(s, strs[i], strl[i]); - s += strl[i]; - } - - apr_file_write(cls->log_fd, str, &len); -#endif - - return OK; -} - -static int multi_log_transaction(request_rec *r) -{ - multi_log_state *mls = ap_get_module_config(r->server->module_config, - &log_config_module); - config_log_state *clsarray; - int i; - - /* - * Log this transaction.. - */ - if (mls->config_logs->nelts) { - clsarray = (config_log_state *) mls->config_logs->elts; - for (i = 0; i < mls->config_logs->nelts; ++i) { - config_log_state *cls = &clsarray[i]; - - config_log_transaction(r, cls, mls->default_format); - } - } - else if (mls->server_config_logs) { - clsarray = (config_log_state *) mls->server_config_logs->elts; - for (i = 0; i < mls->server_config_logs->nelts; ++i) { - config_log_state *cls = &clsarray[i]; - - config_log_transaction(r, cls, mls->default_format); - } - } - - return OK; -} - -/***************************************************************** - * - * Module glue... - */ - -static void *make_config_log_state(apr_pool_t *p, server_rec *s) -{ - multi_log_state *mls; - - mls = (multi_log_state *) apr_palloc(p, sizeof(multi_log_state)); - mls->config_logs = apr_array_make(p, 1, sizeof(config_log_state)); - mls->default_format_string = NULL; - mls->default_format = NULL; - mls->server_config_logs = NULL; - mls->formats = apr_table_make(p, 4); - apr_table_setn(mls->formats, "CLF", DEFAULT_LOG_FORMAT); - - return mls; -} - -/* - * Use the merger to simply add a pointer from the vhost log state - * to the log of logs specified for the non-vhost configuration. Make sure - * vhosts inherit any globally-defined format names. - */ - -static void *merge_config_log_state(apr_pool_t *p, void *basev, void *addv) -{ - multi_log_state *base = (multi_log_state *) basev; - multi_log_state *add = (multi_log_state *) addv; - - add->server_config_logs = base->config_logs; - if (!add->default_format) { - add->default_format_string = base->default_format_string; - add->default_format = base->default_format; - } - add->formats = apr_table_overlay(p, base->formats, add->formats); - - return add; -} - -/* - * Set the default logfile format, or define a nickname for a format string. - */ -static const char *log_format(cmd_parms *cmd, void *dummy, const char *fmt, - const char *name) -{ - const char *err_string = NULL; - multi_log_state *mls = ap_get_module_config(cmd->server->module_config, - &log_config_module); - - /* - * If we were given two arguments, the second is a name to be given to the - * format. This syntax just defines the nickname - it doesn't actually - * make the format the default. - */ - if (name != NULL) { - parse_log_string(cmd->pool, fmt, &err_string); - if (err_string == NULL) { - apr_table_setn(mls->formats, name, fmt); - } - } - else { - mls->default_format_string = fmt; - mls->default_format = parse_log_string(cmd->pool, fmt, &err_string); - } - return err_string; -} - - -static const char *add_custom_log(cmd_parms *cmd, void *dummy, const char *fn, - const char *fmt, const char *envclause) -{ - const char *err_string = NULL; - multi_log_state *mls = ap_get_module_config(cmd->server->module_config, - &log_config_module); - config_log_state *cls; - - cls = (config_log_state *) apr_array_push(mls->config_logs); - cls->condition_var = NULL; - if (envclause != NULL) { - if (strncasecmp(envclause, "env=", 4) != 0) { - return "error in condition clause"; - } - if ((envclause[4] == '\0') - || ((envclause[4] == '!') && (envclause[5] == '\0'))) { - return "missing environment variable name"; - } - cls->condition_var = apr_pstrdup(cmd->pool, &envclause[4]); - } - - cls->fname = fn; - cls->format_string = fmt; - if (fmt == NULL) { - cls->format = NULL; - } - else { - cls->format = parse_log_string(cmd->pool, fmt, &err_string); - } - cls->log_fd = NULL; - - return err_string; -} - -static const char *set_transfer_log(cmd_parms *cmd, void *dummy, - const char *fn) -{ - return add_custom_log(cmd, dummy, fn, NULL, NULL); -} - -static const char *set_cookie_log(cmd_parms *cmd, void *dummy, const char *fn) -{ - return add_custom_log(cmd, dummy, fn, "%{Cookie}n \"%r\" %t", NULL); -} - -static const command_rec config_log_cmds[] = -{ -AP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF, - "a file name, a custom log format string or format name, " - "and an optional \"env=\" clause (see docs)"), -AP_INIT_TAKE1("TransferLog", set_transfer_log, NULL, RSRC_CONF, - "the filename of the access log"), -AP_INIT_TAKE12("LogFormat", log_format, NULL, RSRC_CONF, - "a log format string (see docs) and an optional format name"), -AP_INIT_TAKE1("CookieLog", set_cookie_log, NULL, RSRC_CONF, - "the filename of the cookie log"), - {NULL} -}; - -static config_log_state *open_config_log(server_rec *s, apr_pool_t *p, - config_log_state *cls, - apr_array_header_t *default_format) -{ - apr_status_t status; - - if (cls->log_fd != NULL) { - return cls; /* virtual config shared w/main server */ - } - - if (cls->fname == NULL) { - return cls; /* Leave it NULL to decline. */ - } - - if (*cls->fname == '|') { - piped_log *pl; - - pl = ap_open_piped_log(p, cls->fname + 1); - if (pl == NULL) { - exit(1); - } - cls->log_fd = ap_piped_log_write_fd(pl); - } - else { - const char *fname = ap_server_root_relative(p, cls->fname); - if ((status = apr_file_open(&cls->log_fd, fname, xfer_flags, xfer_perms, p)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, status, s, - "could not open transfer log file %s.", fname); - exit(1); - } - } -#ifdef BUFFERED_LOGS - cls->outcnt = 0; -#endif - - return cls; -} - -static config_log_state *open_multi_logs(server_rec *s, apr_pool_t *p) -{ - int i; - multi_log_state *mls = ap_get_module_config(s->module_config, - &log_config_module); - config_log_state *clsarray; - const char *dummy; - const char *format; - - if (mls->default_format_string) { - format = apr_table_get(mls->formats, mls->default_format_string); - if (format) { - mls->default_format = parse_log_string(p, format, &dummy); - } - } - - if (!mls->default_format) { - mls->default_format = parse_log_string(p, DEFAULT_LOG_FORMAT, &dummy); - } - - if (mls->config_logs->nelts) { - clsarray = (config_log_state *) mls->config_logs->elts; - for (i = 0; i < mls->config_logs->nelts; ++i) { - config_log_state *cls = &clsarray[i]; - - if (cls->format_string) { - format = apr_table_get(mls->formats, cls->format_string); - if (format) { - cls->format = parse_log_string(p, format, &dummy); - } - } - - cls = open_config_log(s, p, cls, mls->default_format); - } - } - else if (mls->server_config_logs) { - clsarray = (config_log_state *) mls->server_config_logs->elts; - for (i = 0; i < mls->server_config_logs->nelts; ++i) { - config_log_state *cls = &clsarray[i]; - - if (cls->format_string) { - format = apr_table_get(mls->formats, cls->format_string); - if (format) { - cls->format = parse_log_string(p, format, &dummy); - } - } - - cls = open_config_log(s, p, cls, mls->default_format); - } - } - - return NULL; -} - -#ifdef BUFFERED_LOGS -static apr_status_t flush_all_logs(void *data) -{ - server_rec *s = data; - multi_log_state *mls; - apr_array_header_t *log_list; - config_log_state *clsarray; - int i; - - for (; s; s = s->next) { - mls = ap_get_module_config(s->module_config, &log_config_module); - log_list = NULL; - if (mls->config_logs->nelts) { - log_list = mls->config_logs; - } - else if (mls->server_config_logs) { - log_list = mls->server_config_logs; - } - if (log_list) { - clsarray = (config_log_state *) log_list->elts; - for (i = 0; i < log_list->nelts; ++i) { - flush_log(&clsarray[i]); - } - } - } - return APR_SUCCESS; -} -#endif - -static void init_config_log(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, server_rec *s) -{ - /* First, do "physical" server, which gets default log fd and format - * for the virtual servers, if they don't override... - */ - - open_multi_logs(s, p); - - /* Then, virtual servers */ - - for (s = s->next; s; s = s->next) { - open_multi_logs(s, p); - } -} - -static void init_child(apr_pool_t *p, server_rec *s) -{ -#ifdef BUFFERED_LOGS - /* Now register the last buffer flush with the cleanup engine */ - apr_pool_cleanup_register(p, s, flush_all_logs, flush_all_logs); -#endif -} - -static void ap_register_log_handler(apr_pool_t *p, char *tag, - ap_log_handler_fn_t *handler, int def) -{ - ap_log_handler *log_struct = apr_palloc(p, sizeof(*log_struct)); - log_struct->func = handler; - log_struct->want_orig_default = def; - - apr_hash_set(log_hash, tag, 1, (const void *)log_struct); -} - -static void log_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) -{ - static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register; - - log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler); - - if (log_pfn_register) { - log_pfn_register(p, "h", log_remote_host, 0); - log_pfn_register(p, "a", log_remote_address, 0 ); - log_pfn_register(p, "A", log_local_address, 0 ); - log_pfn_register(p, "l", log_remote_logname, 0); - log_pfn_register(p, "u", log_remote_user, 0); - log_pfn_register(p, "t", log_request_time, 0); - log_pfn_register(p, "f", log_request_file, 0); - log_pfn_register(p, "b", clf_log_bytes_sent, 0); - log_pfn_register(p, "B", log_bytes_sent, 0); - log_pfn_register(p, "i", log_header_in, 0); - log_pfn_register(p, "o", log_header_out, 0); - log_pfn_register(p, "n", log_note, 0); - log_pfn_register(p, "e", log_env_var, 0); - log_pfn_register(p, "V", log_server_name, 0); - log_pfn_register(p, "v", log_virtual_host, 0); - log_pfn_register(p, "p", log_server_port, 0); - log_pfn_register(p, "P", log_child_pid, 0); - log_pfn_register(p, "H", log_request_protocol, 0); - log_pfn_register(p, "m", log_request_method, 0); - log_pfn_register(p, "q", log_request_query, 0); - log_pfn_register(p, "c", log_connection_status, 0); - log_pfn_register(p, "C", log_cookie, 0); - log_pfn_register(p, "r", log_request_line, 1); - log_pfn_register(p, "D", log_request_duration_microseconds, 1); - log_pfn_register(p, "T", log_request_duration, 1); - log_pfn_register(p, "U", log_request_uri, 1); - log_pfn_register(p, "s", log_status, 1); - } -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_pre_config(log_pre_config,NULL,NULL,APR_HOOK_REALLY_FIRST); - ap_hook_child_init(init_child,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_open_logs(init_config_log,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_log_transaction(multi_log_transaction,NULL,NULL,APR_HOOK_MIDDLE); - - /* Init log_hash before we register the optional function. It is - * possible for the optional function, ap_register_log_handler, - * to be called before any other mod_log_config hooks are called. - * As a policy, we should init everything required by an optional function - * before calling APR_REGISTER_OPTIONAL_FN. - */ - log_hash = apr_hash_make(p); - APR_REGISTER_OPTIONAL_FN(ap_register_log_handler); -} - -module AP_MODULE_DECLARE_DATA log_config_module = -{ - STANDARD20_MODULE_STUFF, - NULL, /* create per-dir config */ - NULL, /* merge per-dir config */ - make_config_log_state, /* server config */ - merge_config_log_state, /* merge server config */ - config_log_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/loggers/mod_log_config.exp b/modules/loggers/mod_log_config.exp deleted file mode 100644 index 01b926f4bb..0000000000 --- a/modules/loggers/mod_log_config.exp +++ /dev/null @@ -1 +0,0 @@ -config_log_module diff --git a/modules/loggers/mod_log_config.h b/modules/loggers/mod_log_config.h deleted file mode 100644 index d30409f804..0000000000 --- a/modules/loggers/mod_log_config.h +++ /dev/null @@ -1,75 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr_optional.h" -#include "httpd.h" - -#ifndef _MOD_LOG_CONFIG_H -#define _MOD_LOG_CONFIG_H 1 - -typedef const char *ap_log_handler_fn_t(request_rec *r, char *a); - -typedef struct ap_log_handler { - ap_log_handler_fn_t *func; - int want_orig_default; -} ap_log_handler; - -APR_DECLARE_OPTIONAL_FN(void, ap_register_log_handler, - (apr_pool_t *p, char *tag, ap_log_handler_fn_t *func, int def)); - -#endif /* MOD_LOG_CONFIG */ diff --git a/modules/mappers/.cvsignore b/modules/mappers/.cvsignore deleted file mode 100644 index 65f0cc30cf..0000000000 --- a/modules/mappers/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -.deps -.libs -*.la -modules.mk -Makefile -*.lo -*.slo -*.so -Debug -Release diff --git a/modules/mappers/.indent.pro b/modules/mappers/.indent.pro deleted file mode 100644 index a9fbe9f9a1..0000000000 --- a/modules/mappers/.indent.pro +++ /dev/null @@ -1,54 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 --TBUFF --TFILE --TTRANS --TUINT4 --T_trans --Tallow_options_t --Tapache_sfio --Tarray_header --Tbool_int --Tbuf_area --Tbuff_struct --Tbuffy --Tcmd_how --Tcmd_parms --Tcommand_rec --Tcommand_struct --Tconn_rec --Tcore_dir_config --Tcore_server_config --Tdir_maker_func --Tevent --Tglobals_s --Thandler_func --Thandler_rec --Tjoblist_s --Tlisten_rec --Tmerger_func --Tmode_t --Tmodule --Tmodule_struct --Tmutex --Tn_long --Tother_child_rec --Toverrides_t --Tparent_score --Tpid_t --Tpiped_log --Tpool --Trequest_rec --Trequire_line --Trlim_t --Tscoreboard --Tsemaphore --Tserver_addr_rec --Tserver_rec --Tserver_rec_chain --Tshort_score --Ttable --Ttable_entry --Tthread --Tu_wide_int --Tvtime_t --Twide_int diff --git a/modules/mappers/Makefile.in b/modules/mappers/Makefile.in deleted file mode 100644 index 167b343d0d..0000000000 --- a/modules/mappers/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ - -include $(top_srcdir)/build/special.mk - diff --git a/modules/mappers/config9.m4 b/modules/mappers/config9.m4 deleted file mode 100644 index 170a2944db..0000000000 --- a/modules/mappers/config9.m4 +++ /dev/null @@ -1,33 +0,0 @@ -dnl modules enabled in this directory by default - -dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]]) - -APACHE_MODPATH_INIT(mappers) - -APACHE_MODULE(vhost_alias, mass hosting module, , , most) -APACHE_MODULE(negotiation, content negoatiation, , , yes) -APACHE_MODULE(dir, directory request handling, , , yes) -APACHE_MODULE(imap, internal imagemaps, , , yes) -APACHE_MODULE(actions, Action triggering on requests, , , yes) -APACHE_MODULE(speling, correct common URL misspellings, , , most) -APACHE_MODULE(userdir, mapping of user requests, , , yes) -APACHE_MODULE(alias, translation of requests, , , yes) - -APACHE_MODULE(rewrite, regex URL translation, , , most, [ - APR_ADDTO(CFLAGS,-DNO_DBM_REWRITEMAP) -]) - -dnl ### this isn't going to work quite right because of ordering issues -dnl ### among the config.m4 files. it is possible that a *later* module -dnl ### is marked as shared (thus setting sharedobjs), so we won't see -dnl ### it here. we need to shift *this* config.m4 to be "last" or we -dnl ### need to find a different way to set up this default and module spec. -if test "$sharedobjs" = "yes"; then - APACHE_MODULE(so, DSO capability, , , yes) -else - APACHE_MODULE(so, DSO capability, , , no) -fi -dnl ### why save the cache? -AC_CACHE_SAVE - -APACHE_MODPATH_FINISH diff --git a/modules/mappers/mod_actions.c b/modules/mappers/mod_actions.c deleted file mode 100644 index d6a31ddeb1..0000000000 --- a/modules/mappers/mod_actions.c +++ /dev/null @@ -1,226 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_actions.c: executes scripts based on MIME type or HTTP method - * - * by Alexei Kosut; based on mod_cgi.c, mod_mime.c and mod_includes.c, - * adapted by rst from original NCSA code by Rob McCool - * - * Usage instructions: - * - * Action mime/type /cgi-bin/script - * - * will activate /cgi-bin/script when a file of content type mime/type is - * requested. It sends the URL and file path of the requested document using - * the standard CGI PATH_INFO and PATH_TRANSLATED environment variables. - * - * Script PUT /cgi-bin/script - * - * will activate /cgi-bin/script when a request is received with the - * HTTP method "PUT". The available method names are defined in httpd.h. - * If the method is GET, the script will only be activated if the requested - * URI includes query information (stuff after a ?-mark). - */ - -#include "apr_strings.h" -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_main.h" -#include "http_log.h" -#include "util_script.h" - -typedef struct { - apr_table_t *action_types; /* Added with Action... */ - const char *scripted[METHODS]; /* Added with Script... */ -} action_dir_config; - -module actions_module; - -static void *create_action_dir_config(apr_pool_t *p, char *dummy) -{ - action_dir_config *new = - (action_dir_config *) apr_pcalloc(p, sizeof(action_dir_config)); - - new->action_types = apr_table_make(p, 4); - - return new; -} - -static void *merge_action_dir_configs(apr_pool_t *p, void *basev, void *addv) -{ - action_dir_config *base = (action_dir_config *) basev; - action_dir_config *add = (action_dir_config *) addv; - action_dir_config *new = (action_dir_config *) apr_palloc(p, - sizeof(action_dir_config)); - int i; - - new->action_types = apr_table_overlay(p, add->action_types, - base->action_types); - - for (i = 0; i < METHODS; ++i) { - new->scripted[i] = add->scripted[i] ? add->scripted[i] - : base->scripted[i]; - } - return new; -} - -static const char *add_action(cmd_parms *cmd, void *m_v, - const char *type, const char *script) -{ - action_dir_config *m = (action_dir_config *)m_v; - apr_table_setn(m->action_types, type, script); - return NULL; -} - -static const char *set_script(cmd_parms *cmd, void *m_v, - const char *method, const char *script) -{ - action_dir_config *m = (action_dir_config *)m_v; - int methnum; - - methnum = ap_method_number_of(method); - if (methnum == M_TRACE) - return "TRACE not allowed for Script"; - else if (methnum == M_INVALID) - return "Unknown method type for Script"; - else - m->scripted[methnum] = script; - - return NULL; -} - -static const command_rec action_cmds[] = -{ - AP_INIT_TAKE2("Action", add_action, NULL, OR_FILEINFO, - "a media type followed by a script name"), - AP_INIT_TAKE2("Script", set_script, NULL, ACCESS_CONF | RSRC_CONF, - "a method followed by a script name"), - {NULL} -}; - -static int action_handler(request_rec *r) -{ - action_dir_config *conf = (action_dir_config *) - ap_get_module_config(r->per_dir_config, &actions_module); - const char *t, *action = r->handler ? r->handler : - ap_field_noparam(r->pool, r->content_type); - const char *script; - int i; - - /* Note that this handler handles _all_ types, so handler is unchecked */ - - /* Set allowed stuff */ - for (i = 0; i < METHODS; ++i) { - if (conf->scripted[i]) - r->allowed |= (1 << i); - } - - /* First, check for the method-handling scripts */ - if (r->method_number == M_GET) { - if (r->args) - script = conf->scripted[M_GET]; - else - script = NULL; - } - else { - script = conf->scripted[r->method_number]; - } - - /* Check for looping, which can happen if the CGI script isn't */ - if (script && r->prev && r->prev->prev) - return DECLINED; - - /* Second, check for actions (which override the method scripts) */ - if ((t = apr_table_get(conf->action_types, - action ? action : ap_default_type(r)))) { - script = t; - if (r->finfo.filetype == 0) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "File does not exist: %s", r->filename); - return HTTP_NOT_FOUND; - } - } - - if (script == NULL) - return DECLINED; - - ap_internal_redirect_handler(apr_pstrcat(r->pool, script, ap_escape_uri(r->pool, - r->uri), r->args ? "?" : NULL, r->args, NULL), r); - return OK; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_handler(action_handler,NULL,NULL,APR_HOOK_LAST); -} - -module actions_module = -{ - STANDARD20_MODULE_STUFF, - create_action_dir_config, /* dir config creater */ - merge_action_dir_configs, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - action_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/mappers/mod_actions.exp b/modules/mappers/mod_actions.exp deleted file mode 100644 index 815dff29a8..0000000000 --- a/modules/mappers/mod_actions.exp +++ /dev/null @@ -1 +0,0 @@ -action_module diff --git a/modules/mappers/mod_alias.c b/modules/mappers/mod_alias.c deleted file mode 100644 index a5752e3c1e..0000000000 --- a/modules/mappers/mod_alias.c +++ /dev/null @@ -1,443 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_alias.c: Stuff for dealing with directory aliases - * - * Original by Rob McCool, rewritten in succession by David Robinson - * and rst. - * - */ - -#include "apr_strings.h" -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" - - -typedef struct { - const char *real; - const char *fake; - char *handler; - regex_t *regexp; - int redir_status; /* 301, 302, 303, 410, etc */ -} alias_entry; - -typedef struct { - apr_array_header_t *aliases; - apr_array_header_t *redirects; -} alias_server_conf; - -typedef struct { - apr_array_header_t *redirects; -} alias_dir_conf; - -module AP_MODULE_DECLARE_DATA alias_module; - -static void *create_alias_config(apr_pool_t *p, server_rec *s) -{ - alias_server_conf *a = - (alias_server_conf *) apr_pcalloc(p, sizeof(alias_server_conf)); - - a->aliases = apr_array_make(p, 20, sizeof(alias_entry)); - a->redirects = apr_array_make(p, 20, sizeof(alias_entry)); - return a; -} - -static void *create_alias_dir_config(apr_pool_t *p, char *d) -{ - alias_dir_conf *a = - (alias_dir_conf *) apr_pcalloc(p, sizeof(alias_dir_conf)); - a->redirects = apr_array_make(p, 2, sizeof(alias_entry)); - return a; -} - -static void *merge_alias_config(apr_pool_t *p, void *basev, void *overridesv) -{ - alias_server_conf *a = - (alias_server_conf *) apr_pcalloc(p, sizeof(alias_server_conf)); - alias_server_conf *base = (alias_server_conf *) basev, *overrides = (alias_server_conf *) overridesv; - - a->aliases = apr_array_append(p, overrides->aliases, base->aliases); - a->redirects = apr_array_append(p, overrides->redirects, base->redirects); - return a; -} - -static void *merge_alias_dir_config(apr_pool_t *p, void *basev, void *overridesv) -{ - alias_dir_conf *a = - (alias_dir_conf *) apr_pcalloc(p, sizeof(alias_dir_conf)); - alias_dir_conf *base = (alias_dir_conf *) basev, *overrides = (alias_dir_conf *) overridesv; - a->redirects = apr_array_append(p, overrides->redirects, base->redirects); - return a; -} - -static const char *add_alias_internal(cmd_parms *cmd, void *dummy, - const char *f, const char *r, - int use_regex) -{ - server_rec *s = cmd->server; - alias_server_conf *conf = ap_get_module_config(s->module_config, - &alias_module); - alias_entry *new = apr_array_push(conf->aliases); - - /* XX r can NOT be relative to DocumentRoot here... compat bug. */ - - if (use_regex) { - new->regexp = ap_pregcomp(cmd->pool, f, REG_EXTENDED); - if (new->regexp == NULL) - return "Regular expression could not be compiled."; - new->real = r; - } -#ifndef OS2 - else - new->real = ap_os_canonical_filename(cmd->pool, r); -#else - new->real = r; -#endif - - new->fake = f; - new->handler = cmd->info; - - return NULL; -} - -static const char *add_alias(cmd_parms *cmd, void *dummy, const char *f, - const char *r) -{ - return add_alias_internal(cmd, dummy, f, r, 0); -} - -static const char *add_alias_regex(cmd_parms *cmd, void *dummy, const char *f, - const char *r) -{ - return add_alias_internal(cmd, dummy, f, r, 1); -} - -static const char *add_redirect_internal(cmd_parms *cmd, - alias_dir_conf *dirconf, - const char *arg1, const char *arg2, - const char *arg3, int use_regex) -{ - alias_entry *new; - server_rec *s = cmd->server; - alias_server_conf *serverconf = ap_get_module_config(s->module_config, - &alias_module); - int status = (int) (long) cmd->info; - regex_t *r = NULL; - const char *f = arg2; - const char *url = arg3; - - if (!strcasecmp(arg1, "gone")) - status = HTTP_GONE; - else if (!strcasecmp(arg1, "permanent")) - status = HTTP_MOVED_PERMANENTLY; - else if (!strcasecmp(arg1, "temp")) - status = HTTP_MOVED_TEMPORARILY; - else if (!strcasecmp(arg1, "seeother")) - status = HTTP_SEE_OTHER; - else if (apr_isdigit(*arg1)) - status = atoi(arg1); - else { - f = arg1; - url = arg2; - } - - if (use_regex) { - r = ap_pregcomp(cmd->pool, f, REG_EXTENDED); - if (r == NULL) - return "Regular expression could not be compiled."; - } - - if (ap_is_HTTP_REDIRECT(status)) { - if (!url) - return "URL to redirect to is missing"; - if (!use_regex && !ap_is_url(url)) - return "Redirect to non-URL"; - } - else { - if (url) - return "Redirect URL not valid for this status"; - } - - if (cmd->path) - new = apr_array_push(dirconf->redirects); - else - new = apr_array_push(serverconf->redirects); - - new->fake = f; - new->real = url; - new->regexp = r; - new->redir_status = status; - return NULL; -} - -static const char *add_redirect(cmd_parms *cmd, void *dirconf, - const char *arg1, const char *arg2, - const char *arg3) -{ - return add_redirect_internal(cmd, dirconf, arg1, arg2, arg3, 0); -} - -static const char *add_redirect2(cmd_parms *cmd, void *dirconf, - const char *arg1, const char *arg2) -{ - return add_redirect_internal(cmd, dirconf, arg1, arg2, NULL, 0); -} - -static const char *add_redirect_regex(cmd_parms *cmd, void *dirconf, - const char *arg1, const char *arg2, - const char *arg3) -{ - return add_redirect_internal(cmd, dirconf, arg1, arg2, arg3, 1); -} - -static const command_rec alias_cmds[] = -{ - AP_INIT_TAKE2("Alias", add_alias, NULL, RSRC_CONF, - "a fakename and a realname"), - AP_INIT_TAKE2("ScriptAlias", add_alias, "cgi-script", RSRC_CONF, - "a fakename and a realname"), - AP_INIT_TAKE23("Redirect", add_redirect, (void *) HTTP_MOVED_TEMPORARILY, - OR_FILEINFO, - "an optional status, then document to be redirected and " - "destination URL"), - AP_INIT_TAKE2("AliasMatch", add_alias_regex, NULL, RSRC_CONF, - "a regular expression and a filename"), - AP_INIT_TAKE2("ScriptAliasMatch", add_alias_regex, "cgi-script", RSRC_CONF, - "a regular expression and a filename"), - AP_INIT_TAKE23("RedirectMatch", add_redirect_regex, - (void *) HTTP_MOVED_TEMPORARILY, OR_FILEINFO, - "an optional status, then a regular expression and " - "destination URL"), - AP_INIT_TAKE2("RedirectTemp", add_redirect2, - (void *) HTTP_MOVED_TEMPORARILY, OR_FILEINFO, - "a document to be redirected, then the destination URL"), - AP_INIT_TAKE2("RedirectPermanent", add_redirect2, - (void *) HTTP_MOVED_PERMANENTLY, OR_FILEINFO, - "a document to be redirected, then the destination URL"), - {NULL} -}; - -static int alias_matches(const char *uri, const char *alias_fakename) -{ - const char *end_fakename = alias_fakename + strlen(alias_fakename); - const char *aliasp = alias_fakename, *urip = uri; - - while (aliasp < end_fakename) { - if (*aliasp == '/') { - /* any number of '/' in the alias matches any number in - * the supplied URI, but there must be at least one... - */ - if (*urip != '/') - return 0; - - while (*aliasp == '/') - ++aliasp; - while (*urip == '/') - ++urip; - } - else { - /* Other characters are compared literally */ - if (*urip++ != *aliasp++) - return 0; - } - } - - /* Check last alias path component matched all the way */ - - if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/') - return 0; - - /* Return number of characters from URI which matched (may be - * greater than length of alias, since we may have matched - * doubled slashes) - */ - - return urip - uri; -} - -static char *try_alias_list(request_rec *r, apr_array_header_t *aliases, int doesc, int *status) -{ - alias_entry *entries = (alias_entry *) aliases->elts; - regmatch_t regm[10]; - char *found = NULL; - int i; - - for (i = 0; i < aliases->nelts; ++i) { - alias_entry *p = &entries[i]; - int l; - - if (p->regexp) { - if (!ap_regexec(p->regexp, r->uri, p->regexp->re_nsub + 1, regm, 0)) { - if (p->real) { - found = ap_pregsub(r->pool, p->real, r->uri, - p->regexp->re_nsub + 1, regm); - if (found && doesc) { - found = ap_escape_uri(r->pool, found); - } - } - else { - /* need something non-null */ - found = apr_pstrdup(r->pool, ""); - } - } - } - else { - l = alias_matches(r->uri, p->fake); - - if (l > 0) { - if (doesc) { - char *escurl; - escurl = ap_os_escape_path(r->pool, r->uri + l, 1); - - found = apr_pstrcat(r->pool, p->real, escurl, NULL); - } - else - found = apr_pstrcat(r->pool, p->real, r->uri + l, NULL); - } - } - - if (found) { - if (p->handler) { /* Set handler, and leave a note for mod_cgi */ - r->handler = p->handler; - apr_table_setn(r->notes, "alias-forced-type", r->handler); - } - - *status = p->redir_status; - - return found; - } - - } - - return NULL; -} - -static int translate_alias_redir(request_rec *r) -{ - ap_conf_vector_t *sconf = r->server->module_config; - alias_server_conf *serverconf = ap_get_module_config(sconf, &alias_module); - char *ret; - int status; - - if (r->uri[0] != '/' && r->uri[0] != '\0') - return DECLINED; - - if ((ret = try_alias_list(r, serverconf->redirects, 1, &status)) != NULL) { - if (ap_is_HTTP_REDIRECT(status)) { - /* include QUERY_STRING if any */ - if (r->args) { - ret = apr_pstrcat(r->pool, ret, "?", r->args, NULL); - } - apr_table_setn(r->headers_out, "Location", ret); - } - return status; - } - - if ((ret = try_alias_list(r, serverconf->aliases, 0, &status)) != NULL) { - r->filename = ret; - return OK; - } - - return DECLINED; -} - -static int fixup_redir(request_rec *r) -{ - void *dconf = r->per_dir_config; - alias_dir_conf *dirconf = - (alias_dir_conf *) ap_get_module_config(dconf, &alias_module); - char *ret; - int status; - - /* It may have changed since last time, so try again */ - - if ((ret = try_alias_list(r, dirconf->redirects, 1, &status)) != NULL) { - if (ap_is_HTTP_REDIRECT(status)) - apr_table_setn(r->headers_out, "Location", ret); - return status; - } - - return DECLINED; -} - -static void register_hooks(apr_pool_t *p) -{ - static const char * const aszPre[]={ "mod_userdir.c",NULL }; - - ap_hook_translate_name(translate_alias_redir,aszPre,NULL,APR_HOOK_MIDDLE); - ap_hook_fixups(fixup_redir,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA alias_module = -{ - STANDARD20_MODULE_STUFF, - create_alias_dir_config, /* dir config creater */ - merge_alias_dir_config, /* dir merger --- default is to override */ - create_alias_config, /* server config */ - merge_alias_config, /* merge server configs */ - alias_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/mappers/mod_alias.exp b/modules/mappers/mod_alias.exp deleted file mode 100644 index ac386ec3fa..0000000000 --- a/modules/mappers/mod_alias.exp +++ /dev/null @@ -1 +0,0 @@ -alias_module diff --git a/modules/mappers/mod_dir.c b/modules/mappers/mod_dir.c deleted file mode 100644 index b216622018..0000000000 --- a/modules/mappers/mod_dir.c +++ /dev/null @@ -1,252 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_dir.c: handle default index files, and trailing-/ redirects - */ - -#include "apr_strings.h" -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_request.h" -#include "http_protocol.h" -#include "http_log.h" -#include "http_main.h" -#include "util_script.h" - -module AP_MODULE_DECLARE_DATA dir_module; - -typedef struct dir_config_struct { - apr_array_header_t *index_names; -} dir_config_rec; - -#define DIR_CMD_PERMS OR_INDEXES - -static const char *add_index(cmd_parms *cmd, void *dummy, const char *arg) -{ - dir_config_rec *d = dummy; - - if (!d->index_names) { - d->index_names = apr_array_make(cmd->pool, 2, sizeof(char *)); - } - *(const char **)apr_array_push(d->index_names) = arg; - return NULL; -} - -static const command_rec dir_cmds[] = -{ - AP_INIT_ITERATE("DirectoryIndex", add_index, NULL, DIR_CMD_PERMS, - "a list of file names"), - {NULL} -}; - -static void *create_dir_config(apr_pool_t *p, char *dummy) -{ - dir_config_rec *new = - (dir_config_rec *) apr_pcalloc(p, sizeof(dir_config_rec)); - - new->index_names = NULL; - return (void *) new; -} - -static void *merge_dir_configs(apr_pool_t *p, void *basev, void *addv) -{ - dir_config_rec *new = (dir_config_rec *) apr_pcalloc(p, sizeof(dir_config_rec)); - dir_config_rec *base = (dir_config_rec *) basev; - dir_config_rec *add = (dir_config_rec *) addv; - - new->index_names = add->index_names ? add->index_names : base->index_names; - return new; -} - -static int fixup_dir(request_rec *r) -{ - /* only (potentially) redirect for GET requests against directories */ - if (r->method_number != M_GET || r->finfo.filetype != APR_DIR) { - return DECLINED; - } - - if (r->uri[0] == '\0' || r->uri[strlen(r->uri) - 1] != '/') { - char *ifile; - if (r->args != NULL) - ifile = apr_pstrcat(r->pool, ap_escape_uri(r->pool, r->uri), - "/", "?", r->args, NULL); - else - ifile = apr_pstrcat(r->pool, ap_escape_uri(r->pool, r->uri), - "/", NULL); - - apr_table_setn(r->headers_out, "Location", - ap_construct_url(r->pool, ifile, r)); - return HTTP_MOVED_PERMANENTLY; - } - - return OK; -} - -static int handle_dir(request_rec *r) -{ - dir_config_rec *d; - char *dummy_ptr[1]; - char **names_ptr; - int num_names; - int error_notfound = 0; - - if (strcmp(r->handler,DIR_MAGIC_TYPE)) { - return DECLINED; - } - - d = (dir_config_rec *) ap_get_module_config(r->per_dir_config, - &dir_module); - - /* KLUDGE --- make the sub_req lookups happen in the right directory. - * Fixing this in the sub_req_lookup functions themselves is difficult, - * and would probably break virtual includes... - */ - - if (r->filename[strlen(r->filename) - 1] != '/') { - r->filename = apr_pstrcat(r->pool, r->filename, "/", NULL); - } - - if (d->index_names) { - names_ptr = (char **)d->index_names->elts; - num_names = d->index_names->nelts; - } - else { - dummy_ptr[0] = AP_DEFAULT_INDEX; - names_ptr = dummy_ptr; - num_names = 1; - } - - for (; num_names; ++names_ptr, --num_names) { - char *name_ptr = *names_ptr; - request_rec *rr = ap_sub_req_lookup_uri(name_ptr, r, NULL); - - if (rr->status == HTTP_OK && rr->finfo.filetype == APR_REG) { - char *new_uri = ap_escape_uri(r->pool, rr->uri); - - if (rr->args != NULL) - new_uri = apr_pstrcat(r->pool, new_uri, "?", rr->args, NULL); - else if (r->args != NULL) - new_uri = apr_pstrcat(r->pool, new_uri, "?", r->args, NULL); - - ap_destroy_sub_req(rr); - ap_internal_redirect(new_uri, r); - return OK; - } - - /* If the request returned a redirect, propagate it to the client */ - - if (ap_is_HTTP_REDIRECT(rr->status) || - (rr->status == HTTP_NOT_ACCEPTABLE && num_names == 1) || - (rr->status == HTTP_UNAUTHORIZED && num_names == 1)) { - - apr_pool_join(r->pool, rr->pool); - error_notfound = rr->status; - r->notes = apr_table_overlay(r->pool, r->notes, rr->notes); - r->headers_out = apr_table_overlay(r->pool, r->headers_out, - rr->headers_out); - r->err_headers_out = apr_table_overlay(r->pool, r->err_headers_out, - rr->err_headers_out); - return error_notfound; - } - - /* If the request returned something other than 404 (or 200), - * it means the module encountered some sort of problem. To be - * secure, we should return the error, rather than create - * along a (possibly unsafe) directory index. - * - * So we store the error, and if none of the listed files - * exist, we return the last error response we got, instead - * of a directory listing. - */ - if (rr->status && rr->status != HTTP_NOT_FOUND && rr->status != HTTP_OK) - error_notfound = rr->status; - - ap_destroy_sub_req(rr); - } - - if (error_notfound) - return error_notfound; - - if (r->method_number != M_GET) - return DECLINED; - - /* nothing for us to do, pass on through */ - - return DECLINED; -} - -static void register_hooks(apr_pool_t *p) -{ - static const char * const aszSucc[]={"mod_autoindex.c", NULL}; - - ap_hook_fixups(fixup_dir,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_handler(handle_dir,NULL,aszSucc,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA dir_module = { - STANDARD20_MODULE_STUFF, - create_dir_config, /* create per-directory config structure */ - merge_dir_configs, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - dir_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/mappers/mod_dir.exp b/modules/mappers/mod_dir.exp deleted file mode 100644 index 5fbf772991..0000000000 --- a/modules/mappers/mod_dir.exp +++ /dev/null @@ -1 +0,0 @@ -dir_module diff --git a/modules/mappers/mod_imap.c b/modules/mappers/mod_imap.c deleted file mode 100644 index c29567e90f..0000000000 --- a/modules/mappers/mod_imap.c +++ /dev/null @@ -1,925 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * This imagemap module started as a port of the original imagemap.c - * written by Rob McCool (11/13/93 robm@ncsa.uiuc.edu). - * This version includes the mapping algorithms found in version 1.3 - * of imagemap.c. - * - * Contributors to this code include: - * - * Kevin Hughes, kevinh@pulua.hcc.hawaii.edu - * - * Eric Haines, erich@eye.com - * "macmartinized" polygon code copyright 1992 by Eric Haines, erich@eye.com - * - * Randy Terbush, randy@zyzzyva.com - * port to Apache module format, "base_uri" and support for relative URLs - * - * James H. Cloos, Jr., cloos@jhcloos.com - * Added point datatype, using code in NCSA's version 1.8 imagemap.c - * program, as distributed with version 1.4.1 of their server. - * The point code is originally added by Craig Milo Rogers, Rogers@ISI.Edu - * - * Nathan Kurz, nate@tripod.com - * Rewrite/reorganization. New handling of default, base and relative URLs. - * New Configuration directives: - * ImapMenu {none, formatted, semiformatted, unformatted} - * ImapDefault {error, nocontent, referer, menu, URL} - * ImapBase {map, referer, URL} - * Support for creating non-graphical menu added. (backwards compatible): - * Old: directive URL [x,y ...] - * New: directive URL "Menu text" [x,y ...] - * or: directive URL x,y ... "Menu text" - * Map format and menu concept courtesy Joshua Bell, jsbell@acs.ucalgary.ca. - * - * Mark Cox, mark@ukweb.com, Allow relative URLs even when no base specified - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_lib.h" - -#define APR_WANT_STDIO /* for sscanf() */ -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_main.h" -#include "http_log.h" -#include "util_script.h" -#include "mod_core.h" - - -#define IMAP_MAGIC_TYPE "application/x-httpd-imap" -#define MAXVERTS 100 -#define X 0 -#define Y 1 - -#define IMAP_MENU_DEFAULT "formatted" -#define IMAP_DEFAULT_DEFAULT "nocontent" -#define IMAP_BASE_DEFAULT "map" - -#ifdef SUNOS4 -double strtod(); /* SunOS needed this */ -#endif - -module AP_MODULE_DECLARE_DATA imap_module; - -typedef struct { - char *imap_menu; - char *imap_default; - char *imap_base; -} imap_conf_rec; - -static void *create_imap_dir_config(apr_pool_t *p, char *dummy) -{ - imap_conf_rec *icr = - (imap_conf_rec *) apr_palloc(p, sizeof(imap_conf_rec)); - - icr->imap_menu = NULL; - icr->imap_default = NULL; - icr->imap_base = NULL; - - return icr; -} - -static void *merge_imap_dir_configs(apr_pool_t *p, void *basev, void *addv) -{ - imap_conf_rec *new = (imap_conf_rec *) apr_pcalloc(p, sizeof(imap_conf_rec)); - imap_conf_rec *base = (imap_conf_rec *) basev; - imap_conf_rec *add = (imap_conf_rec *) addv; - - new->imap_menu = add->imap_menu ? add->imap_menu : base->imap_menu; - new->imap_default = add->imap_default ? add->imap_default - : base->imap_default; - new->imap_base = add->imap_base ? add->imap_base : base->imap_base; - - return new; -} - - -static const command_rec imap_cmds[] = -{ - AP_INIT_TAKE1("ImapMenu", ap_set_string_slot, - (void *) XtOffsetOf(imap_conf_rec, imap_menu), OR_INDEXES, - "the type of menu generated: none, formatted, semiformatted, " - "unformatted"), - AP_INIT_TAKE1("ImapDefault", ap_set_string_slot, - (void *) XtOffsetOf(imap_conf_rec, imap_default), OR_INDEXES, - "the action taken if no match: error, nocontent, referer, " - "menu, URL"), - AP_INIT_TAKE1("ImapBase", ap_set_string_slot, - (void *) XtOffsetOf(imap_conf_rec, imap_base), OR_INDEXES, - "the base for all URL's: map, referer, URL (or start of)"), - {NULL} -}; - -static int pointinrect(const double point[2], double coords[MAXVERTS][2]) -{ - double max[2], min[2]; - if (coords[0][X] > coords[1][X]) { - max[0] = coords[0][X]; - min[0] = coords[1][X]; - } - else { - max[0] = coords[1][X]; - min[0] = coords[0][X]; - } - - if (coords[0][Y] > coords[1][Y]) { - max[1] = coords[0][Y]; - min[1] = coords[1][Y]; - } - else { - max[1] = coords[1][Y]; - min[1] = coords[0][Y]; - } - - return ((point[X] >= min[0] && point[X] <= max[0]) && - (point[Y] >= min[1] && point[Y] <= max[1])); -} - -static int pointincircle(const double point[2], double coords[MAXVERTS][2]) -{ - double radius1, radius2; - - radius1 = ((coords[0][Y] - coords[1][Y]) * (coords[0][Y] - coords[1][Y])) - + ((coords[0][X] - coords[1][X]) * (coords[0][X] - coords[1][X])); - - radius2 = ((coords[0][Y] - point[Y]) * (coords[0][Y] - point[Y])) - + ((coords[0][X] - point[X]) * (coords[0][X] - point[X])); - - return (radius2 <= radius1); -} - -#define fmin(a,b) (((a)>(b))?(b):(a)) -#define fmax(a,b) (((a)>(b))?(a):(b)) - -static int pointinpoly(const double point[2], double pgon[MAXVERTS][2]) -{ - int i, numverts, crossings = 0; - double x = point[X], y = point[Y]; - - for (numverts = 0; pgon[numverts][X] != -1 && numverts < MAXVERTS; - numverts++) { - /* just counting the vertexes */ - } - - for (i = 0; i < numverts; i++) { - double x1=pgon[i][X]; - double y1=pgon[i][Y]; - double x2=pgon[(i + 1) % numverts][X]; - double y2=pgon[(i + 1) % numverts][Y]; - double d=(y - y1) * (x2 - x1) - (x - x1) * (y2 - y1); - - if ((y1 >= y) != (y2 >= y)) { - crossings +=y2 - y1 >= 0 ? d >= 0 : d <= 0; - } - if (!d && fmin(x1,x2) <= x && x <= fmax(x1,x2) - && fmin(y1,y2) <= y && y <= fmax(y1,y2)) { - return 1; - } - } - return crossings & 0x01; -} - - -static int is_closer(const double point[2], double coords[MAXVERTS][2], - double *closest) -{ - double dist_squared = ((point[X] - coords[0][X]) - * (point[X] - coords[0][X])) - + ((point[Y] - coords[0][Y]) - * (point[Y] - coords[0][Y])); - - if (point[X] < 0 || point[Y] < 0) { - return (0); /* don't mess around with negative coordinates */ - } - - if (*closest < 0 || dist_squared < *closest) { - *closest = dist_squared; - return (1); /* if this is the first point or is the closest yet - set 'closest' equal to this distance^2 */ - } - - return (0); /* if it's not the first or closest */ - -} - -static double get_x_coord(const char *args) -{ - char *endptr; /* we want it non-null */ - double x_coord = -1; /* -1 is returned if no coordinate is given */ - - if (args == NULL) { - return (-1); /* in case we aren't passed anything */ - } - - while (*args && !apr_isdigit(*args) && *args != ',') { - args++; /* jump to the first digit, but not past - a comma or end */ - } - - x_coord = strtod(args, &endptr); - - if (endptr > args) { /* if a conversion was made */ - return (x_coord); - } - - return (-1); /* else if no conversion was made, - or if no args was given */ -} - -static double get_y_coord(const char *args) -{ - char *endptr; /* we want it non-null */ - const char *start_of_y = NULL; - double y_coord = -1; /* -1 is returned on error */ - - if (args == NULL) { - return (-1); /* in case we aren't passed anything */ - } - - start_of_y = ap_strchr_c(args, ','); /* the comma */ - - if (start_of_y) { - - start_of_y++; /* start looking at the character after - the comma */ - - while (*start_of_y && !apr_isdigit(*start_of_y)) { - start_of_y++; /* jump to the first digit, but not - past the end */ - } - - y_coord = strtod(start_of_y, &endptr); - - if (endptr > start_of_y) { - return (y_coord); - } - } - - return (-1); /* if no conversion was made, or - no comma was found in args */ -} - - -/* See if string has a "quoted part", and if so set *quoted_part to - * the first character of the quoted part, then hammer a \0 onto the - * trailing quote, and set *string to point at the first character - * past the second quote. - * - * Otherwise set *quoted_part to NULL, and leave *string alone. - */ -static void read_quoted(char **string, char **quoted_part) -{ - char *strp = *string; - - /* assume there's no quoted part */ - *quoted_part = NULL; - - while (apr_isspace(*strp)) { - strp++; /* go along string until non-whitespace */ - } - - if (*strp == '"') { /* if that character is a double quote */ - strp++; /* step over it */ - *quoted_part = strp; /* note where the quoted part begins */ - - while (*strp && *strp != '"') { - ++strp; /* skip the quoted portion */ - } - - *strp = '\0'; /* end the string with a NUL */ - - strp++; /* step over the last double quote */ - *string = strp; - } -} - -/* - * returns the mapped URL or NULL. - */ -static char *imap_url(request_rec *r, const char *base, const char *value) -{ -/* translates a value into a URL. */ - int slen, clen; - char *string_pos = NULL; - const char *string_pos_const = NULL; - char *directory = NULL; - const char *referer = NULL; - char *my_base; - - if (!strcasecmp(value, "map") || !strcasecmp(value, "menu")) { - return ap_construct_url(r->pool, r->uri, r); - } - - if (!strcasecmp(value, "nocontent") || !strcasecmp(value, "error")) { - return apr_pstrdup(r->pool, value); /* these are handled elsewhere, - so just copy them */ - } - - if (!strcasecmp(value, "referer")) { - referer = apr_table_get(r->headers_in, "Referer"); - if (referer && *referer) { - return apr_pstrdup(r->pool, referer); - } - else { - /* XXX: This used to do *value = '\0'; ... which is totally bogus - * because it hammers the passed in value, which can be a string - * constant, or part of a config, or whatever. Total garbage. - * This works around that without changing the rest of this - * code much - */ - value = ""; /* if 'referer' but no referring page, - null the value */ - } - } - - string_pos_const = value; - while (apr_isalpha(*string_pos_const)) { - string_pos_const++; /* go along the URL from the map - until a non-letter */ - } - if (*string_pos_const == ':') { - /* if letters and then a colon (like http:) */ - /* it's an absolute URL, so use it! */ - return apr_pstrdup(r->pool, value); - } - - if (!base || !*base) { - if (value && *value) { - return apr_pstrdup(r->pool, value); /* no base: use what is given */ - } - /* no base, no value: pick a simple default */ - return ap_construct_url(r->pool, "/", r); - } - - /* must be a relative URL to be combined with base */ - if (ap_strchr_c(base, '/') == NULL && (!strncmp(value, "../", 3) - || !strcmp(value, ".."))) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "invalid base directive in map file: %s", r->uri); - return NULL; - } - my_base = apr_pstrdup(r->pool, base); - string_pos = my_base; - while (*string_pos) { - if (*string_pos == '/' && *(string_pos + 1) == '/') { - string_pos += 2; /* if there are two slashes, jump over them */ - continue; - } - if (*string_pos == '/') { /* the first single slash */ - if (value[0] == '/') { - *string_pos = '\0'; - } /* if the URL from the map starts from root, - end the base URL string at the first single - slash */ - else { - directory = string_pos; /* save the start of - the directory portion */ - - string_pos = strrchr(string_pos, '/'); /* now reuse - string_pos */ - string_pos++; /* step over that last slash */ - *string_pos = '\0'; - } /* but if the map url is relative, leave the - slash on the base (if there is one) */ - break; - } - string_pos++; /* until we get to the end of my_base without - finding a slash by itself */ - } - - while (!strncmp(value, "../", 3) || !strcmp(value, "..")) { - - if (directory && (slen = strlen(directory))) { - - /* for each '..', knock a directory off the end - by ending the string right at the last slash. - But only consider the directory portion: don't eat - into the server name. And only try if a directory - portion was found */ - - clen = slen - 1; - - while ((slen - clen) == 1) { - - if ((string_pos = strrchr(directory, '/'))) { - *string_pos = '\0'; - } - clen = strlen(directory); - if (clen == 0) { - break; - } - } - - value += 2; /* jump over the '..' that we found in the - value */ - } - else if (directory) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "invalid directory name in map file: %s", r->uri); - return NULL; - } - - if (!strncmp(value, "/../", 4) || !strcmp(value, "/..")) { - value++; /* step over the '/' if there are more '..' - to do. This way, we leave the starting - '/' on value after the last '..', but get - rid of it otherwise */ - } - - } /* by this point, value does not start - with '..' */ - - if (value && *value) { - return apr_pstrcat(r->pool, my_base, value, NULL); - } - return my_base; -} - -static int imap_reply(request_rec *r, char *redirect) -{ - if (!strcasecmp(redirect, "error")) { - /* they actually requested an error! */ - return HTTP_INTERNAL_SERVER_ERROR; - } - if (!strcasecmp(redirect, "nocontent")) { - /* tell the client to keep the page it has */ - return HTTP_NO_CONTENT; - } - if (redirect && *redirect) { - /* must be a URL, so redirect to it */ - apr_table_setn(r->headers_out, "Location", redirect); - return HTTP_MOVED_TEMPORARILY; - } - return HTTP_INTERNAL_SERVER_ERROR; -} - -static void menu_header(request_rec *r, char *menu) -{ - r->content_type = "text/html"; - - ap_rvputs(r, DOCTYPE_HTML_3_2, "<html><head>\n<title>Menu for ", r->uri, - "</title>\n</head><body>\n", NULL); - - if (!strcasecmp(menu, "formatted")) { - ap_rvputs(r, "<h1>Menu for ", r->uri, "</h1>\n<hr>\n\n", NULL); - } - - return; -} - -static void menu_blank(request_rec *r, char *menu) -{ - if (!strcasecmp(menu, "formatted")) { - ap_rputs("\n", r); - } - if (!strcasecmp(menu, "semiformatted")) { - ap_rputs("<br>\n", r); - } - if (!strcasecmp(menu, "unformatted")) { - ap_rputs("\n", r); - } - return; -} - -static void menu_comment(request_rec *r, char *menu, char *comment) -{ - if (!strcasecmp(menu, "formatted")) { - ap_rputs("\n", r); /* print just a newline if 'formatted' */ - } - if (!strcasecmp(menu, "semiformatted") && *comment) { - ap_rvputs(r, comment, "\n", NULL); - } - if (!strcasecmp(menu, "unformatted") && *comment) { - ap_rvputs(r, comment, "\n", NULL); - } - return; /* comments are ignored in the - 'formatted' form */ -} - -static void menu_default(request_rec *r, char *menu, char *href, char *text) -{ - if (!strcasecmp(href, "error") || !strcasecmp(href, "nocontent")) { - return; /* don't print such lines, these aren't - really href's */ - } - if (!strcasecmp(menu, "formatted")) { - ap_rvputs(r, "<pre>(Default) <a href=\"", href, "\">", text, - "</a></pre>\n", NULL); - } - if (!strcasecmp(menu, "semiformatted")) { - ap_rvputs(r, "<pre>(Default) <a href=\"", href, "\">", text, - "</a></pre>\n", NULL); - } - if (!strcasecmp(menu, "unformatted")) { - ap_rvputs(r, "<a href=\"", href, "\">", text, "</a>", NULL); - } - return; -} - -static void menu_directive(request_rec *r, char *menu, char *href, char *text) -{ - if (!strcasecmp(href, "error") || !strcasecmp(href, "nocontent")) { - return; /* don't print such lines, as this isn't - really an href */ - } - if (!strcasecmp(menu, "formatted")) { - ap_rvputs(r, "<pre> <a href=\"", href, "\">", text, - "</a></pre>\n", NULL); - } - if (!strcasecmp(menu, "semiformatted")) { - ap_rvputs(r, "<pre> <a href=\"", href, "\">", text, - "</a></pre>\n", NULL); - } - if (!strcasecmp(menu, "unformatted")) { - ap_rvputs(r, "<a href=\"", href, "\">", text, "</a>", NULL); - } - return; -} - -static void menu_footer(request_rec *r) -{ - ap_rputs("\n\n</body>\n</html>\n", r); /* finish the menu */ -} - -static int imap_handler(request_rec *r) -{ - char input[MAX_STRING_LEN]; - char *directive; - char *value; - char *href_text; - char *base; - char *redirect; - char *mapdflt; - char *closest = NULL; - double closest_yet = -1; - apr_status_t status; - - double testpoint[2]; - double pointarray[MAXVERTS + 1][2]; - int vertex; - - char *string_pos; - int showmenu = 0; - - imap_conf_rec *icr; - - char *imap_menu; - char *imap_default; - char *imap_base; - - ap_configfile_t *imap; - - if (r->method_number != M_GET || (strcmp(r->handler,IMAP_MAGIC_TYPE) - && strcmp(r->handler, "imap-file"))) - return DECLINED; - - icr = ap_get_module_config(r->per_dir_config, &imap_module); - - imap_menu = icr->imap_menu ? icr->imap_menu : IMAP_MENU_DEFAULT; - imap_default = icr->imap_default - ? icr->imap_default : IMAP_DEFAULT_DEFAULT; - imap_base = icr->imap_base ? icr->imap_base : IMAP_BASE_DEFAULT; - - status = ap_pcfg_openfile(&imap, r->pool, r->filename); - - if (status != APR_SUCCESS) { - return HTTP_NOT_FOUND; - } - - base = imap_url(r, NULL, imap_base); /* set base according - to default */ - if (!base) { - return HTTP_INTERNAL_SERVER_ERROR; - } - mapdflt = imap_url(r, NULL, imap_default); /* and default to - global default */ - if (!mapdflt) { - return HTTP_INTERNAL_SERVER_ERROR; - } - - testpoint[X] = get_x_coord(r->args); - testpoint[Y] = get_y_coord(r->args); - - if ((testpoint[X] == -1 || testpoint[Y] == -1) || - (testpoint[X] == 0 && testpoint[Y] == 0)) { - /* if either is -1 or if both are zero (new Lynx) */ - /* we don't have valid coordinates */ - testpoint[X] = -1; - testpoint[Y] = -1; - if (strncasecmp(imap_menu, "none", 2)) { - showmenu = 1; /* show the menu _unless_ ImapMenu is - 'none' or 'no' */ - } - } - - if (showmenu) { /* send start of imagemap menu if - we're going to */ - menu_header(r, imap_menu); - } - - while (!ap_cfg_getline(input, sizeof(input), imap)) { - if (!input[0]) { - if (showmenu) { - menu_blank(r, imap_menu); - } - continue; - } - - if (input[0] == '#') { - if (showmenu) { - menu_comment(r, imap_menu, input + 1); - } - continue; - } /* blank lines and comments are ignored - if we aren't printing a menu */ - - /* find the first two space delimited fields, recall that - * ap_cfg_getline has removed leading/trailing whitespace. - * - * note that we're tokenizing as we go... if we were to use the - * ap_getword() class of functions we would end up allocating extra - * memory for every line of the map file - */ - string_pos = input; - if (!*string_pos) { /* need at least two fields */ - goto need_2_fields; - } - - directive = string_pos; - while (*string_pos && !apr_isspace(*string_pos)) { /* past directive */ - ++string_pos; - } - if (!*string_pos) { /* need at least two fields */ - goto need_2_fields; - } - *string_pos++ = '\0'; - - if (!*string_pos) { /* need at least two fields */ - goto need_2_fields; - } - while(*string_pos && apr_isspace(*string_pos)) { /* past whitespace */ - ++string_pos; - } - - value = string_pos; - while (*string_pos && !apr_isspace(*string_pos)) { /* past value */ - ++string_pos; - } - if (apr_isspace(*string_pos)) { - *string_pos++ = '\0'; - } - else { - /* end of input, don't advance past it */ - *string_pos = '\0'; - } - - if (!strncasecmp(directive, "base", 4)) { /* base, base_uri */ - base = imap_url(r, NULL, value); - if (!base) { - goto menu_bail; - } - continue; /* base is never printed to a menu */ - } - - read_quoted(&string_pos, &href_text); - - if (!strcasecmp(directive, "default")) { /* default */ - mapdflt = imap_url(r, NULL, value); - if (!mapdflt) { - goto menu_bail; - } - if (showmenu) { /* print the default if there's a menu */ - redirect = imap_url(r, base, mapdflt); - if (!redirect) { - goto menu_bail; - } - menu_default(r, imap_menu, redirect, - href_text ? href_text : mapdflt); - } - continue; - } - - vertex = 0; - while (vertex < MAXVERTS && - sscanf(string_pos, "%lf%*[, ]%lf", - &pointarray[vertex][X], &pointarray[vertex][Y]) == 2) { - /* Now skip what we just read... we can't use ANSIism %n */ - while (apr_isspace(*string_pos)) { /* past whitespace */ - string_pos++; - } - while (apr_isdigit(*string_pos)) { /* and the 1st number */ - string_pos++; - } - string_pos++; /* skip the ',' */ - while (apr_isspace(*string_pos)) { /* past any more whitespace */ - string_pos++; - } - while (apr_isdigit(*string_pos)) { /* 2nd number */ - string_pos++; - } - vertex++; - } /* so long as there are more vertices to - read, and we have room, read them in. - We start where we left off of the last - sscanf, not at the beginning. */ - - pointarray[vertex][X] = -1; /* signals the end of vertices */ - - if (showmenu) { - if (!href_text) { - read_quoted(&string_pos, &href_text); /* href text could - be here instead */ - } - redirect = imap_url(r, base, value); - if (!redirect) { - goto menu_bail; - } - menu_directive(r, imap_menu, redirect, - href_text ? href_text : value); - continue; - } - /* note that we don't make it past here if we are making a menu */ - - if (testpoint[X] == -1 || pointarray[0][X] == -1) { - continue; /* don't try the following tests if testpoints - are invalid, or if there are no - coordinates */ - } - - if (!strcasecmp(directive, "poly")) { /* poly */ - - if (pointinpoly(testpoint, pointarray)) { - ap_cfg_closefile(imap); - redirect = imap_url(r, base, value); - if (!redirect) { - return HTTP_INTERNAL_SERVER_ERROR; - } - return (imap_reply(r, redirect)); - } - continue; - } - - if (!strcasecmp(directive, "circle")) { /* circle */ - - if (pointincircle(testpoint, pointarray)) { - ap_cfg_closefile(imap); - redirect = imap_url(r, base, value); - if (!redirect) { - return HTTP_INTERNAL_SERVER_ERROR; - } - return (imap_reply(r, redirect)); - } - continue; - } - - if (!strcasecmp(directive, "rect")) { /* rect */ - - if (pointinrect(testpoint, pointarray)) { - ap_cfg_closefile(imap); - redirect = imap_url(r, base, value); - if (!redirect) { - return HTTP_INTERNAL_SERVER_ERROR; - } - return (imap_reply(r, redirect)); - } - continue; - } - - if (!strcasecmp(directive, "point")) { /* point */ - - if (is_closer(testpoint, pointarray, &closest_yet)) { - closest = apr_pstrdup(r->pool, value); - } - - continue; - } /* move on to next line whether it's - closest or not */ - - } /* nothing matched, so we get another line! */ - - ap_cfg_closefile(imap); /* we are done with the map file; close it */ - - if (showmenu) { - menu_footer(r); /* finish the menu and we are done */ - return OK; - } - - if (closest) { /* if a 'point' directive has been seen */ - redirect = imap_url(r, base, closest); - if (!redirect) { - return HTTP_INTERNAL_SERVER_ERROR; - } - return (imap_reply(r, redirect)); - } - - if (mapdflt) { /* a default should be defined, even if - only 'nocontent' */ - redirect = imap_url(r, base, mapdflt); - if (!redirect) { - return HTTP_INTERNAL_SERVER_ERROR; - } - return (imap_reply(r, redirect)); - } - - return HTTP_INTERNAL_SERVER_ERROR; /* If we make it this far, - we failed. They lose! */ - -need_2_fields: - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "map file %s, line %d syntax error: requires at " - "least two fields", r->uri, imap->line_number); - /* fall through */ -menu_bail: - ap_cfg_closefile(imap); - if (showmenu) { - /* There's not much else we can do ... we've already sent the headers - * to the client. - */ - ap_rputs("\n\n[an internal server error occured]\n", r); - menu_footer(r); - return OK; - } - return HTTP_INTERNAL_SERVER_ERROR; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_handler(imap_handler,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA imap_module = -{ - STANDARD20_MODULE_STUFF, - create_imap_dir_config, /* dir config creater */ - merge_imap_dir_configs, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - imap_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/mappers/mod_imap.exp b/modules/mappers/mod_imap.exp deleted file mode 100644 index 1e0e0b83d0..0000000000 --- a/modules/mappers/mod_imap.exp +++ /dev/null @@ -1 +0,0 @@ -imap_module diff --git a/modules/mappers/mod_negotiation.c b/modules/mappers/mod_negotiation.c deleted file mode 100644 index 679460c088..0000000000 --- a/modules/mappers/mod_negotiation.c +++ /dev/null @@ -1,2756 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_negotiation.c: keeps track of MIME types the client is willing to - * accept, and contains code to handle type arbitration. - * - * rst - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_file_io.h" -#include "apr_lib.h" - -#define APR_WANT_STDIO /* for EOF */ -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_protocol.h" -#include "http_core.h" -#include "http_log.h" -#include "util_script.h" - - -#define MAP_FILE_MAGIC_TYPE "application/x-type-map" - -/* Commands --- configuring document caching on a per (virtual?) - * server basis... - */ - -typedef struct { - apr_array_header_t *language_priority; -} neg_dir_config; - -module AP_MODULE_DECLARE_DATA negotiation_module; - -static void *create_neg_dir_config(apr_pool_t *p, char *dummy) -{ - neg_dir_config *new = (neg_dir_config *) apr_palloc(p, sizeof(neg_dir_config)); - - new->language_priority = apr_array_make(p, 4, sizeof(char *)); - return new; -} - -static void *merge_neg_dir_configs(apr_pool_t *p, void *basev, void *addv) -{ - neg_dir_config *base = (neg_dir_config *) basev; - neg_dir_config *add = (neg_dir_config *) addv; - neg_dir_config *new = (neg_dir_config *) apr_palloc(p, sizeof(neg_dir_config)); - - /* give priority to the config in the subdirectory */ - new->language_priority = apr_array_append(p, add->language_priority, - base->language_priority); - return new; -} - -static const char *set_language_priority(cmd_parms *cmd, void *n, - const char *lang) -{ - apr_array_header_t *arr = ((neg_dir_config *) n)->language_priority; - const char **langp = (const char **) apr_array_push(arr); - - *langp = lang; - return NULL; -} - -static const char *cache_negotiated_docs(cmd_parms *cmd, void *dummy, - int arg) -{ - ap_set_module_config(cmd->server->module_config, &negotiation_module, - (arg ? "Cache" : NULL)); - return NULL; -} - -static int do_cache_negotiated_docs(server_rec *s) -{ - return (ap_get_module_config(s->module_config, &negotiation_module) != NULL); -} - -static const command_rec negotiation_cmds[] = -{ - AP_INIT_FLAG("CacheNegotiatedDocs", cache_negotiated_docs, NULL, RSRC_CONF, - "Either 'on' or 'off' (default)"), - AP_INIT_ITERATE("LanguagePriority", set_language_priority, NULL, OR_FILEINFO, - "space-delimited list of MIME language abbreviations"), - {NULL} -}; - -/* - * Record of available info on a media type specified by the client - * (we also use 'em for encodings and languages) - */ - -typedef struct accept_rec { - char *name; /* MUST be lowercase */ - float quality; - float level; - char *charset; /* for content-type only */ -} accept_rec; - -/* - * Record of available info on a particular variant - * - * Note that a few of these fields are updated by the actual negotiation - * code. These are: - * - * level_matched --- initialized to zero. Set to the value of level - * if the client actually accepts this media type at that - * level (and *not* if it got in on a wildcard). See level_cmp - * below. - * mime_stars -- initialized to zero. Set to the number of stars - * present in the best matching Accept header element. - * 1 for star/star, 2 for type/star and 3 for - * type/subtype. - * - * definite -- initialized to 1. Set to 0 if there is a match which - * makes the variant non-definite according to the rules - * in rfc2296. - */ - -typedef struct var_rec { - request_rec *sub_req; /* May be NULL (is, for map files) */ - char *mime_type; /* MUST be lowercase */ - char *file_name; - const char *content_encoding; - apr_array_header_t *content_languages; /* list of languages for this variant */ - char *content_charset; - char *description; - - /* The next five items give the quality values for the dimensions - * of negotiation for this variant. They are obtained from the - * appropriate header lines, except for source_quality, which - * is obtained from the variant itself (the 'qs' parameter value - * from the variant's mime-type). Apart from source_quality, - * these values are set when we find the quality for each variant - * (see best_match()). source_quality is set from the 'qs' parameter - * of the variant description or mime type: see set_mime_fields(). - */ - float lang_quality; /* quality of this variant's language */ - float encoding_quality; /* ditto encoding */ - float charset_quality; /* ditto charset */ - float mime_type_quality; /* ditto media type */ - float source_quality; /* source quality for this variant */ - - /* Now some special values */ - float level; /* Auxiliary to content-type... */ - long bytes; /* content length, if known */ - int lang_index; /* pre HTTP/1.1 language priority stuff */ - int is_pseudo_html; /* text/html, *or* the INCLUDES_MAGIC_TYPEs */ - - /* Above are all written-once properties of the variant. The - * three fields below are changed during negotiation: - */ - - float level_matched; - int mime_stars; - int definite; -} var_rec; - -/* Something to carry around the state of negotiation (and to keep - * all of this thread-safe)... - */ - -typedef struct { - apr_pool_t *pool; - request_rec *r; - char *dir_name; - int accept_q; /* 1 if an Accept item has a q= param */ - float default_lang_quality; /* fiddle lang q for variants with no lang */ - - /* the array pointers below are NULL if the corresponding accept - * headers are not present - */ - apr_array_header_t *accepts; /* accept_recs */ - apr_array_header_t *accept_encodings; /* accept_recs */ - apr_array_header_t *accept_charsets; /* accept_recs */ - apr_array_header_t *accept_langs; /* accept_recs */ - - apr_array_header_t *avail_vars; /* available variants */ - - int count_multiviews_variants; /* number of variants found on disk */ - - int is_transparent; /* 1 if this resource is trans. negotiable */ - - int dont_fiddle_headers; /* 1 if we may not fiddle with accept hdrs */ - int ua_supports_trans; /* 1 if ua supports trans negotiation */ - int send_alternates; /* 1 if we want to send an Alternates header */ - int may_choose; /* 1 if we may choose a variant for the client */ - int use_rvsa; /* 1 if we must use RVSA/1.0 negotiation algo */ -} negotiation_state; - -/* A few functions to manipulate var_recs. - * Cleaning out the fields... - */ - -static void clean_var_rec(var_rec *mime_info) -{ - mime_info->sub_req = NULL; - mime_info->mime_type = ""; - mime_info->file_name = ""; - mime_info->content_encoding = NULL; - mime_info->content_languages = NULL; - mime_info->content_charset = ""; - mime_info->description = ""; - - mime_info->is_pseudo_html = 0; - mime_info->level = 0.0f; - mime_info->level_matched = 0.0f; - mime_info->bytes = 0; - mime_info->lang_index = -1; - mime_info->mime_stars = 0; - mime_info->definite = 1; - - mime_info->charset_quality = 1.0f; - mime_info->encoding_quality = 1.0f; - mime_info->lang_quality = 1.0f; - mime_info->mime_type_quality = 1.0f; - mime_info->source_quality = 0.0f; -} - -/* Initializing the relevant fields of a variant record from the - * accept_info read out of its content-type, one way or another. - */ - -static void set_mime_fields(var_rec *var, accept_rec *mime_info) -{ - var->mime_type = mime_info->name; - var->source_quality = mime_info->quality; - var->level = mime_info->level; - var->content_charset = mime_info->charset; - - var->is_pseudo_html = (!strcmp(var->mime_type, "text/html") - || !strcmp(var->mime_type, INCLUDES_MAGIC_TYPE) - || !strcmp(var->mime_type, INCLUDES_MAGIC_TYPE3)); -} - -/* Create a variant list validator in r using info from vlistr. */ - -static void set_vlist_validator(request_rec *r, request_rec *vlistr) -{ - /* Calculating the variant list validator is similar to - * calculating an etag for the source of the variant list - * information, so we use ap_make_etag(). Note that this - * validator can be 'weak' in extreme case. - */ - ap_update_mtime(vlistr, vlistr->finfo.mtime); - r->vlist_validator = ap_make_etag(vlistr, 0); - - /* ap_set_etag will later take r->vlist_validator into account - * when creating the etag header - */ -} - - -/***************************************************************** - * - * Parsing (lists of) media types and their parameters, as seen in - * HTTPD header lines and elsewhere. - */ - -/* - * Get a single mime type entry --- one media type and parameters; - * enter the values we recognize into the argument accept_rec - */ - -static const char *get_entry(apr_pool_t *p, accept_rec *result, - const char *accept_line) -{ - result->quality = 1.0f; - result->level = 0.0f; - result->charset = ""; - - /* - * Note that this handles what I gather is the "old format", - * - * Accept: text/html text/plain moo/zot - * - * without any compatibility kludges --- if the token after the - * MIME type begins with a semicolon, we know we're looking at parms, - * otherwise, we know we aren't. (So why all the pissing and moaning - * in the CERN server code? I must be missing something). - */ - - result->name = ap_get_token(p, &accept_line, 0); - ap_str_tolower(result->name); /* You want case insensitive, - * you'll *get* case insensitive. - */ - - /* KLUDGE!!! Default HTML to level 2.0 unless the browser - * *explicitly* says something else. - */ - - if (!strcmp(result->name, "text/html") && (result->level == 0.0)) { - result->level = 2.0f; - } - else if (!strcmp(result->name, INCLUDES_MAGIC_TYPE)) { - result->level = 2.0f; - } - else if (!strcmp(result->name, INCLUDES_MAGIC_TYPE3)) { - result->level = 3.0f; - } - - while (*accept_line == ';') { - /* Parameters ... */ - - char *parm; - char *cp; - char *end; - - ++accept_line; - parm = ap_get_token(p, &accept_line, 1); - - /* Look for 'var = value' --- and make sure the var is in lcase. */ - - for (cp = parm; (*cp && !apr_isspace(*cp) && *cp != '='); ++cp) { - *cp = apr_tolower(*cp); - } - - if (!*cp) { - continue; /* No '='; just ignore it. */ - } - - *cp++ = '\0'; /* Delimit var */ - while (*cp && (apr_isspace(*cp) || *cp == '=')) { - ++cp; - } - - if (*cp == '"') { - ++cp; - for (end = cp; - (*end && *end != '\n' && *end != '\r' && *end != '\"'); - end++); - } - else { - for (end = cp; (*end && !apr_isspace(*end)); end++); - } - if (*end) { - *end = '\0'; /* strip ending quote or return */ - } - ap_str_tolower(cp); - - if (parm[0] == 'q' - && (parm[1] == '\0' || (parm[1] == 's' && parm[2] == '\0'))) { - result->quality = (float)atof(cp); - } - else if (parm[0] == 'l' && !strcmp(&parm[1], "evel")) { - result->level = (float)atof(cp); - } - else if (!strcmp(parm, "charset")) { - result->charset = cp; - } - } - - if (*accept_line == ',') { - ++accept_line; - } - - return accept_line; -} - -/***************************************************************** - * - * Dealing with header lines ... - * - * Accept, Accept-Charset, Accept-Language and Accept-Encoding - * are handled by do_header_line() - they all have the same - * basic structure of a list of items of the format - * name; q=N; charset=TEXT - * - * where charset is only valid in Accept. - */ - -static apr_array_header_t *do_header_line(apr_pool_t *p, const char *accept_line) -{ - apr_array_header_t *accept_recs; - - if (!accept_line) { - return NULL; - } - - accept_recs = apr_array_make(p, 40, sizeof(accept_rec)); - - while (*accept_line) { - accept_rec *new = (accept_rec *) apr_array_push(accept_recs); - accept_line = get_entry(p, new, accept_line); - } - - return accept_recs; -} - -/* Given the text of the Content-Languages: line from the var map file, - * return an array containing the languages of this variant - */ - -static apr_array_header_t *do_languages_line(apr_pool_t *p, const char **lang_line) -{ - apr_array_header_t *lang_recs = apr_array_make(p, 2, sizeof(char *)); - - if (!lang_line) { - return lang_recs; - } - - while (**lang_line) { - char **new = (char **) apr_array_push(lang_recs); - *new = ap_get_token(p, lang_line, 0); - ap_str_tolower(*new); - if (**lang_line == ',' || **lang_line == ';') { - ++(*lang_line); - } - } - - return lang_recs; -} - -/***************************************************************** - * - * Handling header lines from clients... - */ - -static negotiation_state *parse_accept_headers(request_rec *r) -{ - negotiation_state *new = - (negotiation_state *) apr_pcalloc(r->pool, sizeof(negotiation_state)); - accept_rec *elts; - apr_table_t *hdrs = r->headers_in; - int i; - - new->pool = r->pool; - new->r = r; - new->dir_name = ap_make_dirstr_parent(r->pool, r->filename); - - new->accepts = do_header_line(r->pool, apr_table_get(hdrs, "Accept")); - - /* calculate new->accept_q value */ - if (new->accepts) { - elts = (accept_rec *) new->accepts->elts; - - for (i = 0; i < new->accepts->nelts; ++i) { - if (elts[i].quality < 1.0) { - new->accept_q = 1; - } - } - } - - new->accept_encodings = - do_header_line(r->pool, apr_table_get(hdrs, "Accept-Encoding")); - new->accept_langs = - do_header_line(r->pool, apr_table_get(hdrs, "Accept-Language")); - new->accept_charsets = - do_header_line(r->pool, apr_table_get(hdrs, "Accept-Charset")); - - new->avail_vars = apr_array_make(r->pool, 40, sizeof(var_rec)); - - return new; -} - - -static void parse_negotiate_header(request_rec *r, negotiation_state *neg) -{ - const char *negotiate = apr_table_get(r->headers_in, "Negotiate"); - char *tok; - - /* First, default to no TCN, no Alternates, and the original Apache - * negotiation algorithm with fiddles for broken browser configs. - * - * To save network bandwidth, we do not configure to send an - * Alternates header to the user agent by default. User - * agents that want an Alternates header for agent-driven - * negotiation will have to request it by sending an - * appropriate Negotiate header. - */ - neg->ua_supports_trans = 0; - neg->send_alternates = 0; - neg->may_choose = 1; - neg->use_rvsa = 0; - neg->dont_fiddle_headers = 0; - - if (!negotiate) - return; - - if (strcmp(negotiate, "trans") == 0) { - /* Lynx 2.7 and 2.8 send 'negotiate: trans' even though they - * do not support transparent content negotiation, so for Lynx we - * ignore the negotiate header when its contents are exactly "trans". - * If future versions of Lynx ever need to say 'negotiate: trans', - * they can send the equivalent 'negotiate: trans, trans' instead - * to avoid triggering the workaround below. - */ - const char *ua = apr_table_get(r->headers_in, "User-Agent"); - - if (ua && (strncmp(ua, "Lynx", 4) == 0)) - return; - } - - neg->may_choose = 0; /* An empty Negotiate would require 300 response */ - - while ((tok = ap_get_list_item(neg->pool, &negotiate)) != NULL) { - - if (strcmp(tok, "trans") == 0 || - strcmp(tok, "vlist") == 0 || - strcmp(tok, "guess-small") == 0 || - apr_isdigit(tok[0]) || - strcmp(tok, "*") == 0) { - - /* The user agent supports transparent negotiation */ - neg->ua_supports_trans = 1; - - /* Send-alternates could be configurable, but note - * that it must be 1 if we have 'vlist' in the - * negotiate header. - */ - neg->send_alternates = 1; - - if (strcmp(tok, "1.0") == 0) { - /* we may use the RVSA/1.0 algorithm, configure for it */ - neg->may_choose = 1; - neg->use_rvsa = 1; - neg->dont_fiddle_headers = 1; - } - else if (tok[0] == '*') { - /* we may use any variant selection algorithm, configure - * to use the Apache algorithm - */ - neg->may_choose = 1; - - /* We disable header fiddles on the assumption that a - * client sending Negotiate knows how to send correct - * headers which don't need fiddling. - */ - neg->dont_fiddle_headers = 1; - } - } - } - -#ifdef NEG_DEBUG - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "dont_fiddle_headers=%d use_rvsa=%d ua_supports_trans=%d " - "send_alternates=%d, may_choose=%d", - neg->dont_fiddle_headers, neg->use_rvsa, - neg->ua_supports_trans, neg->send_alternates, neg->may_choose); -#endif - -} - -/* Sometimes clients will give us no Accept info at all; this routine sets - * up the standard default for that case, and also arranges for us to be - * willing to run a CGI script if we find one. (In fact, we set up to - * dramatically prefer CGI scripts in cases where that's appropriate, - * e.g., POST or when URI includes query args or extra path info). - */ -static void maybe_add_default_accepts(negotiation_state *neg, - int prefer_scripts) -{ - accept_rec *new_accept; - - if (!neg->accepts) { - neg->accepts = apr_array_make(neg->pool, 4, sizeof(accept_rec)); - - new_accept = (accept_rec *) apr_array_push(neg->accepts); - - new_accept->name = "*/*"; - new_accept->quality = 1.0f; - new_accept->level = 0.0f; - } - - new_accept = (accept_rec *) apr_array_push(neg->accepts); - - new_accept->name = CGI_MAGIC_TYPE; - if (neg->use_rvsa) { - new_accept->quality = 0; - } - else { - new_accept->quality = prefer_scripts ? 2.0f : 0.001f; - } - new_accept->level = 0.0f; -} - -/***************************************************************** - * - * Parsing type-map files, in Roy's meta/http format augmented with - * #-comments. - */ - -/* Reading RFC822-style header lines, ignoring #-comments and - * handling continuations. - */ - -enum header_state { - header_eof, header_seen, header_sep -}; - -static enum header_state get_header_line(char *buffer, int len, apr_file_t *map) -{ - char *buf_end = buffer + len; - char *cp; - char c; - - /* Get a noncommented line */ - - do { - if (apr_file_gets(buffer, MAX_STRING_LEN, map) != APR_SUCCESS) { - return header_eof; - } - } while (buffer[0] == '#'); - - /* If blank, just return it --- this ends information on this variant */ - - for (cp = buffer; (*cp && apr_isspace(*cp)); ++cp) { - continue; - } - - if (*cp == '\0') { - return header_sep; - } - - /* If non-blank, go looking for header lines, but note that we still - * have to treat comments specially... - */ - - cp += strlen(cp); - - while (apr_file_getc(&c, map) != APR_EOF) { - if (c == '#') { - /* Comment line */ - while (apr_file_getc(&c, map) != EOF && c != '\n') { - continue; - } - } - else if (apr_isspace(c)) { - /* Leading whitespace. POSSIBLE continuation line - * Also, possibly blank --- if so, we ungetc() the final newline - * so that we will pick up the blank line the next time 'round. - */ - - while (c != '\n' && apr_isspace(c)) { - if(apr_file_getc(&c, map) != APR_SUCCESS) - break; - } - - apr_file_ungetc(c, map); - - if (c == '\n') { - return header_seen; /* Blank line */ - } - - /* Continuation */ - - while (cp < buf_end - 2 && (apr_file_getc(&c, map)) != EOF && c != '\n') { - *cp++ = c; - } - - *cp++ = '\n'; - *cp = '\0'; - } - else { - - /* Line beginning with something other than whitespace */ - - apr_file_ungetc(c, map); - return header_seen; - } - } - - return header_seen; -} - -/* Stripping out RFC822 comments */ - -static void strip_paren_comments(char *hdr) -{ - /* Hmmm... is this correct? In Roy's latest draft, (comments) can nest! */ - /* Nope, it isn't correct. Fails to handle backslash escape as well. */ - - while (*hdr) { - if (*hdr == '"') { - hdr = strchr(hdr, '"'); - if (hdr == NULL) { - return; - } - ++hdr; - } - else if (*hdr == '(') { - while (*hdr && *hdr != ')') { - *hdr++ = ' '; - } - - if (*hdr) { - *hdr++ = ' '; - } - } - else { - ++hdr; - } - } -} - -/* Getting to a header body from the header */ - -static char *lcase_header_name_return_body(char *header, request_rec *r) -{ - char *cp = header; - - for ( ; *cp && *cp != ':' ; ++cp) { - *cp = apr_tolower(*cp); - } - - if (!*cp) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Syntax error in type map --- no ':': %s", r->filename); - return NULL; - } - - do { - ++cp; - } while (*cp && apr_isspace(*cp)); - - if (!*cp) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Syntax error in type map --- no header body: %s", - r->filename); - return NULL; - } - - return cp; -} - -static int read_type_map(negotiation_state *neg, request_rec *rr) -{ - request_rec *r = neg->r; - apr_file_t *map = NULL; - apr_status_t status; - char buffer[MAX_STRING_LEN]; - enum header_state hstate; - struct var_rec mime_info; - int has_content; - - /* We are not using multiviews */ - neg->count_multiviews_variants = 0; - - if ((status = apr_file_open(&map, rr->filename, APR_READ, - APR_OS_DEFAULT, neg->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, - "cannot access type map file: %s", rr->filename); - return HTTP_FORBIDDEN; - } - - clean_var_rec(&mime_info); - has_content = 0; - - do { - hstate = get_header_line(buffer, MAX_STRING_LEN, map); - - if (hstate == header_seen) { - char *body1 = lcase_header_name_return_body(buffer, neg->r); - const char *body; - - if (body1 == NULL) { - return HTTP_INTERNAL_SERVER_ERROR; - } - - strip_paren_comments(body1); - body = body1; - - if (!strncmp(buffer, "uri:", 4)) { - mime_info.file_name = ap_get_token(neg->pool, &body, 0); - } - else if (!strncmp(buffer, "content-type:", 13)) { - struct accept_rec accept_info; - - get_entry(neg->pool, &accept_info, body); - set_mime_fields(&mime_info, &accept_info); - has_content = 1; - } - else if (!strncmp(buffer, "content-length:", 15)) { - mime_info.bytes = atol(body); - has_content = 1; - } - else if (!strncmp(buffer, "content-language:", 17)) { - mime_info.content_languages = do_languages_line(neg->pool, - &body); - has_content = 1; - } - else if (!strncmp(buffer, "content-encoding:", 17)) { - mime_info.content_encoding = ap_get_token(neg->pool, &body, 0); - has_content = 1; - } - else if (!strncmp(buffer, "description:", 12)) { - char *desc = apr_pstrdup(neg->pool, body); - char *cp; - - for (cp = desc; *cp; ++cp) { - if (*cp=='\n') *cp=' '; - } - if (cp>desc) *(cp-1)=0; - mime_info.description = desc; - } - } - else { - if (*mime_info.file_name && has_content) { - void *new_var = apr_array_push(neg->avail_vars); - - memcpy(new_var, (void *) &mime_info, sizeof(var_rec)); - } - - clean_var_rec(&mime_info); - has_content = 0; - } - } while (hstate != header_eof); - - apr_file_close(map); - - set_vlist_validator(r, rr); - - return OK; -} - - -/* Sort function used by read_types_multi. */ -static int variantsortf(var_rec *a, var_rec *b) { - - /* First key is the source quality, sort in descending order. */ - - /* XXX: note that we currently implement no method of setting the - * source quality for multiviews variants, so we are always comparing - * 1.0 to 1.0 for now - */ - if (a->source_quality < b->source_quality) - return 1; - if (a->source_quality > b->source_quality) - return -1; - - /* Second key is the variant name */ - return strcmp(a->file_name, b->file_name); -} - -/***************************************************************** - * - * Same as read_type_map, except we use a filtered directory listing - * as the map... - */ - -static int read_types_multi(negotiation_state *neg) -{ - request_rec *r = neg->r; - - char *filp; - int prefix_len; - apr_dir_t *dirp; - apr_finfo_t dirent; - apr_status_t status; - struct var_rec mime_info; - struct accept_rec accept_info; - void *new_var; - - clean_var_rec(&mime_info); - - if (!(filp = strrchr(r->filename, '/'))) { - return DECLINED; /* Weird... */ - } - - if (strncmp(r->filename, "proxy:", 6) == 0) { - return DECLINED; - } - - ++filp; - prefix_len = strlen(filp); - - if ((status = apr_dir_open(&dirp, neg->dir_name, neg->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, - "cannot read directory for multi: %s", neg->dir_name); - return HTTP_FORBIDDEN; - } - - while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) { - request_rec *sub_req; - - /* Do we have a match? */ - if (strncmp(dirent.name, filp, prefix_len)) { - continue; - } - if (dirent.name[prefix_len] != '.') { - continue; - } - - /* Yep. See if it's something which we have access to, and - * which has a known type and encoding (as opposed to something - * which we'll be slapping default_type on later). - */ - - sub_req = ap_sub_req_lookup_file(dirent.name, r, NULL); - - /* If it has a handler, we'll pretend it's a CGI script, - * since that's a good indication of the sort of thing it - * might be doing. - */ - if (sub_req->handler && !sub_req->content_type) { - sub_req->content_type = CGI_MAGIC_TYPE; - } - - if (sub_req->status != HTTP_OK || !sub_req->content_type) { - ap_destroy_sub_req(sub_req); - continue; - } - - /* If it's a map file, we use that instead of the map - * we're building... - */ - - if (((sub_req->content_type) && - !strcmp(sub_req->content_type, MAP_FILE_MAGIC_TYPE)) || - ((sub_req->handler) && - !strcmp(sub_req->handler, "type-map"))) { - - apr_dir_close(dirp); - neg->avail_vars->nelts = 0; - if (sub_req->status != HTTP_OK) { - return sub_req->status; - } - return read_type_map(neg, sub_req); - } - - /* Have reasonable variant --- gather notes. */ - - mime_info.sub_req = sub_req; - mime_info.file_name = apr_pstrdup(neg->pool, dirent.name); - if (sub_req->content_encoding) { - mime_info.content_encoding = sub_req->content_encoding; - } - if (sub_req->content_languages) { - mime_info.content_languages = sub_req->content_languages; - } - - get_entry(neg->pool, &accept_info, sub_req->content_type); - set_mime_fields(&mime_info, &accept_info); - - new_var = apr_array_push(neg->avail_vars); - memcpy(new_var, (void *) &mime_info, sizeof(var_rec)); - - neg->count_multiviews_variants++; - - clean_var_rec(&mime_info); - } - - apr_dir_close(dirp); - - set_vlist_validator(r, r); - - /* Sort the variants into a canonical order. The negotiation - * result sometimes depends on the order of the variants. By - * sorting the variants into a canonical order, rather than using - * the order in which readdir() happens to return them, we ensure - * that the negotiation result will be consistent over filesystem - * backup/restores and over all mirror sites. - */ - - qsort((void *) neg->avail_vars->elts, neg->avail_vars->nelts, - sizeof(var_rec), (int (*)(const void *, const void *)) variantsortf); - - return OK; -} - - -/***************************************************************** - * And now for the code you've been waiting for... actually - * finding a match to the client's requirements. - */ - -/* Matching MIME types ... the star/star and foo/star commenting conventions - * are implemented here. (You know what I mean by star/star, but just - * try mentioning those three characters in a C comment). Using strcmp() - * is legit, because everything has already been smashed to lowercase. - * - * Note also that if we get an exact match on the media type, we update - * level_matched for use in level_cmp below... - * - * We also give a value for mime_stars, which is used later. It should - * be 1 for star/star, 2 for type/star and 3 for type/subtype. - */ - -static int mime_match(accept_rec *accept_r, var_rec *avail) -{ - char *accept_type = accept_r->name; - char *avail_type = avail->mime_type; - int len = strlen(accept_type); - - if (accept_type[0] == '*') { /* Anything matches star/star */ - if (avail->mime_stars < 1) { - avail->mime_stars = 1; - } - return 1; - } - else if ((accept_type[len - 1] == '*') && - !strncmp(accept_type, avail_type, len - 2)) { - if (avail->mime_stars < 2) { - avail->mime_stars = 2; - } - return 1; - } - else if (!strcmp(accept_type, avail_type) - || (!strcmp(accept_type, "text/html") - && (!strcmp(avail_type, INCLUDES_MAGIC_TYPE) - || !strcmp(avail_type, INCLUDES_MAGIC_TYPE3)))) { - if (accept_r->level >= avail->level) { - avail->level_matched = avail->level; - avail->mime_stars = 3; - return 1; - } - } - - return OK; -} - -/* This code implements a piece of the tie-breaking algorithm between - * variants of equal quality. This piece is the treatment of variants - * of the same base media type, but different levels. What we want to - * return is the variant at the highest level that the client explicitly - * claimed to accept. - * - * If all the variants available are at a higher level than that, or if - * the client didn't say anything specific about this media type at all - * and these variants just got in on a wildcard, we prefer the lowest - * level, on grounds that that's the one that the client is least likely - * to choke on. - * - * (This is all motivated by treatment of levels in HTML --- we only - * want to give level 3 to browsers that explicitly ask for it; browsers - * that don't, including HTTP/0.9 browsers that only get the implicit - * "Accept: * / *" [space added to avoid confusing cpp --- no, that - * syntax doesn't really work] should get HTML2 if available). - * - * (Note that this code only comes into play when we are choosing among - * variants of equal quality, where the draft standard gives us a fair - * bit of leeway about what to do. It ain't specified by the standard; - * rather, it is a choice made by this server about what to do in cases - * where the standard does not specify a unique course of action). - */ - -static int level_cmp(var_rec *var1, var_rec *var2) -{ - /* Levels are only comparable between matching media types */ - - if (var1->is_pseudo_html && !var2->is_pseudo_html) { - return 0; - } - - if (!var1->is_pseudo_html && strcmp(var1->mime_type, var2->mime_type)) { - return 0; - } - /* The result of the above if statements is that, if we get to - * here, both variants have the same mime_type or both are - * pseudo-html. - */ - - /* Take highest level that matched, if either did match. */ - - if (var1->level_matched > var2->level_matched) { - return 1; - } - if (var1->level_matched < var2->level_matched) { - return -1; - } - - /* Neither matched. Take lowest level, if there's a difference. */ - - if (var1->level < var2->level) { - return 1; - } - if (var1->level > var2->level) { - return -1; - } - - /* Tied */ - - return 0; -} - -/* Finding languages. The main entry point is set_language_quality() - * which is called for each variant. It sets two elements in the - * variant record: - * language_quality - the 'q' value of the 'best' matching language - * from Accept-Language: header (HTTP/1.1) - * lang_index - Pre HTTP/1.1 language priority, using - * position of language on the Accept-Language: - * header, if present, else LanguagePriority - * directive order. - * - * When we do the variant checking for best variant, we use language - * quality first, and if a tie, language_index next (this only applies - * when _not_ using the RVSA/1.0 algorithm). If using the RVSA/1.0 - * algorithm, lang_index is never used. - * - * set_language_quality() calls find_lang_index() and find_default_index() - * to set lang_index. - */ - -static int find_lang_index(apr_array_header_t *accept_langs, char *lang) -{ - accept_rec *accs; - int i; - - if (!lang || !accept_langs) { - return -1; - } - - accs = (accept_rec *) accept_langs->elts; - - for (i = 0; i < accept_langs->nelts; ++i) { - if (!strncmp(lang, accs[i].name, strlen(accs[i].name))) { - return i; - } - } - - return -1; -} - -/* This function returns the priority of a given language - * according to LanguagePriority. It is used in case of a tie - * between several languages. - */ - -static int find_default_index(neg_dir_config *conf, char *lang) -{ - apr_array_header_t *arr; - int nelts; - char **elts; - int i; - - if (!lang) { - return -1; - } - - arr = conf->language_priority; - nelts = arr->nelts; - elts = (char **) arr->elts; - - for (i = 0; i < nelts; ++i) { - if (!strcasecmp(elts[i], lang)) { - return i; - } - } - - return -1; -} - -/* set_default_lang_quality() sets the quality we apply to variants - * which have no language assigned to them. If none of the variants - * have a language, we are not negotiating on language, so all are - * acceptable, and we set the default q value to 1.0. However if - * some of the variants have languages, we set this default to 0.001. - * The value of this default will be applied to all variants with - * no explicit language -- which will have the effect of making them - * acceptable, but only if no variants with an explicit language - * are acceptable. The default q value set here is assigned to variants - * with no language type in set_language_quality(). - * - * Note that if using the RVSA/1.0 algorithm, we don't use this - * fiddle. - */ - -static void set_default_lang_quality(negotiation_state *neg) -{ - var_rec *avail_recs = (var_rec *) neg->avail_vars->elts; - int j; - - if (!neg->dont_fiddle_headers) { - for (j = 0; j < neg->avail_vars->nelts; ++j) { - var_rec *variant = &avail_recs[j]; - if (variant->content_languages && - variant->content_languages->nelts) { - neg->default_lang_quality = 0.001f; - return; - } - } - } - - neg->default_lang_quality = 1.0f; -} - -/* Set the language_quality value in the variant record. Also - * assigns lang_index for back-compat. - * - * To find the language_quality value, we look for the 'q' value - * of the 'best' matching language on the Accept-Language - * header. The 'best' match is the language on Accept-Language - * header which matches the language of this variant either fully, - * or as far as the prefix marker (-). If two or more languages - * match, use the longest string from the Accept-Language header - * (see HTTP/1.1 [14.4]) - * - * When a variant has multiple languages, we find the 'best' - * match for each variant language tag as above, then select the - * one with the highest q value. Because both the accept-header - * and variant can have multiple languages, we now have a hairy - * loop-within-a-loop here. - * - * If the variant has no language and we have no Accept-Language - * items, leave the quality at 1.0 and return. - * - * If the variant has no language, we use the default as set by - * set_default_lang_quality() (1.0 if we are not negotiating on - * language, 0.001 if we are). - * - * Following the setting of the language quality, we drop through to - * set the old 'lang_index'. This is set based on either the order - * of the languages on the Accept-Language header, or the - * order on the LanguagePriority directive. This is only used - * in the negotiation if the language qualities tie. - */ - -static void set_language_quality(negotiation_state *neg, var_rec *variant) -{ - char *firstlang; - int idx; - - if (!variant->content_languages || !variant->content_languages->nelts) { - /* This variant has no content-language, so use the default - * quality factor for variants with no content-language - * (previously set by set_default_lang_quality()). - * Leave the factor alone (it remains at 1.0) when we may not fiddle - * with the headers. - */ - if (!neg->dont_fiddle_headers) { - variant->lang_quality = neg->default_lang_quality; - } - if (!neg->accept_langs) { - return; /* no accept-language header */ - } - - } - else { - /* Variant has one (or more) languages. Look for the best - * match. We do this by going through each language on the - * variant description looking for a match on the - * Accept-Language header. The best match is the longest - * matching language on the header. The final result is the - * best q value from all the languages on the variant - * description. - */ - - if (!neg->accept_langs) { - /* no accept-language header makes the variant indefinite */ - variant->definite = 0; - } - else { /* There is an accept-language with 0 or more items */ - accept_rec *accs = (accept_rec *) neg->accept_langs->elts; - accept_rec *best = NULL, *star = NULL; - accept_rec *bestthistag; - char *lang, *p; - float fiddle_q = 0.0f; - int any_match_on_star = 0; - int i, j; - size_t alen, longest_lang_range_len; - - for (j = 0; j < variant->content_languages->nelts; ++j) { - p = NULL; - bestthistag = NULL; - longest_lang_range_len = 0; - alen = 0; - - /* lang is the variant's language-tag, which is the one - * we are allowed to use the prefix of in HTTP/1.1 - */ - lang = ((char **) (variant->content_languages->elts))[j]; - - /* now find the best (i.e. longest) matching - * Accept-Language header language. We put the best match - * for this tag in bestthistag. We cannot update the - * overall best (based on q value) because the best match - * for this tag is the longest language item on the accept - * header, not necessarily the highest q. - */ - for (i = 0; i < neg->accept_langs->nelts; ++i) { - if (!strcmp(accs[i].name, "*")) { - if (!star) { - star = &accs[i]; - } - continue; - } - /* Find language. We match if either the variant - * language tag exactly matches the language range - * from the accept header, or a prefix of the variant - * language tag up to a '-' character matches the - * whole of the language range in the Accept-Language - * header. Note that HTTP/1.x allows any number of - * '-' characters in a tag or range, currently only - * tags with zero or one '-' characters are defined - * for general use (see rfc1766). - * - * We only use language range in the Accept-Language - * header the best match for the variant language tag - * if it is longer than the previous best match. - */ - - alen = strlen(accs[i].name); - - if ((strlen(lang) >= alen) && - !strncmp(lang, accs[i].name, alen) && - ((lang[alen] == 0) || (lang[alen] == '-')) ) { - - if (alen > longest_lang_range_len) { - longest_lang_range_len = alen; - bestthistag = &accs[i]; - } - } - - if (!bestthistag && !neg->dont_fiddle_headers) { - /* The next bit is a fiddle. Some browsers might - * be configured to send more specific language - * ranges than desirable. For example, an - * Accept-Language of en-US should never match - * variants with languages en or en-GB. But US - * English speakers might pick en-US as their - * language choice. So this fiddle checks if the - * language range has a prefix, and if so, it - * matches variants which match that prefix with a - * priority of 0.001. So a request for en-US would - * match variants of types en and en-GB, but at - * much lower priority than matches of en-US - * directly, or of any other language listed on - * the Accept-Language header. Note that this - * fiddle does not handle multi-level prefixes. - */ - if ((p = strchr(accs[i].name, '-'))) { - int plen = p - accs[i].name; - - if (!strncmp(lang, accs[i].name, plen)) { - fiddle_q = 0.001f; - } - } - } - } - /* Finished looking at Accept-Language headers, the best - * (longest) match is in bestthistag, or NULL if no match - */ - if (!best || - (bestthistag && bestthistag->quality > best->quality)) { - best = bestthistag; - } - - /* See if the tag matches on a * in the Accept-Language - * header. If so, record this fact for later use - */ - if (!bestthistag && star) { - any_match_on_star = 1; - } - } - - /* If one of the language tags of the variant matched on *, we - * need to see if its q is better than that of any non-* match - * on any other tag of the variant. If so the * match takes - * precedence and the overall match is not definite. - */ - if ( any_match_on_star && - ((best && star->quality > best->quality) || - (!best)) ) { - best = star; - variant->definite = 0; - } - - variant->lang_quality = best ? best->quality : fiddle_q; - } - } - - /* Now set the old lang_index field. Since this is old - * stuff anyway, don't bother with handling multiple languages - * per variant, just use the first one assigned to it - */ - idx = 0; - if (variant->content_languages && variant->content_languages->nelts) { - firstlang = ((char **) variant->content_languages->elts)[0]; - } - else { - firstlang = ""; - } - if (!neg->accept_langs) { /* Client doesn't care */ - idx = find_default_index((neg_dir_config *) ap_get_module_config( - neg->r->per_dir_config, &negotiation_module), - firstlang); - } - else { /* Client has Accept-Language */ - idx = find_lang_index(neg->accept_langs, firstlang); - } - variant->lang_index = idx; - - return; -} - -/* Determining the content length --- if the map didn't tell us, - * we have to do a stat() and remember for next time. - * - * Grump. For Apache, even the first stat here may well be - * redundant (for multiviews) with a stat() done by the sub_req - * machinery. At some point, that ought to be fixed. - */ - -static long find_content_length(negotiation_state *neg, var_rec *variant) -{ - apr_finfo_t statb; - - if (variant->bytes == 0) { - char *fullname = ap_make_full_path(neg->pool, neg->dir_name, - variant->file_name); - - if (apr_stat(&statb, fullname, - APR_FINFO_SIZE, neg->pool) == APR_SUCCESS) { - variant->bytes = statb.size; - } - } - - return variant->bytes; -} - -/* For a given variant, find the best matching Accept: header - * and assign the Accept: header's quality value to the - * mime_type_quality field of the variant, for later use in - * determining the best matching variant. - */ - -static void set_accept_quality(negotiation_state *neg, var_rec *variant) -{ - int i; - accept_rec *accept_recs; - float q = 0.0f; - int q_definite = 1; - - /* if no Accept: header, leave quality alone (will - * remain at the default value of 1) - * - * XXX: This if is currently never true because of the effect of - * maybe_add_default_accepts(). - */ - if (!neg->accepts) { - if (variant->mime_type && *variant->mime_type) - variant->definite = 0; - return; - } - - accept_recs = (accept_rec *) neg->accepts->elts; - - /* - * Go through each of the ranges on the Accept: header, - * looking for the 'best' match with this variant's - * content-type. We use the best match's quality - * value (from the Accept: header) for this variant's - * mime_type_quality field. - * - * The best match is determined like this: - * type/type is better than type/ * is better than * / * - * if match is type/type, use the level mime param if available - */ - for (i = 0; i < neg->accepts->nelts; ++i) { - - accept_rec *type = &accept_recs[i]; - int prev_mime_stars; - - prev_mime_stars = variant->mime_stars; - - if (!mime_match(type, variant)) { - continue; /* didn't match the content type at all */ - } - else { - /* did match - see if there were less or more stars than - * in previous match - */ - if (prev_mime_stars == variant->mime_stars) { - continue; /* more stars => not as good a match */ - } - } - - /* If we are allowed to mess with the q-values - * and have no explicit q= parameters in the accept header, - * make wildcards very low, so we have a low chance - * of ending up with them if there's something better. - */ - - if (!neg->dont_fiddle_headers && !neg->accept_q && - variant->mime_stars == 1) { - q = 0.01f; - } - else if (!neg->dont_fiddle_headers && !neg->accept_q && - variant->mime_stars == 2) { - q = 0.02f; - } - else { - q = type->quality; - } - - q_definite = (variant->mime_stars == 3); - } - variant->mime_type_quality = q; - variant->definite = variant->definite && q_definite; - -} - -/* For a given variant, find the 'q' value of the charset given - * on the Accept-Charset line. If no charsets are listed, - * assume value of '1'. - */ -static void set_charset_quality(negotiation_state *neg, var_rec *variant) -{ - int i; - accept_rec *accept_recs; - char *charset = variant->content_charset; - accept_rec *star = NULL; - - /* if no Accept-Charset: header, leave quality alone (will - * remain at the default value of 1) - */ - if (!neg->accept_charsets) { - if (charset && *charset) - variant->definite = 0; - return; - } - - accept_recs = (accept_rec *) neg->accept_charsets->elts; - - if (charset == NULL || !*charset) { - /* Charset of variant not known */ - - /* if not a text / * type, leave quality alone */ - if (!(!strncmp(variant->mime_type, "text/", 5) - || !strcmp(variant->mime_type, INCLUDES_MAGIC_TYPE) - || !strcmp(variant->mime_type, INCLUDES_MAGIC_TYPE3) - )) - return; - - /* Don't go guessing if we are in strict header mode, - * e.g. when running the rvsa, as any guess won't be reflected - * in the variant list or content-location headers. - */ - if (neg->dont_fiddle_headers) - return; - - charset = "iso-8859-1"; /* The default charset for HTTP text types */ - } - - /* - * Go through each of the items on the Accept-Charset header, - * looking for a match with this variant's charset. If none - * match, charset is unacceptable, so set quality to 0. - */ - for (i = 0; i < neg->accept_charsets->nelts; ++i) { - - accept_rec *type = &accept_recs[i]; - - if (!strcmp(type->name, charset)) { - variant->charset_quality = type->quality; - return; - } - else if (strcmp(type->name, "*") == 0) { - star = type; - } - } - /* No explicit match */ - if (star) { - variant->charset_quality = star->quality; - variant->definite = 0; - return; - } - /* If this variant is in charset iso-8859-1, the default is 1.0 */ - if (strcmp(charset, "iso-8859-1") == 0) { - variant->charset_quality = 1.0f; - } - else { - variant->charset_quality = 0.0f; - } -} - - -/* is_identity_encoding is included for back-compat, but does anyone - * use 7bit, 8bin or binary in their var files?? - */ - -static int is_identity_encoding(const char *enc) -{ - return (!enc || !enc[0] || !strcmp(enc, "7bit") || !strcmp(enc, "8bit") - || !strcmp(enc, "binary")); -} - -/* - * set_encoding_quality determines whether the encoding for a particular - * variant is acceptable for the user-agent. - * - * The rules for encoding are that if the user-agent does not supply - * any Accept-Encoding header, then all encodings are allowed but a - * variant with no encoding should be preferred. - * If there is an empty Accept-Encoding header, then no encodings are - * acceptable. If there is a non-empty Accept-Encoding header, then - * any of the listed encodings are acceptable, as well as no encoding - * unless the "identity" encoding is specifically excluded. - */ -static void set_encoding_quality(negotiation_state *neg, var_rec *variant) -{ - accept_rec *accept_recs; - const char *enc = variant->content_encoding; - accept_rec *star = NULL; - float value_if_not_found = 0.0f; - int i; - - if (!neg->accept_encodings) { - /* We had no Accept-Encoding header, assume that all - * encodings are acceptable with a low quality, - * but we prefer no encoding if available. - */ - if (!enc || is_identity_encoding(enc)) - variant->encoding_quality = 1.0f; - else - variant->encoding_quality = 0.5f; - - return; - } - - if (!enc || is_identity_encoding(enc)) { - enc = "identity"; - value_if_not_found = 0.0001f; - } - - accept_recs = (accept_rec *) neg->accept_encodings->elts; - - /* Go through each of the encodings on the Accept-Encoding: header, - * looking for a match with our encoding. x- prefixes are ignored. - */ - if (enc[0] == 'x' && enc[1] == '-') { - enc += 2; - } - for (i = 0; i < neg->accept_encodings->nelts; ++i) { - - char *name = accept_recs[i].name; - - if (name[0] == 'x' && name[1] == '-') { - name += 2; - } - - if (!strcmp(name, enc)) { - variant->encoding_quality = accept_recs[i].quality; - return; - } - - if (strcmp(name, "*") == 0) { - star = &accept_recs[i]; - } - - } - /* No explicit match */ - if (star) { - variant->encoding_quality = star->quality; - return; - } - - /* Encoding not found on Accept-Encoding: header, so it is - * _not_ acceptable unless it is the identity (no encoding) - */ - variant->encoding_quality = value_if_not_found; -} - -/************************************************************* - * Possible results of the variant selection algorithm - */ -enum algorithm_results { - alg_choice = 1, /* choose variant */ - alg_list /* list variants */ -}; - -/* Below is the 'best_match' function. It returns an int, which has - * one of the two values alg_choice or alg_list, which give the result - * of the variant selection algorithm. alg_list means that no best - * variant was found by the algorithm, alg_choice means that a best - * variant was found and should be returned. The list/choice - * terminology comes from TCN (rfc2295), but is used in a more generic - * way here. The best variant is returned in *pbest. best_match has - * two possible algorithms for determining the best variant: the - * RVSA/1.0 algorithm (from RFC2296), and the standard Apache - * algorithm. These are split out into separate functions - * (is_variant_better_rvsa() and is_variant_better()). Selection of - * one is through the neg->use_rvsa flag. - * - * The call to best_match also creates full information, including - * language, charset, etc quality for _every_ variant. This is needed - * for generating a correct Vary header, and can be used for the - * Alternates header, the human-readable list responses and 406 errors. - */ - -/* Firstly, the RVSA/1.0 (HTTP Remote Variant Selection Algorithm - * v1.0) from rfc2296. This is the algorithm that goes together with - * transparent content negotiation (TCN). - */ -static int is_variant_better_rvsa(negotiation_state *neg, var_rec *variant, - var_rec *best, float *p_bestq) -{ - float bestq = *p_bestq, q; - - /* TCN does not cover negotiation on content-encoding. For now, - * we ignore the encoding unless it was explicitly excluded. - */ - if (variant->encoding_quality == 0.0f) - return 0; - - q = variant->mime_type_quality * - variant->source_quality * - variant->charset_quality * - variant->lang_quality; - - /* RFC 2296 calls for the result to be rounded to 5 decimal places, - * but we don't do that because it serves no useful purpose other - * than to ensure that a remote algorithm operates on the same - * precision as ours. That is silly, since what we obviously want - * is for the algorithm to operate on the best available precision - * regardless of who runs it. Since the above calculation may - * result in significant variance at 1e-12, rounding would be bogus. - */ - -#ifdef NEG_DEBUG - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Variant: file=%s type=%s lang=%s sourceq=%1.3f " - "mimeq=%1.3f langq=%1.3f charq=%1.3f encq=%1.3f " - "q=%1.5f definite=%d", - (variant->file_name ? variant->file_name : ""), - (variant->mime_type ? variant->mime_type : ""), - (variant->content_languages - ? apr_array_pstrcat(neg->pool, variant->content_languages, ',') - : ""), - variant->source_quality, - variant->mime_type_quality, - variant->lang_quality, - variant->charset_quality, - variant->encoding_quality, - q, - variant->definite); -#endif - - if (q <= 0.0f) { - return 0; - } - if (q > bestq) { - *p_bestq = q; - return 1; - } - if (q == bestq) { - /* If the best variant's encoding is of lesser quality than - * this variant, then we prefer this variant - */ - if (variant->encoding_quality > best->encoding_quality) { - *p_bestq = q; - return 1; - } - } - return 0; -} - -/* Negotiation algorithm as used by previous versions of Apache - * (just about). - */ - -static int is_variant_better(negotiation_state *neg, var_rec *variant, - var_rec *best, float *p_bestq) -{ - float bestq = *p_bestq, q; - int levcmp; - - /* For non-transparent negotiation, server can choose how - * to handle the negotiation. We'll use the following in - * order: content-type, language, content-type level, charset, - * content encoding, content length. - * - * For each check, we have three possible outcomes: - * This variant is worse than current best: return 0 - * This variant is better than the current best: - * assign this variant's q to *p_bestq, and return 1 - * This variant is just as desirable as the current best: - * drop through to the next test. - * - * This code is written in this long-winded way to allow future - * customisation, either by the addition of additional - * checks, or to allow the order of the checks to be determined - * by configuration options (e.g. we might prefer to check - * language quality _before_ content type). - */ - - /* First though, eliminate this variant if it is not - * acceptable by type, charset, encoding or language. - */ - -#ifdef NEG_DEBUG - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Variant: file=%s type=%s lang=%s sourceq=%1.3f " - "mimeq=%1.3f langq=%1.3f langidx=%d charq=%1.3f encq=%1.3f ", - (variant->file_name ? variant->file_name : ""), - (variant->mime_type ? variant->mime_type : ""), - (variant->content_languages - ? apr_array_pstrcat(neg->pool, variant->content_languages, ',') - : ""), - variant->source_quality, - variant->mime_type_quality, - variant->lang_quality, - variant->lang_index, - variant->charset_quality, - variant->encoding_quality); -#endif - - if (variant->encoding_quality == 0.0f || - variant->lang_quality == 0.0f || - variant->source_quality == 0.0f || - variant->charset_quality == 0.0f || - variant->mime_type_quality == 0.0f) { - return 0; /* don't consider unacceptables */ - } - - q = variant->mime_type_quality * variant->source_quality; - if (q == 0.0 || q < bestq) { - return 0; - } - if (q > bestq || !best) { - *p_bestq = q; - return 1; - } - - /* language */ - if (variant->lang_quality < best->lang_quality) { - return 0; - } - if (variant->lang_quality > best->lang_quality) { - *p_bestq = q; - return 1; - } - - /* if language qualities were equal, try the LanguagePriority stuff */ - if (best->lang_index != -1 && - (variant->lang_index == -1 || variant->lang_index > best->lang_index)) { - return 0; - } - if (variant->lang_index != -1 && - (best->lang_index == -1 || variant->lang_index < best->lang_index)) { - *p_bestq = q; - return 1; - } - - /* content-type level (sometimes used with text/html, though we - * support it on other types too) - */ - levcmp = level_cmp(variant, best); - if (levcmp == -1) { - return 0; - } - if (levcmp == 1) { - *p_bestq = q; - return 1; - } - - /* charset */ - if (variant->charset_quality < best->charset_quality) { - return 0; - } - /* If the best variant's charset is ISO-8859-1 and this variant has - * the same charset quality, then we prefer this variant - */ - - if (variant->charset_quality > best->charset_quality || - ((variant->content_charset != NULL && - *variant->content_charset != '\0' && - strcmp(variant->content_charset, "iso-8859-1") != 0) && - (best->content_charset == NULL || - *best->content_charset == '\0' || - strcmp(best->content_charset, "iso-8859-1") == 0))) { - *p_bestq = q; - return 1; - } - - /* Prefer the highest value for encoding_quality. - */ - if (variant->encoding_quality < best->encoding_quality) { - return 0; - } - if (variant->encoding_quality > best->encoding_quality) { - *p_bestq = q; - return 1; - } - - /* content length if all else equal */ - if (find_content_length(neg, variant) >= find_content_length(neg, best)) { - return 0; - } - - /* ok, to get here means every thing turned out equal, except - * we have a shorter content length, so use this variant - */ - *p_bestq = q; - return 1; -} - -static int best_match(negotiation_state *neg, var_rec **pbest) -{ - int j; - var_rec *best = NULL; - float bestq = 0.0f; - enum algorithm_results algorithm_result; - - var_rec *avail_recs = (var_rec *) neg->avail_vars->elts; - - set_default_lang_quality(neg); - - /* - * Find the 'best' variant - */ - - for (j = 0; j < neg->avail_vars->nelts; ++j) { - var_rec *variant = &avail_recs[j]; - - /* Find all the relevant 'quality' values from the - * Accept... headers, and store in the variant. This also - * prepares for sending an Alternates header etc so we need to - * do it even if we do not actually plan to find a best - * variant. - */ - set_accept_quality(neg, variant); - set_language_quality(neg, variant); - set_encoding_quality(neg, variant); - set_charset_quality(neg, variant); - - /* Only do variant selection if we may actually choose a - * variant for the client - */ - if (neg->may_choose) { - - /* Now find out if this variant is better than the current - * best, either using the RVSA/1.0 algorithm, or Apache's - * internal server-driven algorithm. Presumably other - * server-driven algorithms are possible, and could be - * implemented here. - */ - - if (neg->use_rvsa) { - if (is_variant_better_rvsa(neg, variant, best, &bestq)) { - best = variant; - } - } - else { - if (is_variant_better(neg, variant, best, &bestq)) { - best = variant; - } - } - } - } - - /* We now either have a best variant, or no best variant */ - - if (neg->use_rvsa) { - /* calculate result for RVSA/1.0 algorithm: - * only a choice response if the best variant has q>0 - * and is definite - */ - algorithm_result = (best && best->definite) && (bestq > 0) ? - alg_choice : alg_list; - } - else { - /* calculate result for Apache negotiation algorithm */ - algorithm_result = bestq > 0 ? alg_choice : alg_list; - } - - /* Returning a choice response with a non-neighboring variant is a - * protocol security error in TCN (see rfc2295). We do *not* - * verify here that the variant and URI are neighbors, even though - * we may return alg_choice. We depend on the environment (the - * caller) to only declare the resource transparently negotiable if - * all variants are neighbors. - */ - *pbest = best; - return algorithm_result; -} - -/* Sets response headers for a negotiated response. - * neg->is_transparent determines whether a transparently negotiated - * response or a plain `server driven negotiation' response is - * created. Applicable headers are Alternates, Vary, and TCN. - * - * The Vary header we create is sometimes longer than is required for - * the correct caching of negotiated results by HTTP/1.1 caches. For - * example if we have 3 variants x.html, x.ps.en and x.ps.nl, and if - * the Accept: header assigns a 0 quality to .ps, then the results of - * the two server-side negotiation algorithms we currently implement - * will never depend on Accept-Language so we could return `Vary: - * negotiate, accept' instead of the longer 'Vary: negotiate, accept, - * accept-language' which the code below will return. A routine for - * computing the exact minimal Vary header would be a huge pain to code - * and maintain though, especially because we need to take all possible - * twiddles in the server-side negotiation algorithms into account. - */ -static void set_neg_headers(request_rec *r, negotiation_state *neg, - int alg_result) -{ - apr_table_t *hdrs; - var_rec *avail_recs = (var_rec *) neg->avail_vars->elts; - const char *sample_type = NULL; - const char *sample_language = NULL; - const char *sample_encoding = NULL; - const char *sample_charset = NULL; - char *lang; - char *qstr; - char *lenstr; - long len; - apr_array_header_t *arr; - int max_vlist_array = (neg->avail_vars->nelts * 21); - int first_variant = 1; - int vary_by_type = 0; - int vary_by_language = 0; - int vary_by_charset = 0; - int vary_by_encoding = 0; - int j; - - /* In order to avoid O(n^2) memory copies in building Alternates, - * we preallocate a apr_table_t with the maximum substrings possible, - * fill it with the variant list, and then concatenate the entire array. - * Note that if you change the number of substrings pushed, you also - * need to change the calculation of max_vlist_array above. - */ - if (neg->send_alternates && neg->avail_vars->nelts) - arr = apr_array_make(r->pool, max_vlist_array, sizeof(char *)); - else - arr = NULL; - - /* Put headers into err_headers_out, since send_http_header() - * outputs both headers_out and err_headers_out. - */ - hdrs = r->err_headers_out; - - for (j = 0; j < neg->avail_vars->nelts; ++j) { - var_rec *variant = &avail_recs[j]; - - if (variant->content_languages && variant->content_languages->nelts) { - lang = apr_array_pstrcat(r->pool, variant->content_languages, ','); - } - else { - lang = NULL; - } - - /* Calculate Vary by looking for any difference between variants */ - - if (first_variant) { - sample_type = variant->mime_type; - sample_charset = variant->content_charset; - sample_language = lang; - sample_encoding = variant->content_encoding; - } - else { - if (!vary_by_type && - strcmp(sample_type ? sample_type : "", - variant->mime_type ? variant->mime_type : "")) { - vary_by_type = 1; - } - if (!vary_by_charset && - strcmp(sample_charset ? sample_charset : "", - variant->content_charset ? - variant->content_charset : "")) { - vary_by_charset = 1; - } - if (!vary_by_language && - strcmp(sample_language ? sample_language : "", - lang ? lang : "")) { - vary_by_language = 1; - } - if (!vary_by_encoding && - strcmp(sample_encoding ? sample_encoding : "", - variant->content_encoding ? - variant->content_encoding : "")) { - vary_by_encoding = 1; - } - } - first_variant = 0; - - if (!neg->send_alternates) - continue; - - /* Generate the string components for this Alternates entry */ - - *((const char **) apr_array_push(arr)) = "{\""; - *((const char **) apr_array_push(arr)) = variant->file_name; - *((const char **) apr_array_push(arr)) = "\" "; - - qstr = (char *) apr_palloc(r->pool, 6); - apr_snprintf(qstr, 6, "%1.3f", variant->source_quality); - - /* Strip trailing zeros (saves those valuable network bytes) */ - if (qstr[4] == '0') { - qstr[4] = '\0'; - if (qstr[3] == '0') { - qstr[3] = '\0'; - if (qstr[2] == '0') { - qstr[1] = '\0'; - } - } - } - *((const char **) apr_array_push(arr)) = qstr; - - if (variant->mime_type && *variant->mime_type) { - *((const char **) apr_array_push(arr)) = " {type "; - *((const char **) apr_array_push(arr)) = variant->mime_type; - *((const char **) apr_array_push(arr)) = "}"; - } - if (variant->content_charset && *variant->content_charset) { - *((const char **) apr_array_push(arr)) = " {charset "; - *((const char **) apr_array_push(arr)) = variant->content_charset; - *((const char **) apr_array_push(arr)) = "}"; - } - if (lang) { - *((const char **) apr_array_push(arr)) = " {language "; - *((const char **) apr_array_push(arr)) = lang; - *((const char **) apr_array_push(arr)) = "}"; - } - if (variant->content_encoding && *variant->content_encoding) { - /* Strictly speaking, this is non-standard, but so is TCN */ - - *((const char **) apr_array_push(arr)) = " {encoding "; - *((const char **) apr_array_push(arr)) = variant->content_encoding; - *((const char **) apr_array_push(arr)) = "}"; - } - - /* Note that the Alternates specification (in rfc2295) does - * not require that we include {length x}, so we could omit it - * if determining the length is too expensive. We currently - * always include it though. 22 bytes is enough for 2^64. - * - * If the variant is a CGI script, find_content_length would - * return the length of the script, not the output it - * produces, so we check for the presence of a handler and if - * there is one we don't add a length. - * - * XXX: TODO: This check does not detect a CGI script if we - * get the variant from a type map. This needs to be fixed - * (without breaking things if the type map specifies a - * content-length, which currently leads to the correct result). - */ - if (!(variant->sub_req && variant->sub_req->handler) - && (len = find_content_length(neg, variant)) != 0) { - - lenstr = (char *) apr_palloc(r->pool, 22); - apr_snprintf(lenstr, 22, "%ld", len); - *((const char **) apr_array_push(arr)) = " {length "; - *((const char **) apr_array_push(arr)) = lenstr; - *((const char **) apr_array_push(arr)) = "}"; - } - - *((const char **) apr_array_push(arr)) = "}"; - *((const char **) apr_array_push(arr)) = ", "; /* trimmed below */ - } - - if (neg->send_alternates && neg->avail_vars->nelts) { - arr->nelts--; /* remove last comma */ - apr_table_mergen(hdrs, "Alternates", - apr_array_pstrcat(r->pool, arr, '\0')); - } - - if (neg->is_transparent || vary_by_type || vary_by_language || - vary_by_language || vary_by_charset || vary_by_encoding) { - - apr_table_mergen(hdrs, "Vary", 2 + apr_pstrcat(r->pool, - neg->is_transparent ? ", negotiate" : "", - vary_by_type ? ", accept" : "", - vary_by_language ? ", accept-language" : "", - vary_by_charset ? ", accept-charset" : "", - vary_by_encoding ? ", accept-encoding" : "", NULL)); - } - - if (neg->is_transparent) { /* Create TCN response header */ - apr_table_setn(hdrs, "TCN", - alg_result == alg_list ? "list" : "choice"); - } -} - -/********************************************************************** - * - * Return an HTML list of variants. This is output as part of the - * choice response or 406 status body. - */ - -static char *make_variant_list(request_rec *r, negotiation_state *neg) -{ - apr_array_header_t *arr; - int i; - int max_vlist_array = (neg->avail_vars->nelts * 15) + 2; - - /* In order to avoid O(n^2) memory copies in building the list, - * we preallocate a apr_table_t with the maximum substrings possible, - * fill it with the variant list, and then concatenate the entire array. - */ - arr = apr_array_make(r->pool, max_vlist_array, sizeof(char *)); - - *((const char **) apr_array_push(arr)) = "Available variants:\n<ul>\n"; - - for (i = 0; i < neg->avail_vars->nelts; ++i) { - var_rec *variant = &((var_rec *) neg->avail_vars->elts)[i]; - char *filename = variant->file_name ? variant->file_name : ""; - apr_array_header_t *languages = variant->content_languages; - char *description = variant->description ? variant->description : ""; - - /* The format isn't very neat, and it would be nice to make - * the tags human readable (eg replace 'language en' with 'English'). - * Note that if you change the number of substrings pushed, you also - * need to change the calculation of max_vlist_array above. - */ - *((const char **) apr_array_push(arr)) = "<li><a href=\""; - *((const char **) apr_array_push(arr)) = filename; - *((const char **) apr_array_push(arr)) = "\">"; - *((const char **) apr_array_push(arr)) = filename; - *((const char **) apr_array_push(arr)) = "</a> "; - *((const char **) apr_array_push(arr)) = description; - - if (variant->mime_type && *variant->mime_type) { - *((const char **) apr_array_push(arr)) = ", type "; - *((const char **) apr_array_push(arr)) = variant->mime_type; - } - if (languages && languages->nelts) { - *((const char **) apr_array_push(arr)) = ", language "; - *((const char **) apr_array_push(arr)) = apr_array_pstrcat(r->pool, - languages, ','); - } - if (variant->content_charset && *variant->content_charset) { - *((const char **) apr_array_push(arr)) = ", charset "; - *((const char **) apr_array_push(arr)) = variant->content_charset; - } - if (variant->content_encoding) { - *((const char **) apr_array_push(arr)) = ", encoding "; - *((const char **) apr_array_push(arr)) = variant->content_encoding; - } - *((const char **) apr_array_push(arr)) = "\n"; - } - *((const char **) apr_array_push(arr)) = "</ul>\n"; - - return apr_array_pstrcat(r->pool, arr, '\0'); -} - -static void store_variant_list(request_rec *r, negotiation_state *neg) -{ - if (r->main == NULL) { - apr_table_setn(r->notes, "variant-list", make_variant_list(r, neg)); - } - else { - apr_table_setn(r->main->notes, "variant-list", - make_variant_list(r->main, neg)); - } -} - -/* Called if we got a "Choice" response from the variant selection algorithm. - * It checks the result of the chosen variant to see if it - * is itself negotiated (if so, return error HTTP_VARIANT_ALSO_VARIES). - * Otherwise, add the appropriate headers to the current response. - */ - -static int setup_choice_response(request_rec *r, negotiation_state *neg, - var_rec *variant) -{ - request_rec *sub_req; - const char *sub_vary; - - if (!variant->sub_req) { - int status; - - sub_req = ap_sub_req_lookup_file(variant->file_name, r, NULL); - status = sub_req->status; - - if (status != HTTP_OK && - !apr_table_get(sub_req->err_headers_out, "TCN")) { - ap_destroy_sub_req(sub_req); - return status; - } - variant->sub_req = sub_req; - } - else { - sub_req = variant->sub_req; - } - - /* The variant selection algorithm told us to return a "Choice" - * response. This is the normal variant response, with - * some extra headers. First, ensure that the chosen - * variant did or will not itself engage in transparent negotiation. - * If not, set the appropriate headers, and fall through to - * the normal variant handling - */ - - /* This catches the error that a transparent type map selects a - * transparent multiviews resource as the best variant. - * - * XXX: We do not signal an error if a transparent type map - * selects a _non_transparent multiviews resource as the best - * variant, because we can generate a legal negotiation response - * in this case. In this case, the vlist_validator of the - * nontransparent subrequest will be lost however. This could - * lead to cases in which a change in the set of variants or the - * negotiation algorithm of the nontransparent resource is never - * propagated up to a HTTP/1.1 cache which interprets Vary. To be - * completely on the safe side we should return HTTP_VARIANT_ALSO_VARIES - * for this type of recursive negotiation too. - */ - if (neg->is_transparent && - apr_table_get(sub_req->err_headers_out, "TCN")) { - return HTTP_VARIANT_ALSO_VARIES; - } - - /* This catches the error that a transparent type map recursively - * selects, as the best variant, another type map which itself - * causes transparent negotiation to be done. - * - * XXX: Actually, we catch this error by catching all cases of - * type map recursion. There are some borderline recursive type - * map arrangements which would not produce transparent - * negotiation protocol errors or lack of cache propagation - * problems, but such arrangements are very hard to detect at this - * point in the control flow, so we do not bother to single them - * out. - * - * Recursive type maps imply a recursive arrangement of negotiated - * resources which is visible to outside clients, and this is not - * supported by the transparent negotiation caching protocols, so - * if we are to have generic support for recursive type maps, we - * have to create some configuration setting which makes all type - * maps non-transparent when recursion is enabled. Also, if we - * want recursive type map support which ensures propagation of - * type map changes into HTTP/1.1 caches that handle Vary, we - * would have to extend the current mechanism for generating - * variant list validators. - */ - if (sub_req->handler && strcmp(sub_req->handler, "type-map") == 0) { - return HTTP_VARIANT_ALSO_VARIES; - } - - /* This adds an appropriate Variant-Vary header if the subrequest - * is a multiviews resource. - * - * XXX: TODO: Note that this does _not_ handle any Vary header - * returned by a CGI if sub_req is a CGI script, because we don't - * see that Vary header yet at this point in the control flow. - * This won't cause any cache consistency problems _unless_ the - * CGI script also returns a Cache-Control header marking the - * response as cachable. This needs to be fixed, also there are - * problems if a CGI returns an Etag header which also need to be - * fixed. - */ - if ((sub_vary = apr_table_get(sub_req->err_headers_out, "Vary")) != NULL) { - apr_table_setn(r->err_headers_out, "Variant-Vary", sub_vary); - - /* Move the subreq Vary header into the main request to - * prevent having two Vary headers in the response, which - * would be legal but strange. - */ - apr_table_setn(r->err_headers_out, "Vary", sub_vary); - apr_table_unset(sub_req->err_headers_out, "Vary"); - } - - apr_table_setn(r->err_headers_out, "Content-Location", - apr_pstrdup(r->pool, variant->file_name)); - - set_neg_headers(r, neg, alg_choice); /* add Alternates and Vary */ - - /* Still to do by caller: add Expires */ - - return 0; -} - -/**************************************************************** - * - * Executive... - */ - -static int do_negotiation(request_rec *r, negotiation_state *neg, - var_rec **bestp, int prefer_scripts) -{ - var_rec *avail_recs = (var_rec *) neg->avail_vars->elts; - int alg_result; /* result of variant selection algorithm */ - int res; - int j; - - /* Decide if resource is transparently negotiable */ - - /* GET or HEAD? (HEAD has same method number as GET) */ - if (r->method_number == M_GET) { - - /* maybe this should be configurable, see also the comment - * about recursive type maps in setup_choice_response() - */ - neg->is_transparent = 1; - - /* We can't be transparent if we are a map file in the middle - * of the request URI. - */ - if (r->path_info && *r->path_info) - neg->is_transparent = 0; - - for (j = 0; j < neg->avail_vars->nelts; ++j) { - var_rec *variant = &avail_recs[j]; - - /* We can't be transparent, because of internal - * assumptions in best_match(), if there is a - * non-neighboring variant. We can have a non-neighboring - * variant when processing a type map. - */ - if (strchr(variant->file_name, '/')) - neg->is_transparent = 0; - } - } - - if (neg->is_transparent) { - parse_negotiate_header(r, neg); - } - else { /* configure negotiation on non-transparent resource */ - neg->may_choose = 1; - } - - maybe_add_default_accepts(neg, prefer_scripts); - - alg_result = best_match(neg, bestp); - - /* alg_result is one of - * alg_choice: a best variant is chosen - * alg_list: no best variant is chosen - */ - - if (alg_result == alg_list) { - /* send a list response or HTTP_NOT_ACCEPTABLE error response */ - - neg->send_alternates = 1; /* always include Alternates header */ - set_neg_headers(r, neg, alg_result); - store_variant_list(r, neg); - - if (neg->is_transparent && neg->ua_supports_trans) { - /* XXX todo: expires? cachability? */ - - /* Some HTTP/1.0 clients are known to choke when they get - * a 300 (multiple choices) response without a Location - * header. However the 300 code response we are are about - * to generate will only reach 1.0 clients which support - * transparent negotiation, and they should be OK. The - * response should never reach older 1.0 clients, even if - * we have CacheNegotiatedDocs enabled, because no 1.0 - * proxy cache (we know of) will cache and return 300 - * responses (they certainly won't if they conform to the - * HTTP/1.0 specification). - */ - return HTTP_MULTIPLE_CHOICES; - } - - if (!*bestp) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "no acceptable variant: %s", r->filename); - return HTTP_NOT_ACCEPTABLE; - } - } - - /* Variant selection chose a variant */ - - /* XXX todo: merge the two cases in the if statement below */ - if (neg->is_transparent) { - - if ((res = setup_choice_response(r, neg, *bestp)) != 0) { - return res; /* return if error */ - } - } - else { - set_neg_headers(r, neg, alg_result); - } - - /* Make sure caching works - Vary should handle HTTP/1.1, but for - * HTTP/1.0, we can't allow caching at all. - */ - - /* XXX: Note that we only set r->no_cache to 1, which causes - * Expires: <now> to be added, when responding to a HTTP/1.0 - * client. If we return the response to a 1.1 client, we do not - * add Expires <now>, because doing so would degrade 1.1 cache - * performance by preventing re-use of the response without prior - * revalidation. On the other hand, if the 1.1 client is a proxy - * which was itself contacted by a 1.0 client, or a proxy cache - * which can be contacted later by 1.0 clients, then we currently - * rely on this 1.1 proxy to add the Expires: <now> when it - * forwards the response. - * - * XXX: TODO: Find out if the 1.1 spec requires proxies and - * tunnels to add Expires: <now> when forwarding the response to - * 1.0 clients. I (kh) recall it is rather vague on this point. - * Testing actual 1.1 proxy implementations would also be nice. If - * Expires: <now> is not added by proxies then we need to always - * include Expires: <now> ourselves to ensure correct caching, but - * this would degrade HTTP/1.1 cache efficiency unless we also add - * Cache-Control: max-age=N, which we currently don't. - * - * Roy: No, we are not going to screw over HTTP future just to - * ensure that people who can't be bothered to upgrade their - * clients will always receive perfect server-side negotiation. - * Hell, those clients are sending bogus accept headers anyway. - * - * Manual setting of cache-control/expires always overrides this - * automated kluge, on purpose. - */ - - if ((!do_cache_negotiated_docs(r->server) - && (r->proto_num < HTTP_VERSION(1,1))) - && neg->count_multiviews_variants != 1) { - r->no_cache = 1; - } - - return OK; -} - -static int handle_map_file(request_rec *r) -{ - negotiation_state *neg; - var_rec *best; - int res; - char *udir; - - if(strcmp(r->handler,MAP_FILE_MAGIC_TYPE) && strcmp(r->handler,"type-map")) - return DECLINED; - - neg = parse_accept_headers(r); - if ((res = read_type_map(neg, r))) { - return res; - } - - res = do_negotiation(r, neg, &best, 0); - if (res != 0) return res; - - if (r->path_info && *r->path_info) { - r->uri[ap_find_path_info(r->uri, r->path_info)] = '\0'; - } - udir = ap_make_dirstr_parent(r->pool, r->uri); - udir = ap_escape_uri(r->pool, udir); - ap_internal_redirect(apr_pstrcat(r->pool, udir, best->file_name, - r->path_info, NULL), r); - return OK; -} - -static int handle_multi(request_rec *r) -{ - negotiation_state *neg; - var_rec *best, *avail_recs; - request_rec *sub_req; - int res; - int j; - - if (r->finfo.filetype != 0 || !(ap_allow_options(r) & OPT_MULTI)) { - return DECLINED; - } - - neg = parse_accept_headers(r); - - if ((res = read_types_multi(neg))) { - return_from_multi: - /* free all allocated memory from subrequests */ - avail_recs = (var_rec *) neg->avail_vars->elts; - for (j = 0; j < neg->avail_vars->nelts; ++j) { - var_rec *variant = &avail_recs[j]; - if (variant->sub_req) { - ap_destroy_sub_req(variant->sub_req); - } - } - return res; - } - if (neg->avail_vars->nelts == 0) { - return DECLINED; - } - - res = do_negotiation(r, neg, &best, - (r->method_number != M_GET) || r->args || - (r->path_info && *r->path_info)); - if (res != 0) - goto return_from_multi; - - if (!(sub_req = best->sub_req)) { - /* We got this out of a map file, so we don't actually have - * a sub_req structure yet. Get one now. - */ - - sub_req = ap_sub_req_lookup_file(best->file_name, r, NULL); - if (sub_req->status != HTTP_OK) { - res = sub_req->status; - ap_destroy_sub_req(sub_req); - goto return_from_multi; - } - } - - /* BLECH --- don't multi-resolve non-ordinary files */ - - if (sub_req->finfo.filetype != APR_REG) { - res = HTTP_NOT_FOUND; - goto return_from_multi; - } - - /* Otherwise, use it. */ - - /* now do a "fast redirect" ... promote the sub_req into the main req */ - /* We need to tell POOL_DEBUG that we're guaranteeing that sub_req->pool - * will exist as long as r->pool. Otherwise we run into troubles because - * some values in this request will be allocated in r->pool, and others in - * sub_req->pool. - */ - apr_pool_join(r->pool, sub_req->pool); - r->mtime = 0; /* reset etag info for subrequest */ - r->filename = sub_req->filename; - r->handler = sub_req->handler; - r->content_type = sub_req->content_type; - r->content_encoding = sub_req->content_encoding; - r->content_languages = sub_req->content_languages; - r->content_language = sub_req->content_language; - r->finfo = sub_req->finfo; - r->per_dir_config = sub_req->per_dir_config; - /* copy output headers from subrequest, but leave negotiation headers */ - r->notes = apr_table_overlay(r->pool, sub_req->notes, r->notes); - r->headers_out = apr_table_overlay(r->pool, sub_req->headers_out, - r->headers_out); - r->err_headers_out = apr_table_overlay(r->pool, sub_req->err_headers_out, - r->err_headers_out); - r->subprocess_env = apr_table_overlay(r->pool, sub_req->subprocess_env, - r->subprocess_env); - avail_recs = (var_rec *) neg->avail_vars->elts; - for (j = 0; j < neg->avail_vars->nelts; ++j) { - var_rec *variant = &avail_recs[j]; - if (variant != best && variant->sub_req) { - ap_destroy_sub_req(variant->sub_req); - } - } - return OK; -} - -/********************************************************************** - * There is a problem with content-encoding, as some clients send and - * expect an x- token (e.g. x-gzip) while others expect the plain token - * (i.e. gzip). To try and deal with this as best as possible we do - * the following: if the client sent an Accept-Encoding header and it - * contains a plain token corresponding to the content encoding of the - * response, then set content encoding using the plain token. Else if - * the A-E header contains the x- token use the x- token in the C-E - * header. Else don't do anything. - * - * Note that if no A-E header was sent, or it does not contain a token - * compatible with the final content encoding, then the token in the - * C-E header will be whatever was specified in the AddEncoding - * directive. - */ -static int fix_encoding(request_rec *r) -{ - const char *enc = r->content_encoding; - char *x_enc = NULL; - apr_array_header_t *accept_encodings; - accept_rec *accept_recs; - int i; - - if (!enc || !*enc) { - return DECLINED; - } - - if (enc[0] == 'x' && enc[1] == '-') { - enc += 2; - } - - if ((accept_encodings = do_header_line(r->pool, - apr_table_get(r->headers_in, "Accept-Encoding"))) == NULL) { - return DECLINED; - } - - accept_recs = (accept_rec *) accept_encodings->elts; - - for (i = 0; i < accept_encodings->nelts; ++i) { - char *name = accept_recs[i].name; - - if (!strcmp(name, enc)) { - r->content_encoding = name; - return OK; - } - - if (name[0] == 'x' && name[1] == '-' && !strcmp(name+2, enc)) { - x_enc = name; - } - } - - if (x_enc) { - r->content_encoding = x_enc; - return OK; - } - - return DECLINED; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_fixups(fix_encoding,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_type_checker(handle_multi,NULL,NULL,APR_HOOK_FIRST); - ap_hook_handler(handle_map_file,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA negotiation_module = -{ - STANDARD20_MODULE_STUFF, - create_neg_dir_config, /* dir config creator */ - merge_neg_dir_configs, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - negotiation_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/mappers/mod_negotiation.exp b/modules/mappers/mod_negotiation.exp deleted file mode 100644 index a7c18da1de..0000000000 --- a/modules/mappers/mod_negotiation.exp +++ /dev/null @@ -1 +0,0 @@ -negotiation_module diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c deleted file mode 100644 index a5c4563bff..0000000000 --- a/modules/mappers/mod_rewrite.c +++ /dev/null @@ -1,4132 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* _ _ _ -** _ __ ___ ___ __| | _ __ _____ ___ __(_) |_ ___ -** | '_ ` _ \ / _ \ / _` | | '__/ _ \ \ /\ / / '__| | __/ _ \ -** | | | | | | (_) | (_| | | | | __/\ V V /| | | | || __/ -** |_| |_| |_|\___/ \__,_|___|_| \___| \_/\_/ |_| |_|\__\___| -** |_____| -** -** URL Rewriting Module -** -** This module uses a rule-based rewriting engine (based on a -** regular-expression parser) to rewrite requested URLs on the fly. -** -** It supports an unlimited number of additional rule conditions (which can -** operate on a lot of variables, even on HTTP headers) for granular -** matching and even external database lookups (either via plain text -** tables, DBM hash files or even external processes) for advanced URL -** substitution. -** -** It operates on the full URLs (including the PATH_INFO part) both in -** per-server context (httpd.conf) and per-dir context (.htaccess) and even -** can generate QUERY_STRING parts on result. The rewriting result finally -** can lead to internal subprocessing, external request redirection or even -** to internal proxy throughput. -** -** This module was originally written in April 1996 and -** gifted exclusively to the The Apache Software Foundation in July 1997 by -** -** Ralf S. Engelschall -** rse@engelschall.com -** www.engelschall.com -*/ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_user.h" -#include "apr_lib.h" -#include "apr_signal.h" - -#define APR_WANT_STRFUNC -#define APR_WANT_IOVEC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_log.h" -#include "http_protocol.h" -#include "mod_rewrite.h" - -#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) -#include "unixd.h" -#endif - -/* -** +-------------------------------------------------------+ -** | | -** | static module configuration -** | | -** +-------------------------------------------------------+ -*/ - - -/* -** Our interface to the Apache server kernel: -** -** o Runtime logic of a request is as following: -** while(request or subrequest) -** foreach(stage #0...#9) -** foreach(module) (**) -** try to run hook -** -** o the order of modules at (**) is the inverted order as -** given in the "Configuration" file, i.e. the last module -** specified is the first one called for each hook! -** The core module is always the last! -** -** o there are two different types of result checking and -** continue processing: -** for hook #0,#1,#4,#5,#6,#8: -** hook run loop stops on first modules which gives -** back a result != DECLINED, i.e. it usually returns OK -** which says "OK, module has handled this _stage_" and for #1 -** this have not to mean "Ok, the filename is now valid". -** for hook #2,#3,#7,#9: -** all hooks are run, independend of result -** -** o at the last stage, the core module always -** - says "HTTP_BAD_REQUEST" if r->filename does not begin with "/" -** - prefix URL with document_root or replaced server_root -** with document_root and sets r->filename -** - always return a "OK" independed if the file really exists -** or not! -*/ - - /* The section for the Configure script: - * XXX: this needs updating for apache-2.0 configuration method - * MODULE-DEFINITION-START - * Name: rewrite_module - * ConfigStart - . ./build/find-dbm-lib - if [ "x$found_dbm" = "x1" ]; then - echo " enabling DBM support for mod_rewrite" - else - echo " disabling DBM support for mod_rewrite" - echo " (perhaps you need to add -ldbm, -lndbm or -lgdbm to EXTRA_LIBS)" - CFLAGS="$CFLAGS -DNO_DBM_REWRITEMAP" - fi - * ConfigEnd - * MODULE-DEFINITION-END - */ - - /* the module (predeclaration) */ -module AP_MODULE_DECLARE_DATA rewrite_module; - - /* the cache */ -static cache *cachep; - - /* whether proxy module is available or not */ -static int proxy_available; - -static const char *lockname; -static apr_lock_t *rewrite_mapr_lock_acquire = NULL; -static apr_lock_t *rewrite_log_lock = NULL; - -/* -** +-------------------------------------------------------+ -** | | -** | configuration directive handling -** | | -** +-------------------------------------------------------+ -*/ - -/* -** -** per-server configuration structure handling -** -*/ - -static void *config_server_create(apr_pool_t *p, server_rec *s) -{ - rewrite_server_conf *a; - - a = (rewrite_server_conf *)apr_pcalloc(p, sizeof(rewrite_server_conf)); - - a->state = ENGINE_DISABLED; - a->options = OPTION_NONE; - a->rewritelogfile = NULL; - a->rewritelogfp = NULL; - a->rewriteloglevel = 0; - a->rewritemaps = apr_array_make(p, 2, sizeof(rewritemap_entry)); - a->rewriteconds = apr_array_make(p, 2, sizeof(rewritecond_entry)); - a->rewriterules = apr_array_make(p, 2, sizeof(rewriterule_entry)); - a->server = s; - - return (void *)a; -} - -static void *config_server_merge(apr_pool_t *p, void *basev, void *overridesv) -{ - rewrite_server_conf *a, *base, *overrides; - - a = (rewrite_server_conf *)apr_pcalloc(p, sizeof(rewrite_server_conf)); - base = (rewrite_server_conf *)basev; - overrides = (rewrite_server_conf *)overridesv; - - a->state = overrides->state; - a->options = overrides->options; - a->server = overrides->server; - - if (a->options & OPTION_INHERIT) { - /* - * local directives override - * and anything else is inherited - */ - a->rewriteloglevel = overrides->rewriteloglevel != 0 - ? overrides->rewriteloglevel - : base->rewriteloglevel; - a->rewritelogfile = overrides->rewritelogfile != NULL - ? overrides->rewritelogfile - : base->rewritelogfile; - a->rewritelogfp = overrides->rewritelogfp != NULL - ? overrides->rewritelogfp - : base->rewritelogfp; - a->rewritemaps = apr_array_append(p, overrides->rewritemaps, - base->rewritemaps); - a->rewriteconds = apr_array_append(p, overrides->rewriteconds, - base->rewriteconds); - a->rewriterules = apr_array_append(p, overrides->rewriterules, - base->rewriterules); - } - else { - /* - * local directives override - * and anything else gets defaults - */ - a->rewriteloglevel = overrides->rewriteloglevel; - a->rewritelogfile = overrides->rewritelogfile; - a->rewritelogfp = overrides->rewritelogfp; - a->rewritemaps = overrides->rewritemaps; - a->rewriteconds = overrides->rewriteconds; - a->rewriterules = overrides->rewriterules; - } - - return (void *)a; -} - - -/* -** -** per-directory configuration structure handling -** -*/ - -static void *config_perdir_create(apr_pool_t *p, char *path) -{ - rewrite_perdir_conf *a; - - a = (rewrite_perdir_conf *)apr_pcalloc(p, sizeof(rewrite_perdir_conf)); - - a->state = ENGINE_DISABLED; - a->options = OPTION_NONE; - a->baseurl = NULL; - a->rewriteconds = apr_array_make(p, 2, sizeof(rewritecond_entry)); - a->rewriterules = apr_array_make(p, 2, sizeof(rewriterule_entry)); - - if (path == NULL) { - a->directory = NULL; - } - else { - /* make sure it has a trailing slash */ - if (path[strlen(path)-1] == '/') { - a->directory = apr_pstrdup(p, path); - } - else { - a->directory = apr_pstrcat(p, path, "/", NULL); - } - } - - return (void *)a; -} - -static void *config_perdir_merge(apr_pool_t *p, void *basev, void *overridesv) -{ - rewrite_perdir_conf *a, *base, *overrides; - - a = (rewrite_perdir_conf *)apr_pcalloc(p, - sizeof(rewrite_perdir_conf)); - base = (rewrite_perdir_conf *)basev; - overrides = (rewrite_perdir_conf *)overridesv; - - a->state = overrides->state; - a->options = overrides->options; - a->directory = overrides->directory; - a->baseurl = overrides->baseurl; - - if (a->options & OPTION_INHERIT) { - a->rewriteconds = apr_array_append(p, overrides->rewriteconds, - base->rewriteconds); - a->rewriterules = apr_array_append(p, overrides->rewriterules, - base->rewriterules); - } - else { - a->rewriteconds = overrides->rewriteconds; - a->rewriterules = overrides->rewriterules; - } - - return (void *)a; -} - - -/* -** -** the configuration commands -** -*/ - -static const char *cmd_rewriteengine(cmd_parms *cmd, - void *in_dconf, int flag) -{ - rewrite_perdir_conf *dconf = in_dconf; - rewrite_server_conf *sconf; - - sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module); - - if (cmd->path == NULL) { /* is server command */ - sconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED); - } - else /* is per-directory command */ { - dconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED); - } - - return NULL; -} - -static const char *cmd_rewriteoptions(cmd_parms *cmd, - void *in_dconf, const char *option) -{ - rewrite_perdir_conf *dconf = in_dconf; - rewrite_server_conf *sconf; - const char *err; - - sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module); - - if (cmd->path == NULL) { /* is server command */ - err = cmd_rewriteoptions_setoption(cmd->pool, - &(sconf->options), option); - } - else { /* is per-directory command */ - err = cmd_rewriteoptions_setoption(cmd->pool, - &(dconf->options), option); - } - - return err; -} - -static const char *cmd_rewriteoptions_setoption(apr_pool_t *p, int *options, - const char *name) -{ - if (strcasecmp(name, "inherit") == 0) { - *options |= OPTION_INHERIT; - } - else { - return apr_pstrcat(p, "RewriteOptions: unknown option '", - name, "'", NULL); - } - return NULL; -} - -static const char *cmd_rewritelog(cmd_parms *cmd, void *dconf, const char *a1) -{ - rewrite_server_conf *sconf; - - sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module); - - sconf->rewritelogfile = a1; - - return NULL; -} - -static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, const char *a1) -{ - rewrite_server_conf *sconf; - - sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module); - - sconf->rewriteloglevel = atoi(a1); - - return NULL; -} - -static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, const char *a1, - const char *a2) -{ - rewrite_server_conf *sconf; - rewritemap_entry *newmap; - apr_finfo_t st; - - sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module); - - newmap = apr_array_push(sconf->rewritemaps); - - newmap->name = a1; - newmap->func = NULL; - if (strncmp(a2, "txt:", 4) == 0) { - newmap->type = MAPTYPE_TXT; - newmap->datafile = a2+4; - newmap->checkfile = a2+4; - } - else if (strncmp(a2, "rnd:", 4) == 0) { - newmap->type = MAPTYPE_RND; - newmap->datafile = a2+4; - newmap->checkfile = a2+4; - } - else if (strncmp(a2, "dbm:", 4) == 0) { -#ifndef NO_DBM_REWRITEMAP - newmap->type = MAPTYPE_DBM; - newmap->datafile = a2+4; - newmap->checkfile = apr_pstrcat(cmd->pool, a2+4, NDBM_FILE_SUFFIX, NULL); -#else - return apr_pstrdup(cmd->pool, "RewriteMap: cannot use NDBM mapfile, " - "because no NDBM support is compiled in"); -#endif - } - else if (strncmp(a2, "prg:", 4) == 0) { - newmap->type = MAPTYPE_PRG; - newmap->datafile = a2+4; - newmap->checkfile = a2+4; - } - else if (strncmp(a2, "int:", 4) == 0) { - newmap->type = MAPTYPE_INT; - newmap->datafile = NULL; - newmap->checkfile = NULL; - if (strcmp(a2+4, "tolower") == 0) { - newmap->func = rewrite_mapfunc_tolower; - } - else if (strcmp(a2+4, "toupper") == 0) { - newmap->func = rewrite_mapfunc_toupper; - } - else if (strcmp(a2+4, "escape") == 0) { - newmap->func = rewrite_mapfunc_escape; - } - else if (strcmp(a2+4, "unescape") == 0) { - newmap->func = rewrite_mapfunc_unescape; - } - else if (sconf->state == ENGINE_ENABLED) { - return apr_pstrcat(cmd->pool, "RewriteMap: internal map not found:", - a2+4, NULL); - } - } - else { - newmap->type = MAPTYPE_TXT; - newmap->datafile = a2; - newmap->checkfile = a2; - } - newmap->fpin = NULL; - newmap->fpout = NULL; - - if (newmap->checkfile && (sconf->state == ENGINE_ENABLED) - && (apr_stat(&st, newmap->checkfile, APR_FINFO_MIN, - cmd->pool) != APR_SUCCESS)) { - return apr_pstrcat(cmd->pool, - "RewriteMap: map file or program not found:", - newmap->checkfile, NULL); - } - - return NULL; -} - -static const char *cmd_rewritelock(cmd_parms *cmd, void *dconf, const char *a1) -{ - const char *error; - - if ((error = ap_check_cmd_context(cmd, GLOBAL_ONLY)) != NULL) - return error; - - lockname = a1; - - return NULL; -} - -static const char *cmd_rewritebase(cmd_parms *cmd, void *in_dconf, - const char *a1) -{ - rewrite_perdir_conf *dconf = in_dconf; - - if (cmd->path == NULL || dconf == NULL) { - return "RewriteBase: only valid in per-directory config files"; - } - if (a1[0] == '\0') { - return "RewriteBase: empty URL not allowed"; - } - if (a1[0] != '/') { - return "RewriteBase: argument is not a valid URL"; - } - - dconf->baseurl = a1; - - return NULL; -} - -static const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf, - const char *in_str) -{ - rewrite_perdir_conf *dconf = in_dconf; - char *str = apr_pstrdup(cmd->pool, in_str); - rewrite_server_conf *sconf; - rewritecond_entry *newcond; - regex_t *regexp; - char *a1; - char *a2; - char *a3; - char *cp; - const char *err; - int rc; - - sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module); - - /* make a new entry in the internal temporary rewrite rule list */ - if (cmd->path == NULL) { /* is server command */ - newcond = apr_array_push(sconf->rewriteconds); - } - else { /* is per-directory command */ - newcond = apr_array_push(dconf->rewriteconds); - } - - /* parse the argument line ourself */ - if (parseargline(str, &a1, &a2, &a3)) { - return apr_pstrcat(cmd->pool, "RewriteCond: bad argument line '", str, - "'", NULL); - } - - /* arg1: the input string */ - newcond->input = apr_pstrdup(cmd->pool, a1); - - /* arg3: optional flags field - (this have to be first parsed, because we need to - know if the regex should be compiled with ICASE!) */ - newcond->flags = CONDFLAG_NONE; - if (a3 != NULL) { - if ((err = cmd_rewritecond_parseflagfield(cmd->pool, newcond, - a3)) != NULL) { - return err; - } - } - - /* arg2: the pattern - try to compile the regexp to test if is ok */ - cp = a2; - if (cp[0] == '!') { - newcond->flags |= CONDFLAG_NOTMATCH; - cp++; - } - - /* now be careful: Under the POSIX regex library - we can compile the pattern for case insensitive matching, - under the old V8 library we have to do it self via a hack */ - if (newcond->flags & CONDFLAG_NOCASE) { - rc = ((regexp = ap_pregcomp(cmd->pool, cp, REG_EXTENDED|REG_ICASE)) - == NULL); - } - else { - rc = ((regexp = ap_pregcomp(cmd->pool, cp, REG_EXTENDED)) == NULL); - } - if (rc) { - return apr_pstrcat(cmd->pool, - "RewriteCond: cannot compile regular expression '", - a2, "'", NULL); - } - - newcond->pattern = apr_pstrdup(cmd->pool, cp); - newcond->regexp = regexp; - - return NULL; -} - -static const char *cmd_rewritecond_parseflagfield(apr_pool_t *p, - rewritecond_entry *cfg, - char *str) -{ - char *cp; - char *cp1; - char *cp2; - char *cp3; - char *key; - char *val; - const char *err; - - if (str[0] != '[' || str[strlen(str)-1] != ']') { - return "RewriteCond: bad flag delimiters"; - } - - cp = str+1; - str[strlen(str)-1] = ','; /* for simpler parsing */ - for ( ; *cp != '\0'; ) { - /* skip whitespaces */ - for ( ; (*cp == ' ' || *cp == '\t') && *cp != '\0'; cp++) - ; - if (*cp == '\0') { - break; - } - cp1 = cp; - if ((cp2 = strchr(cp, ',')) != NULL) { - cp = cp2+1; - for ( ; (*(cp2-1) == ' ' || *(cp2-1) == '\t'); cp2--) - ; - *cp2 = '\0'; - if ((cp3 = strchr(cp1, '=')) != NULL) { - *cp3 = '\0'; - key = cp1; - val = cp3+1; - } - else { - key = cp1; - val = ""; - } - if ((err = cmd_rewritecond_setflag(p, cfg, key, val)) != NULL) { - return err; - } - } - else { - break; - } - } - - return NULL; -} - -static const char *cmd_rewritecond_setflag(apr_pool_t *p, rewritecond_entry *cfg, - char *key, char *val) -{ - if ( strcasecmp(key, "nocase") == 0 - || strcasecmp(key, "NC") == 0 ) { - cfg->flags |= CONDFLAG_NOCASE; - } - else if ( strcasecmp(key, "ornext") == 0 - || strcasecmp(key, "OR") == 0 ) { - cfg->flags |= CONDFLAG_ORNEXT; - } - else { - return apr_pstrcat(p, "RewriteCond: unknown flag '", key, "'", NULL); - } - return NULL; -} - -static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf, - const char *in_str) -{ - rewrite_perdir_conf *dconf = in_dconf; - char *str = apr_pstrdup(cmd->pool, in_str); - rewrite_server_conf *sconf; - rewriterule_entry *newrule; - regex_t *regexp; - char *a1; - char *a2; - char *a3; - char *cp; - const char *err; - int mode; - - sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module); - - /* make a new entry in the internal rewrite rule list */ - if (cmd->path == NULL) { /* is server command */ - newrule = apr_array_push(sconf->rewriterules); - } - else { /* is per-directory command */ - newrule = apr_array_push(dconf->rewriterules); - } - - /* parse the argument line ourself */ - if (parseargline(str, &a1, &a2, &a3)) { - return apr_pstrcat(cmd->pool, "RewriteRule: bad argument line '", str, - "'", NULL); - } - - /* arg3: optional flags field */ - newrule->forced_mimetype = NULL; - newrule->forced_responsecode = HTTP_MOVED_TEMPORARILY; - newrule->flags = RULEFLAG_NONE; - newrule->env[0] = NULL; - newrule->skip = 0; - if (a3 != NULL) { - if ((err = cmd_rewriterule_parseflagfield(cmd->pool, newrule, - a3)) != NULL) { - return err; - } - } - - /* arg1: the pattern - * try to compile the regexp to test if is ok - */ - cp = a1; - if (cp[0] == '!') { - newrule->flags |= RULEFLAG_NOTMATCH; - cp++; - } - mode = REG_EXTENDED; - if (newrule->flags & RULEFLAG_NOCASE) { - mode |= REG_ICASE; - } - if ((regexp = ap_pregcomp(cmd->pool, cp, mode)) == NULL) { - return apr_pstrcat(cmd->pool, - "RewriteRule: cannot compile regular expression '", - a1, "'", NULL); - } - newrule->pattern = apr_pstrdup(cmd->pool, cp); - newrule->regexp = regexp; - - /* arg2: the output string - * replace the $<N> by \<n> which is needed by the currently - * used Regular Expression library - * - * TODO: Is this still required for PCRE? If not, does it *work* with PCRE? - */ - newrule->output = apr_pstrdup(cmd->pool, a2); - - /* now, if the server or per-dir config holds an - * array of RewriteCond entries, we take it for us - * and clear the array - */ - if (cmd->path == NULL) { /* is server command */ - newrule->rewriteconds = sconf->rewriteconds; - sconf->rewriteconds = apr_array_make(cmd->pool, 2, - sizeof(rewritecond_entry)); - } - else { /* is per-directory command */ - newrule->rewriteconds = dconf->rewriteconds; - dconf->rewriteconds = apr_array_make(cmd->pool, 2, - sizeof(rewritecond_entry)); - } - - return NULL; -} - -static const char *cmd_rewriterule_parseflagfield(apr_pool_t *p, - rewriterule_entry *cfg, - char *str) -{ - char *cp; - char *cp1; - char *cp2; - char *cp3; - char *key; - char *val; - const char *err; - - if (str[0] != '[' || str[strlen(str)-1] != ']') { - return "RewriteRule: bad flag delimiters"; - } - - cp = str+1; - str[strlen(str)-1] = ','; /* for simpler parsing */ - for ( ; *cp != '\0'; ) { - /* skip whitespaces */ - for ( ; (*cp == ' ' || *cp == '\t') && *cp != '\0'; cp++) - ; - if (*cp == '\0') { - break; - } - cp1 = cp; - if ((cp2 = strchr(cp, ',')) != NULL) { - cp = cp2+1; - for ( ; (*(cp2-1) == ' ' || *(cp2-1) == '\t'); cp2--) - ; - *cp2 = '\0'; - if ((cp3 = strchr(cp1, '=')) != NULL) { - *cp3 = '\0'; - key = cp1; - val = cp3+1; - } - else { - key = cp1; - val = ""; - } - if ((err = cmd_rewriterule_setflag(p, cfg, key, val)) != NULL) { - return err; - } - } - else { - break; - } - } - - return NULL; -} - -static const char *cmd_rewriterule_setflag(apr_pool_t *p, rewriterule_entry *cfg, - char *key, char *val) -{ - int status = 0; - int i; - - if ( strcasecmp(key, "redirect") == 0 - || strcasecmp(key, "R") == 0 ) { - cfg->flags |= RULEFLAG_FORCEREDIRECT; - if (strlen(val) > 0) { - if (strcasecmp(val, "permanent") == 0) { - status = HTTP_MOVED_PERMANENTLY; - } - else if (strcasecmp(val, "temp") == 0) { - status = HTTP_MOVED_TEMPORARILY; - } - else if (strcasecmp(val, "seeother") == 0) { - status = HTTP_SEE_OTHER; - } - else if (apr_isdigit(*val)) { - status = atoi(val); - } - if (!ap_is_HTTP_REDIRECT(status)) { - return "RewriteRule: invalid HTTP response code " - "for flag 'R'"; - } - cfg->forced_responsecode = status; - } - } - else if ( strcasecmp(key, "last") == 0 - || strcasecmp(key, "L") == 0 ) { - cfg->flags |= RULEFLAG_LASTRULE; - } - else if ( strcasecmp(key, "next") == 0 - || strcasecmp(key, "N") == 0 ) { - cfg->flags |= RULEFLAG_NEWROUND; - } - else if ( strcasecmp(key, "chain") == 0 - || strcasecmp(key, "C") == 0 ) { - cfg->flags |= RULEFLAG_CHAIN; - } - else if ( strcasecmp(key, "type") == 0 - || strcasecmp(key, "T") == 0 ) { - cfg->forced_mimetype = apr_pstrdup(p, val); - ap_str_tolower(cfg->forced_mimetype); - } - else if ( strcasecmp(key, "env") == 0 - || strcasecmp(key, "E") == 0 ) { - for (i = 0; (cfg->env[i] != NULL) && (i < MAX_ENV_FLAGS); i++) - ; - if (i < MAX_ENV_FLAGS) { - cfg->env[i] = apr_pstrdup(p, val); - cfg->env[i+1] = NULL; - } - else { - return "RewriteRule: too many environment flags 'E'"; - } - } - else if ( strcasecmp(key, "nosubreq") == 0 - || strcasecmp(key, "NS") == 0 ) { - cfg->flags |= RULEFLAG_IGNOREONSUBREQ; - } - else if ( strcasecmp(key, "proxy") == 0 - || strcasecmp(key, "P") == 0 ) { - cfg->flags |= RULEFLAG_PROXY; - } - else if ( strcasecmp(key, "passthrough") == 0 - || strcasecmp(key, "PT") == 0 ) { - cfg->flags |= RULEFLAG_PASSTHROUGH; - } - else if ( strcasecmp(key, "skip") == 0 - || strcasecmp(key, "S") == 0 ) { - cfg->skip = atoi(val); - } - else if ( strcasecmp(key, "forbidden") == 0 - || strcasecmp(key, "F") == 0 ) { - cfg->flags |= RULEFLAG_FORBIDDEN; - } - else if ( strcasecmp(key, "gone") == 0 - || strcasecmp(key, "G") == 0 ) { - cfg->flags |= RULEFLAG_GONE; - } - else if ( strcasecmp(key, "qsappend") == 0 - || strcasecmp(key, "QSA") == 0 ) { - cfg->flags |= RULEFLAG_QSAPPEND; - } - else if ( strcasecmp(key, "nocase") == 0 - || strcasecmp(key, "NC") == 0 ) { - cfg->flags |= RULEFLAG_NOCASE; - } - else { - return apr_pstrcat(p, "RewriteRule: unknown flag '", key, "'", NULL); - } - return NULL; -} - - -/* -** -** Global Module Initialization -** [called from read_config() after all -** config commands were already called] -** -*/ - -static void init_module(apr_pool_t *p, - apr_pool_t *plog, - apr_pool_t *ptemp, - server_rec *s) -{ - apr_status_t rv; - void *data; - int first_time = 0; - const char *userdata_key = "rewrite_init_module"; - - apr_pool_userdata_get(&data, userdata_key, s->process->pool); - if (!data) { - first_time = 1; - apr_pool_userdata_set((const void *)1, userdata_key, - apr_pool_cleanup_null, s->process->pool); - } - - /* check if proxy module is available */ - proxy_available = (ap_find_linked_module("mod_proxy.c") != NULL); - - /* create the rewriting lockfiles in the parent */ - if ((rv = apr_lock_create (&rewrite_log_lock, APR_MUTEX, APR_LOCKALL, - NULL, p)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, - "mod_rewrite: could not create rewrite_log_lock"); - exit(1); - } - - rewritelock_create(s, p); - apr_pool_cleanup_register(p, (void *)s, rewritelock_remove, apr_pool_cleanup_null); - - /* step through the servers and - * - open each rewriting logfile - * - open the RewriteMap prg:xxx programs - */ - for (; s; s = s->next) { - open_rewritelog(s, p); - if (!first_time) - run_rewritemap_programs(s, p); - } -} - - -/* -** -** Per-Child Module Initialization -** [called after a child process is spawned] -** -*/ - -static void init_child(apr_pool_t *p, server_rec *s) -{ - apr_status_t rv; - - if (lockname != NULL && *(lockname) != '\0') - { - rv = apr_lock_child_init (&rewrite_mapr_lock_acquire, lockname, p); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, - "mod_rewrite: could not init rewrite_mapr_lock_acquire " - "in child"); - } - } - - /* create the lookup cache */ - cachep = init_cache(p); -} - - -/* -** +-------------------------------------------------------+ -** | | -** | runtime hooks -** | | -** +-------------------------------------------------------+ -*/ - -/* -** -** URI-to-filename hook -** -** [used for the rewriting engine triggered by -** the per-server 'RewriteRule' directives] -** -*/ - -static int hook_uri2file(request_rec *r) -{ - rewrite_server_conf *conf; - const char *var; - const char *thisserver; - char *thisport; - const char *thisurl; - char buf[512]; - char docroot[512]; - char *cp, *cp2; - const char *ccp; - apr_finfo_t finfo; - unsigned int port; - int n; - int l; - - /* - * retrieve the config structures - */ - conf = ap_get_module_config(r->server->module_config, &rewrite_module); - - /* - * only do something under runtime if the engine is really enabled, - * else return immediately! - */ - if (conf->state == ENGINE_DISABLED) { - return DECLINED; - } - - /* - * check for the ugly API case of a virtual host section where no - * mod_rewrite directives exists. In this situation we became no chance - * by the API to setup our default per-server config so we have to - * on-the-fly assume we have the default config. But because the default - * config has a disabled rewriting engine we are lucky because can - * just stop operating now. - */ - if (conf->server != r->server) { - return DECLINED; - } - - /* - * add the SCRIPT_URL variable to the env. this is a bit complicated - * due to the fact that apache uses subrequests and internal redirects - */ - - if (r->main == NULL) { - var = apr_pstrcat(r->pool, "REDIRECT_", ENVVAR_SCRIPT_URL, NULL); - var = apr_table_get(r->subprocess_env, var); - if (var == NULL) { - apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, r->uri); - } - else { - apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, var); - } - } - else { - var = apr_table_get(r->main->subprocess_env, ENVVAR_SCRIPT_URL); - apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, var); - } - - /* - * create the SCRIPT_URI variable for the env - */ - - /* add the canonical URI of this URL */ - thisserver = ap_get_server_name(r); - port = ap_get_server_port(r); - if (ap_is_default_port(port, r)) { - thisport = ""; - } - else { - apr_snprintf(buf, sizeof(buf), ":%u", port); - thisport = buf; - } - thisurl = apr_table_get(r->subprocess_env, ENVVAR_SCRIPT_URL); - - /* set the variable */ - var = apr_pstrcat(r->pool, ap_http_method(r), "://", thisserver, thisport, - thisurl, NULL); - apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URI, var); - - /* if filename was not initially set, - * we start with the requested URI - */ - if (r->filename == NULL) { - r->filename = apr_pstrdup(r->pool, r->uri); - rewritelog(r, 2, "init rewrite engine with requested uri %s", - r->filename); - } - - /* - * now apply the rules ... - */ - if (apply_rewrite_list(r, conf->rewriterules, NULL)) { - - if (strlen(r->filename) > 6 && - strncmp(r->filename, "proxy:", 6) == 0) { - /* it should be go on as an internal proxy request */ - - /* check if the proxy module is enabled, so - * we can actually use it! - */ - if (!proxy_available) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "attempt to make remote request from mod_rewrite " - "without proxy enabled: %s", r->filename); - return HTTP_FORBIDDEN; - } - - /* make sure the QUERY_STRING and - * PATH_INFO parts get incorporated - */ - if (r->path_info != NULL) { - r->filename = apr_pstrcat(r->pool, r->filename, - r->path_info, NULL); - } - if (r->args != NULL && - r->uri == r->unparsed_uri) { - /* see proxy_http:proxy_http_canon() */ - r->filename = apr_pstrcat(r->pool, r->filename, - "?", r->args, NULL); - } - - /* now make sure the request gets handled by the proxy handler */ - r->proxyreq = PROXYREQ_REVERSE; - r->handler = "proxy-server"; - - rewritelog(r, 1, "go-ahead with proxy request %s [OK]", - r->filename); - return OK; - } - else if (is_absolute_uri(r->filename)) { - /* it was finally rewritten to a remote URL */ - - /* skip 'scheme:' */ - for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++) - ; - /* skip '://' */ - cp += 3; - /* skip host part */ - for ( ; *cp != '/' && *cp != '\0'; cp++) - ; - if (*cp != '\0') { - rewritelog(r, 1, "escaping %s for redirect", r->filename); - cp2 = ap_escape_uri(r->pool, cp); - *cp = '\0'; - r->filename = apr_pstrcat(r->pool, r->filename, cp2, NULL); - } - - /* append the QUERY_STRING part */ - if (r->args != NULL) { - r->filename = apr_pstrcat(r->pool, r->filename, "?", - ap_escape_uri(r->pool, r->args), NULL); - } - - /* determine HTTP redirect response code */ - if (ap_is_HTTP_REDIRECT(r->status)) { - n = r->status; - r->status = HTTP_OK; /* make Apache kernel happy */ - } - else { - n = HTTP_MOVED_TEMPORARILY; - } - - /* now do the redirection */ - apr_table_setn(r->headers_out, "Location", r->filename); - rewritelog(r, 1, "redirect to %s [REDIRECT/%d]", r->filename, n); - return n; - } - else if (strlen(r->filename) > 10 && - strncmp(r->filename, "forbidden:", 10) == 0) { - /* This URLs is forced to be forbidden for the requester */ - return HTTP_FORBIDDEN; - } - else if (strlen(r->filename) > 5 && - strncmp(r->filename, "gone:", 5) == 0) { - /* This URLs is forced to be gone */ - return HTTP_GONE; - } - else if (strlen(r->filename) > 12 && - strncmp(r->filename, "passthrough:", 12) == 0) { - /* - * Hack because of underpowered API: passing the current - * rewritten filename through to other URL-to-filename handlers - * just as it were the requested URL. This is to enable - * post-processing by mod_alias, etc. which always act on - * r->uri! The difference here is: We do not try to - * add the document root - */ - r->uri = apr_pstrdup(r->pool, r->filename+12); - return DECLINED; - } - else { - /* it was finally rewritten to a local path */ - - /* expand "/~user" prefix */ -#if APR_HAS_USER - r->filename = expand_tildepaths(r, r->filename); -#endif - rewritelog(r, 2, "local path result: %s", r->filename); - - /* the filename has to start with a slash! */ - if (r->filename[0] != '/') { - return HTTP_BAD_REQUEST; - } - - /* if there is no valid prefix, we have - * to emulate the translator from the core and - * prefix the filename with document_root - * - * NOTICE: - * We cannot leave out the prefix_stat because - * - when we always prefix with document_root - * then no absolute path can be created, e.g. via - * emulating a ScriptAlias directive, etc. - * - when we always NOT prefix with document_root - * then the files under document_root have to - * be references directly and document_root - * gets never used and will be a dummy parameter - - * this is also bad - * - * BUT: - * Under real Unix systems this is no problem, - * because we only do stat() on the first directory - * and this gets cached by the kernel for along time! - */ - n = prefix_stat(r->filename, &finfo); - if (n == 0) { - if ((ccp = ap_document_root(r)) != NULL) { - l = apr_cpystrn(docroot, ccp, sizeof(docroot)) - docroot; - - /* always NOT have a trailing slash */ - if (docroot[l-1] == '/') { - docroot[l-1] = '\0'; - } - if (r->server->path - && !strncmp(r->filename, r->server->path, - r->server->pathlen)) { - r->filename = apr_pstrcat(r->pool, docroot, - (r->filename + - r->server->pathlen), NULL); - } - else { - r->filename = apr_pstrcat(r->pool, docroot, - r->filename, NULL); - } - rewritelog(r, 2, "prefixed with document_root to %s", - r->filename); - } - } - - rewritelog(r, 1, "go-ahead with %s [OK]", r->filename); - return OK; - } - } - else { - rewritelog(r, 1, "pass through %s", r->filename); - return DECLINED; - } -} - - -/* -** -** MIME-type hook -** -** [used to support the forced-MIME-type feature] -** -*/ - -static int hook_mimetype(request_rec *r) -{ - const char *t; - - /* now check if we have to force a MIME-type */ - t = apr_table_get(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR); - if (t == NULL) { - return DECLINED; - } - else { - rewritelog(r, 1, "force filename %s to have MIME-type '%s'", - r->filename, t); - r->content_type = t; - return OK; - } -} - - -/* -** -** Fixup hook -** -** [used for the rewriting engine triggered by -** the per-directory 'RewriteRule' directives] -** -*/ - -static int hook_fixup(request_rec *r) -{ - rewrite_perdir_conf *dconf; - char *cp; - char *cp2; - const char *ccp; - char *prefix; - int l; - int n; - char *ofilename; - - dconf = (rewrite_perdir_conf *)ap_get_module_config(r->per_dir_config, - &rewrite_module); - - /* if there is no per-dir config we return immediately */ - if (dconf == NULL) { - return DECLINED; - } - - /* we shouldn't do anything in subrequests */ - if (r->main != NULL) { - return DECLINED; - } - - /* if there are no real (i.e. no RewriteRule directives!) - per-dir config of us, we return also immediately */ - if (dconf->directory == NULL) { - return DECLINED; - } - - /* - * only do something under runtime if the engine is really enabled, - * for this directory, else return immediately! - */ - if (!(ap_allow_options(r) & (OPT_SYM_LINKS | OPT_SYM_OWNER))) { - /* FollowSymLinks is mandatory! */ - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Options FollowSymLinks or SymLinksIfOwnerMatch is off " - "which implies that RewriteRule directive is forbidden: " - "%s", r->filename); - return HTTP_FORBIDDEN; - } - else { - /* FollowSymLinks is given, but the user can - * still turn off the rewriting engine - */ - if (dconf->state == ENGINE_DISABLED) { - return DECLINED; - } - } - - /* - * remember the current filename before rewriting for later check - * to prevent deadlooping because of internal redirects - * on final URL/filename which can be equal to the inital one. - */ - ofilename = r->filename; - - /* - * now apply the rules ... - */ - if (apply_rewrite_list(r, dconf->rewriterules, dconf->directory)) { - - if (strlen(r->filename) > 6 && - strncmp(r->filename, "proxy:", 6) == 0) { - /* it should go on as an internal proxy request */ - - /* make sure the QUERY_STRING and - * PATH_INFO parts get incorporated - * (r->path_info was already appended by the - * rewriting engine because of the per-dir context!) - */ - if (r->args != NULL) { - r->filename = apr_pstrcat(r->pool, r->filename, - "?", r->args, NULL); - } - - /* now make sure the request gets handled by the proxy handler */ - r->proxyreq = PROXYREQ_REVERSE; - r->handler = "proxy-server"; - - rewritelog(r, 1, "[per-dir %s] go-ahead with proxy request " - "%s [OK]", dconf->directory, r->filename); - return OK; - } - else if (is_absolute_uri(r->filename)) { - /* it was finally rewritten to a remote URL */ - - /* because we are in a per-dir context - * first try to replace the directory with its base-URL - * if there is a base-URL available - */ - if (dconf->baseurl != NULL) { - /* skip 'scheme:' */ - for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++) - ; - /* skip '://' */ - cp += 3; - if ((cp = strchr(cp, '/')) != NULL) { - rewritelog(r, 2, - "[per-dir %s] trying to replace " - "prefix %s with %s", - dconf->directory, dconf->directory, - dconf->baseurl); - cp2 = subst_prefix_path(r, cp, dconf->directory, - dconf->baseurl); - if (strcmp(cp2, cp) != 0) { - *cp = '\0'; - r->filename = apr_pstrcat(r->pool, r->filename, - cp2, NULL); - } - } - } - - /* now prepare the redirect... */ - - /* skip 'scheme:' */ - for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++) - ; - /* skip '://' */ - cp += 3; - /* skip host part */ - for ( ; *cp != '/' && *cp != '\0'; cp++) - ; - if (*cp != '\0') { - rewritelog(r, 1, "[per-dir %s] escaping %s for redirect", - dconf->directory, r->filename); - cp2 = ap_escape_uri(r->pool, cp); - *cp = '\0'; - r->filename = apr_pstrcat(r->pool, r->filename, cp2, NULL); - } - - /* append the QUERY_STRING part */ - if (r->args != NULL) { - r->filename = apr_pstrcat(r->pool, r->filename, "?", - ap_escape_uri(r->pool, r->args), NULL); - } - - /* determine HTTP redirect response code */ - if (ap_is_HTTP_REDIRECT(r->status)) { - n = r->status; - r->status = HTTP_OK; /* make Apache kernel happy */ - } - else { - n = HTTP_MOVED_TEMPORARILY; - } - - /* now do the redirection */ - apr_table_setn(r->headers_out, "Location", r->filename); - rewritelog(r, 1, "[per-dir %s] redirect to %s [REDIRECT/%d]", - dconf->directory, r->filename, n); - return n; - } - else if (strlen(r->filename) > 10 && - strncmp(r->filename, "forbidden:", 10) == 0) { - /* This URL is forced to be forbidden for the requester */ - return HTTP_FORBIDDEN; - } - else if (strlen(r->filename) > 5 && - strncmp(r->filename, "gone:", 5) == 0) { - /* This URL is forced to be gone */ - return HTTP_GONE; - } - else { - /* it was finally rewritten to a local path */ - - /* if someone used the PASSTHROUGH flag in per-dir - * context we just ignore it. It is only useful - * in per-server context - */ - if (strlen(r->filename) > 12 && - strncmp(r->filename, "passthrough:", 12) == 0) { - r->filename = apr_pstrdup(r->pool, r->filename+12); - } - - /* the filename has to start with a slash! */ - if (r->filename[0] != '/') { - return HTTP_BAD_REQUEST; - } - - /* Check for deadlooping: - * At this point we KNOW that at least one rewriting - * rule was applied, but when the resulting URL is - * the same as the initial URL, we are not allowed to - * use the following internal redirection stuff because - * this would lead to a deadloop. - */ - if (strcmp(r->filename, ofilename) == 0) { - rewritelog(r, 1, "[per-dir %s] initial URL equal rewritten " - "URL: %s [IGNORING REWRITE]", - dconf->directory, r->filename); - return OK; - } - - /* if there is a valid base-URL then substitute - * the per-dir prefix with this base-URL if the - * current filename still is inside this per-dir - * context. If not then treat the result as a - * plain URL - */ - if (dconf->baseurl != NULL) { - rewritelog(r, 2, - "[per-dir %s] trying to replace prefix %s with %s", - dconf->directory, dconf->directory, dconf->baseurl); - r->filename = subst_prefix_path(r, r->filename, - dconf->directory, - dconf->baseurl); - } - else { - /* if no explicit base-URL exists we assume - * that the directory prefix is also a valid URL - * for this webserver and only try to remove the - * document_root if it is prefix - */ - if ((ccp = ap_document_root(r)) != NULL) { - prefix = apr_pstrdup(r->pool, ccp); - /* always NOT have a trailing slash */ - l = strlen(prefix); - if (prefix[l-1] == '/') { - prefix[l-1] = '\0'; - l--; - } - if (strncmp(r->filename, prefix, l) == 0) { - rewritelog(r, 2, - "[per-dir %s] strip document_root " - "prefix: %s -> %s", - dconf->directory, r->filename, - r->filename+l); - r->filename = apr_pstrdup(r->pool, r->filename+l); - } - } - } - - /* now initiate the internal redirect */ - rewritelog(r, 1, "[per-dir %s] internal redirect with %s " - "[INTERNAL REDIRECT]", dconf->directory, r->filename); - r->filename = apr_pstrcat(r->pool, "redirect:", r->filename, NULL); - r->handler = "redirect-handler"; - return OK; - } - } - else { - rewritelog(r, 1, "[per-dir %s] pass through %s", - dconf->directory, r->filename); - return DECLINED; - } -} - - -/* -** -** Content-Handlers -** -** [used for redirect support] -** -*/ - -static int handler_redirect(request_rec *r) -{ - if (strcmp(r->handler, "redirect-handler")) { - return DECLINED; - } - - /* just make sure that we are really meant! */ - if (strncmp(r->filename, "redirect:", 9) != 0) { - return DECLINED; - } - - /* now do the internal redirect */ - ap_internal_redirect(apr_pstrcat(r->pool, r->filename+9, - r->args ? "?" : NULL, r->args, NULL), r); - - /* and return gracefully */ - return OK; -} - - -/* -** +-------------------------------------------------------+ -** | | -** | the rewriting engine -** | | -** +-------------------------------------------------------+ -*/ - -/* - * Apply a complete rule set, - * i.e. a list of rewrite rules - */ -static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules, - char *perdir) -{ - rewriterule_entry *entries; - rewriterule_entry *p; - int i; - int changed; - int rc; - int s; - - /* - * Iterate over all existing rules - */ - entries = (rewriterule_entry *)rewriterules->elts; - changed = 0; - loop: - for (i = 0; i < rewriterules->nelts; i++) { - p = &entries[i]; - - /* - * Ignore this rule on subrequests if we are explicitly - * asked to do so or this is a proxy-throughput or a - * forced redirect rule. - */ - if (r->main != NULL && - (p->flags & RULEFLAG_IGNOREONSUBREQ || - p->flags & RULEFLAG_PROXY || - p->flags & RULEFLAG_FORCEREDIRECT )) { - continue; - } - - /* - * Apply the current rule. - */ - rc = apply_rewrite_rule(r, p, perdir); - if (rc) { - /* - * Indicate a change if this was not a match-only rule. - */ - if (rc != 2) { - changed = 1; - } - - /* - * Pass-Through Feature (`RewriteRule .. .. [PT]'): - * Because the Apache 1.x API is very limited we - * need this hack to pass the rewritten URL to other - * modules like mod_alias, mod_userdir, etc. - */ - if (p->flags & RULEFLAG_PASSTHROUGH) { - rewritelog(r, 2, "forcing '%s' to get passed through " - "to next API URI-to-filename handler", r->filename); - r->filename = apr_pstrcat(r->pool, "passthrough:", - r->filename, NULL); - changed = 1; - break; - } - - /* - * Rule has the "forbidden" flag set which means that - * we stop processing and indicate this to the caller. - */ - if (p->flags & RULEFLAG_FORBIDDEN) { - rewritelog(r, 2, "forcing '%s' to be forbidden", r->filename); - r->filename = apr_pstrcat(r->pool, "forbidden:", - r->filename, NULL); - changed = 1; - break; - } - - /* - * Rule has the "gone" flag set which means that - * we stop processing and indicate this to the caller. - */ - if (p->flags & RULEFLAG_GONE) { - rewritelog(r, 2, "forcing '%s' to be gone", r->filename); - r->filename = apr_pstrcat(r->pool, "gone:", r->filename, NULL); - changed = 1; - break; - } - - /* - * Stop processing also on proxy pass-through and - * last-rule and new-round flags. - */ - if (p->flags & RULEFLAG_PROXY) { - break; - } - if (p->flags & RULEFLAG_LASTRULE) { - break; - } - - /* - * On "new-round" flag we just start from the top of - * the rewriting ruleset again. - */ - if (p->flags & RULEFLAG_NEWROUND) { - goto loop; - } - - /* - * If we are forced to skip N next rules, do it now. - */ - if (p->skip > 0) { - s = p->skip; - while ( i < rewriterules->nelts - && s > 0) { - i++; - p = &entries[i]; - s--; - } - } - } - else { - /* - * If current rule is chained with next rule(s), - * skip all this next rule(s) - */ - while ( i < rewriterules->nelts - && p->flags & RULEFLAG_CHAIN) { - i++; - p = &entries[i]; - } - } - } - return changed; -} - -/* - * Apply a single(!) rewrite rule - */ -static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p, - char *perdir) -{ - char *uri; - char *output; - const char *vary; - char newuri[MAX_STRING_LEN]; - regex_t *regexp; - regmatch_t regmatch[MAX_NMATCH]; - backrefinfo *briRR = NULL; - backrefinfo *briRC = NULL; - int prefixstrip; - int failed; - apr_array_header_t *rewriteconds; - rewritecond_entry *conds; - rewritecond_entry *c; - int i; - int rc; - - /* - * Initialisation - */ - uri = r->filename; - regexp = p->regexp; - output = p->output; - - /* - * Add (perhaps splitted away) PATH_INFO postfix to URL to - * make sure we really match against the complete URL. - */ - if (perdir != NULL && r->path_info != NULL && r->path_info[0] != '\0') { - rewritelog(r, 3, "[per-dir %s] add path info postfix: %s -> %s%s", - perdir, uri, uri, r->path_info); - uri = apr_pstrcat(r->pool, uri, r->path_info, NULL); - } - - /* - * On per-directory context (.htaccess) strip the location - * prefix from the URL to make sure patterns apply only to - * the local part. Additionally indicate this special - * threatment in the logfile. - */ - prefixstrip = 0; - if (perdir != NULL) { - if ( strlen(uri) >= strlen(perdir) - && strncmp(uri, perdir, strlen(perdir)) == 0) { - rewritelog(r, 3, "[per-dir %s] strip per-dir prefix: %s -> %s", - perdir, uri, uri+strlen(perdir)); - uri = uri+strlen(perdir); - prefixstrip = 1; - } - } - - /* - * Try to match the URI against the RewriteRule pattern - * and exit immeddiately if it didn't apply. - */ - if (perdir == NULL) { - rewritelog(r, 3, "applying pattern '%s' to uri '%s'", - p->pattern, uri); - } - else { - rewritelog(r, 3, "[per-dir %s] applying pattern '%s' to uri '%s'", - perdir, p->pattern, uri); - } - rc = (ap_regexec(regexp, uri, regexp->re_nsub+1, regmatch, 0) == 0); - if (! (( rc && !(p->flags & RULEFLAG_NOTMATCH)) || - (!rc && (p->flags & RULEFLAG_NOTMATCH)) ) ) { - return 0; - } - - /* - * Else create the RewriteRule `regsubinfo' structure which - * holds the substitution information. - */ - briRR = (backrefinfo *)apr_palloc(r->pool, sizeof(backrefinfo)); - if (!rc && (p->flags & RULEFLAG_NOTMATCH)) { - /* empty info on negative patterns */ - briRR->source = ""; - briRR->nsub = 0; - } - else { - briRR->source = apr_pstrdup(r->pool, uri); - briRR->nsub = regexp->re_nsub; - memcpy((void *)(briRR->regmatch), (void *)(regmatch), - sizeof(regmatch)); - } - - /* - * Initiallally create the RewriteCond backrefinfo with - * empty backrefinfo, i.e. not subst parts - * (this one is adjusted inside apply_rewrite_cond() later!!) - */ - briRC = (backrefinfo *)apr_pcalloc(r->pool, sizeof(backrefinfo)); - briRC->source = ""; - briRC->nsub = 0; - - /* - * Ok, we already know the pattern has matched, but we now - * additionally have to check for all existing preconditions - * (RewriteCond) which have to be also true. We do this at - * this very late stage to avoid unnessesary checks which - * would slow down the rewriting engine!! - */ - rewriteconds = p->rewriteconds; - conds = (rewritecond_entry *)rewriteconds->elts; - failed = 0; - for (i = 0; i < rewriteconds->nelts; i++) { - c = &conds[i]; - rc = apply_rewrite_cond(r, c, perdir, briRR, briRC); - if (c->flags & CONDFLAG_ORNEXT) { - /* - * The "OR" case - */ - if (rc == 0) { - /* One condition is false, but another can be - * still true, so we have to continue... - */ - apr_table_unset(r->notes, VARY_KEY_THIS); - continue; - } - else { - /* One true condition is enough in "or" case, so - * skip the other conditions which are "ornext" - * chained - */ - while ( i < rewriteconds->nelts - && c->flags & CONDFLAG_ORNEXT) { - i++; - c = &conds[i]; - } - continue; - } - } - else { - /* - * The "AND" case, i.e. no "or" flag, - * so a single failure means total failure. - */ - if (rc == 0) { - failed = 1; - break; - } - } - vary = apr_table_get(r->notes, VARY_KEY_THIS); - if (vary != NULL) { - apr_table_merge(r->notes, VARY_KEY, vary); - apr_table_unset(r->notes, VARY_KEY_THIS); - } - } - /* if any condition fails the complete rule fails */ - if (failed) { - apr_table_unset(r->notes, VARY_KEY); - apr_table_unset(r->notes, VARY_KEY_THIS); - return 0; - } - - /* - * Regardless of what we do next, we've found a match. Check to see - * if any of the request header fields were involved, and add them - * to the Vary field of the response. - */ - if ((vary = apr_table_get(r->notes, VARY_KEY)) != NULL) { - apr_table_merge(r->headers_out, "Vary", vary); - apr_table_unset(r->notes, VARY_KEY); - } - - /* - * If this is a pure matching rule (`RewriteRule <pat> -') - * we stop processing and return immediately. The only thing - * we have not to forget are the environment variables - * (`RewriteRule <pat> - [E=...]') - */ - if (strcmp(output, "-") == 0) { - do_expand_env(r, p->env, briRR, briRC); - if (p->forced_mimetype != NULL) { - if (perdir == NULL) { - /* In the per-server context we can force the MIME-type - * the correct way by notifying our MIME-type hook handler - * to do the job when the MIME-type API stage is reached. - */ - rewritelog(r, 2, "remember %s to have MIME-type '%s'", - r->filename, p->forced_mimetype); - apr_table_setn(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR, - p->forced_mimetype); - } - else { - /* In per-directory context we operate in the Fixup API hook - * which is after the MIME-type hook, so our MIME-type handler - * has no chance to set r->content_type. And because we are - * in the situation where no substitution takes place no - * sub-request will happen (which could solve the - * restriction). As a workaround we do it ourself now - * immediately although this is not strictly API-conforming. - * But it's the only chance we have... - */ - rewritelog(r, 1, "[per-dir %s] force %s to have MIME-type " - "'%s'", perdir, r->filename, p->forced_mimetype); - r->content_type = p->forced_mimetype; - } - } - return 2; - } - - /* - * Ok, now we finally know all patterns have matched and - * that there is something to replace, so we create the - * substitution URL string in `newuri'. - */ - do_expand(r, output, newuri, sizeof(newuri), briRR, briRC); - if (perdir == NULL) { - rewritelog(r, 2, "rewrite %s -> %s", uri, newuri); - } - else { - rewritelog(r, 2, "[per-dir %s] rewrite %s -> %s", perdir, uri, newuri); - } - - /* - * Additionally do expansion for the environment variable - * strings (`RewriteRule .. .. [E=<string>]'). - */ - do_expand_env(r, p->env, briRR, briRC); - - /* - * Now replace API's knowledge of the current URI: - * Replace r->filename with the new URI string and split out - * an on-the-fly generated QUERY_STRING part into r->args - */ - r->filename = apr_pstrdup(r->pool, newuri); - splitout_queryargs(r, p->flags & RULEFLAG_QSAPPEND); - - /* - * Again add the previously stripped per-directory location - * prefix if the new URI is not a new one for this - * location, i.e. if it's not starting with either a slash - * or a fully qualified URL scheme. - */ - if (prefixstrip && r->filename[0] != '/' - && !is_absolute_uri(r->filename)) { - rewritelog(r, 3, "[per-dir %s] add per-dir prefix: %s -> %s%s", - perdir, r->filename, perdir, r->filename); - r->filename = apr_pstrcat(r->pool, perdir, r->filename, NULL); - } - - /* - * If this rule is forced for proxy throughput - * (`RewriteRule ... ... [P]') then emulate mod_proxy's - * URL-to-filename handler to be sure mod_proxy is triggered - * for this URL later in the Apache API. But make sure it is - * a fully-qualified URL. (If not it is qualified with - * ourself). - */ - if (p->flags & RULEFLAG_PROXY) { - fully_qualify_uri(r); - if (perdir == NULL) { - rewritelog(r, 2, "forcing proxy-throughput with %s", r->filename); - } - else { - rewritelog(r, 2, "[per-dir %s] forcing proxy-throughput with %s", - perdir, r->filename); - } - r->filename = apr_pstrcat(r->pool, "proxy:", r->filename, NULL); - return 1; - } - - /* - * If this rule is explicitly forced for HTTP redirection - * (`RewriteRule .. .. [R]') then force an external HTTP - * redirect. But make sure it is a fully-qualified URL. (If - * not it is qualified with ourself). - */ - if (p->flags & RULEFLAG_FORCEREDIRECT) { - fully_qualify_uri(r); - if (perdir == NULL) { - rewritelog(r, 2, - "explicitly forcing redirect with %s", r->filename); - } - else { - rewritelog(r, 2, - "[per-dir %s] explicitly forcing redirect with %s", - perdir, r->filename); - } - r->status = p->forced_responsecode; - return 1; - } - - /* - * Special Rewriting Feature: Self-Reduction - * We reduce the URL by stripping a possible - * http[s]://<ourhost>[:<port>] prefix, i.e. a prefix which - * corresponds to ourself. This is to simplify rewrite maps - * and to avoid recursion, etc. When this prefix is not a - * coincidence then the user has to use [R] explicitly (see - * above). - */ - reduce_uri(r); - - /* - * If this rule is still implicitly forced for HTTP - * redirection (`RewriteRule .. <scheme>://...') then - * directly force an external HTTP redirect. - */ - if (is_absolute_uri(r->filename)) { - if (perdir == NULL) { - rewritelog(r, 2, - "implicitly forcing redirect (rc=%d) with %s", - p->forced_responsecode, r->filename); - } - else { - rewritelog(r, 2, "[per-dir %s] implicitly forcing redirect " - "(rc=%d) with %s", perdir, p->forced_responsecode, - r->filename); - } - r->status = p->forced_responsecode; - return 1; - } - - /* - * Now we are sure it is not a fully qualified URL. But - * there is still one special case left: A local rewrite in - * per-directory context, i.e. a substitution URL which does - * not start with a slash. Here we add again the initially - * stripped per-directory prefix. - */ - if (prefixstrip && r->filename[0] != '/') { - rewritelog(r, 3, "[per-dir %s] add per-dir prefix: %s -> %s%s", - perdir, r->filename, perdir, r->filename); - r->filename = apr_pstrcat(r->pool, perdir, r->filename, NULL); - } - - /* - * Finally we had to remember if a MIME-type should be - * forced for this URL (`RewriteRule .. .. [T=<type>]') - * Later in the API processing phase this is forced by our - * MIME API-hook function. This time its no problem even for - * the per-directory context (where the MIME-type hook was - * already processed) because a sub-request happens ;-) - */ - if (p->forced_mimetype != NULL) { - apr_table_setn(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR, - p->forced_mimetype); - if (perdir == NULL) { - rewritelog(r, 2, "remember %s to have MIME-type '%s'", - r->filename, p->forced_mimetype); - } - else { - rewritelog(r, 2, - "[per-dir %s] remember %s to have MIME-type '%s'", - perdir, r->filename, p->forced_mimetype); - } - } - - /* - * Puuhhhhhhhh... WHAT COMPLICATED STUFF ;_) - * But now we're done for this particular rule. - */ - return 1; -} - -static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p, - char *perdir, backrefinfo *briRR, - backrefinfo *briRC) -{ - char input[MAX_STRING_LEN]; - apr_finfo_t sb; - request_rec *rsub; - regmatch_t regmatch[MAX_NMATCH]; - int rc; - - /* - * Construct the string we match against - */ - - do_expand(r, p->input, input, sizeof(input), briRR, briRC); - - /* - * Apply the patterns - */ - - rc = 0; - if (strcmp(p->pattern, "-f") == 0) { - if (apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS) { - if (sb.filetype == APR_REG) { - rc = 1; - } - } - } - else if (strcmp(p->pattern, "-s") == 0) { - if (apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS) { - if ((sb.filetype == APR_REG) && sb.size > 0) { - rc = 1; - } - } - } - else if (strcmp(p->pattern, "-l") == 0) { -#if !defined(OS2) - if (apr_lstat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS) { - if (sb.filetype == APR_LNK) { - rc = 1; - } - } -#endif - } - else if (strcmp(p->pattern, "-d") == 0) { - if (apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS) { - if (sb.filetype == APR_DIR) { - rc = 1; - } - } - } - else if (strcmp(p->pattern, "-U") == 0) { - /* avoid infinite subrequest recursion */ - if (strlen(input) > 0 && subreq_ok(r)) { - - /* run a URI-based subrequest */ - rsub = ap_sub_req_lookup_uri(input, r, NULL); - - /* URI exists for any result up to 3xx, redirects allowed */ - if (rsub->status < 400) - rc = 1; - - /* log it */ - rewritelog(r, 5, "RewriteCond URI (-U) check: " - "path=%s -> status=%d", input, rsub->status); - - /* cleanup by destroying the subrequest */ - ap_destroy_sub_req(rsub); - } - } - else if (strcmp(p->pattern, "-F") == 0) { - /* avoid infinite subrequest recursion */ - if (strlen(input) > 0 && subreq_ok(r)) { - - /* process a file-based subrequest: - * this differs from -U in that no path translation is done. - */ - rsub = ap_sub_req_lookup_file(input, r, NULL); - - /* file exists for any result up to 2xx, no redirects */ - if (rsub->status < 300 && - /* double-check that file exists since default result is 200 */ - apr_stat(&sb, rsub->filename, APR_FINFO_MIN, - r->pool) == APR_SUCCESS) { - rc = 1; - } - - /* log it */ - rewritelog(r, 5, "RewriteCond file (-F) check: path=%s " - "-> file=%s status=%d", input, rsub->filename, - rsub->status); - - /* cleanup by destroying the subrequest */ - ap_destroy_sub_req(rsub); - } - } - else if (strlen(p->pattern) > 1 && *(p->pattern) == '>') { - rc = (compare_lexicography(input, p->pattern+1) == 1 ? 1 : 0); - } - else if (strlen(p->pattern) > 1 && *(p->pattern) == '<') { - rc = (compare_lexicography(input, p->pattern+1) == -1 ? 1 : 0); - } - else if (strlen(p->pattern) > 1 && *(p->pattern) == '=') { - if (strcmp(p->pattern+1, "\"\"") == 0) { - rc = (*input == '\0'); - } - else { - rc = (strcmp(input, p->pattern+1) == 0 ? 1 : 0); - } - } - else { - /* it is really a regexp pattern, so apply it */ - rc = (ap_regexec(p->regexp, input, - p->regexp->re_nsub+1, regmatch,0) == 0); - - /* if it isn't a negated pattern and really matched - we update the passed-through regex subst info structure */ - if (rc && !(p->flags & CONDFLAG_NOTMATCH)) { - briRC->source = apr_pstrdup(r->pool, input); - briRC->nsub = p->regexp->re_nsub; - memcpy((void *)(briRC->regmatch), (void *)(regmatch), - sizeof(regmatch)); - } - } - - /* if this is a non-matching regexp, just negate the result */ - if (p->flags & CONDFLAG_NOTMATCH) { - rc = !rc; - } - - rewritelog(r, 4, "RewriteCond: input='%s' pattern='%s%s' => %s", - input, (p->flags & CONDFLAG_NOTMATCH ? "!" : ""), - p->pattern, rc ? "matched" : "not-matched"); - - /* end just return the result */ - return rc; -} - - -/* -** +-------------------------------------------------------+ -** | | -** | URL transformation functions -** | | -** +-------------------------------------------------------+ -*/ - - -/* -** -** perform all the expansions on the input string -** leaving the result in the supplied buffer -** -*/ - -static void do_expand(request_rec *r, char *input, char *buffer, int nbuf, - backrefinfo *briRR, backrefinfo *briRC) -{ - char *inp, *outp; - size_t span, space; - - /* - * for security reasons this expansion must be perfomed in a - * single pass, otherwise an attacker can arrange for the result - * of an earlier expansion to include expansion specifiers that - * are interpreted by a later expansion, producing results that - * were not intended by the administrator. - */ - - inp = input; - outp = buffer; - space = nbuf - 1; /* room for '\0' */ - - for (;;) { - span = strcspn(inp, "$%"); - if (span > space) { - span = space; - } - memcpy(outp, inp, span); - inp += span; - outp += span; - space -= span; - if (space == 0 || *inp == '\0') { - break; - } - /* now we have a '$' or a '%' */ - if (inp[1] == '{') { - char *endp; - endp = find_closing_bracket(inp+2, '{', '}'); - if (endp == NULL) { - goto skip; - } - /* - * These lookups may be recursive in a very convoluted - * fashion -- see the LA-U and LA-F variable expansion - * prefixes -- so we copy lookup keys to a separate buffer - * rather than adding zero bytes in order to use them in - * place. - */ - if (inp[0] == '$') { - /* ${...} map lookup expansion */ - /* - * To make rewrite maps useful the lookup key and - * default values must be expanded, so we make - * recursive calls to do the work. For security - * reasons we must never expand a string that includes - * verbatim data from the network. The recursion here - * isn't a problem because the result of expansion is - * only passed to lookup_map() so it cannot be - * re-expanded, only re-looked-up. Another way of - * looking at it is that the recursion is entirely - * driven by the syntax of the nested curly brackets. - */ - char *map, *key, *dflt, *result; - char xkey[MAX_STRING_LEN]; - char xdflt[MAX_STRING_LEN]; - key = find_char_in_brackets(inp+2, ':', '{', '}'); - if (key == NULL) - goto skip; - map = apr_pstrndup(r->pool, inp+2, key-inp-2); - dflt = find_char_in_brackets(key+1, '|', '{', '}'); - if (dflt == NULL) { - key = apr_pstrndup(r->pool, key+1, endp-key-1); - dflt = ""; - } else { - key = apr_pstrndup(r->pool, key+1, dflt-key-1); - dflt = apr_pstrndup(r->pool, dflt+1, endp-dflt-1); - } - do_expand(r, key, xkey, sizeof(xkey), briRR, briRC); - result = lookup_map(r, map, xkey); - if (result) { - span = apr_cpystrn(outp, result, space) - outp; - } else { - do_expand(r, dflt, xdflt, sizeof(xdflt), briRR, briRC); - span = apr_cpystrn(outp, xdflt, space) - outp; - } - } - else if (inp[0] == '%') { - /* %{...} variable lookup expansion */ - char *var; - var = apr_pstrndup(r->pool, inp+2, endp-inp-2); - span = apr_cpystrn(outp, lookup_variable(r, var), space) - outp; - } - else { - span = 0; - } - inp = endp+1; - outp += span; - space -= span; - continue; - } - else if (apr_isdigit(inp[1])) { - int n = inp[1] - '0'; - backrefinfo *bri = NULL; - if (inp[0] == '$') { - /* $N RewriteRule regexp backref expansion */ - bri = briRR; - } - else if (inp[0] == '%') { - /* %N RewriteCond regexp backref expansion */ - bri = briRC; - } - /* see ap_pregsub() in src/main/util.c */ - if (bri && n <= bri->nsub && - bri->regmatch[n].rm_eo > bri->regmatch[n].rm_so) { - span = bri->regmatch[n].rm_eo - bri->regmatch[n].rm_so; - if (span > space) { - span = space; - } - memcpy(outp, bri->source + bri->regmatch[n].rm_so, span); - outp += span; - space -= span; - } - inp += 2; - continue; - } - skip: - *outp++ = *inp++; - space--; - } - *outp++ = '\0'; -} - - -/* -** -** perform all the expansions on the environment variables -** -*/ - -static void do_expand_env(request_rec *r, char *env[], - backrefinfo *briRR, backrefinfo *briRC) -{ - int i; - char buf[MAX_STRING_LEN]; - - for (i = 0; env[i] != NULL; i++) { - do_expand(r, env[i], buf, sizeof(buf), briRR, briRC); - add_env_variable(r, buf); - } -} - - -/* -** -** split out a QUERY_STRING part from -** the current URI string -** -*/ - -static void splitout_queryargs(request_rec *r, int qsappend) -{ - char *q; - char *olduri; - - q = strchr(r->filename, '?'); - if (q != NULL) { - olduri = apr_pstrdup(r->pool, r->filename); - *q++ = '\0'; - if (qsappend) { - r->args = apr_pstrcat(r->pool, q, "&", r->args, NULL); - } - else { - r->args = apr_pstrdup(r->pool, q); - } - if (strlen(r->args) == 0) { - r->args = NULL; - rewritelog(r, 3, "split uri=%s -> uri=%s, args=<none>", olduri, - r->filename); - } - else { - if (r->args[strlen(r->args)-1] == '&') { - r->args[strlen(r->args)-1] = '\0'; - } - rewritelog(r, 3, "split uri=%s -> uri=%s, args=%s", olduri, - r->filename, r->args); - } - } - return; -} - - -/* -** -** strip 'http[s]://ourhost/' from URI -** -*/ - -static void reduce_uri(request_rec *r) -{ - char *cp; - unsigned short port; - char *portp; - char *hostp; - char *url; - char c; - char host[LONG_STRING_LEN]; - char buf[MAX_STRING_LEN]; - char *olduri; - int l; - - cp = (char *)ap_http_method(r); - l = strlen(cp); - if ( strlen(r->filename) > l+3 - && strncasecmp(r->filename, cp, l) == 0 - && r->filename[l] == ':' - && r->filename[l+1] == '/' - && r->filename[l+2] == '/' ) { - /* there was really a rewrite to a remote path */ - - olduri = apr_pstrdup(r->pool, r->filename); /* save for logging */ - - /* cut the hostname and port out of the URI */ - apr_cpystrn(buf, r->filename+(l+3), sizeof(buf)); - hostp = buf; - for (cp = hostp; *cp != '\0' && *cp != '/' && *cp != ':'; cp++) - ; - if (*cp == ':') { - /* set host */ - *cp++ = '\0'; - apr_cpystrn(host, hostp, sizeof(host)); - /* set port */ - portp = cp; - for (; *cp != '\0' && *cp != '/'; cp++) - ; - c = *cp; - *cp = '\0'; - port = atoi(portp); - *cp = c; - /* set remaining url */ - url = cp; - } - else if (*cp == '/') { - /* set host */ - *cp = '\0'; - apr_cpystrn(host, hostp, sizeof(host)); - *cp = '/'; - /* set port */ - port = ap_default_port(r); - /* set remaining url */ - url = cp; - } - else { - /* set host */ - apr_cpystrn(host, hostp, sizeof(host)); - /* set port */ - port = ap_default_port(r); - /* set remaining url */ - url = "/"; - } - - /* now check whether we could reduce it to a local path... */ - if (ap_matches_request_vhost(r, host, port)) { - /* this is our host, so only the URL remains */ - r->filename = apr_pstrdup(r->pool, url); - rewritelog(r, 3, "reduce %s -> %s", olduri, r->filename); - } - } - return; -} - - -/* -** -** add 'http[s]://ourhost[:ourport]/' to URI -** if URI is still not fully qualified -** -*/ - -static void fully_qualify_uri(request_rec *r) -{ - char buf[32]; - const char *thisserver; - char *thisport; - int port; - - if (!is_absolute_uri(r->filename)) { - - thisserver = ap_get_server_name(r); - port = ap_get_server_port(r); - if (ap_is_default_port(port,r)) { - thisport = ""; - } - else { - apr_snprintf(buf, sizeof(buf), ":%u", port); - thisport = buf; - } - - if (r->filename[0] == '/') { - r->filename = apr_psprintf(r->pool, "%s://%s%s%s", - ap_http_method(r), thisserver, - thisport, r->filename); - } - else { - r->filename = apr_psprintf(r->pool, "%s://%s%s/%s", - ap_http_method(r), thisserver, - thisport, r->filename); - } - } - return; -} - - -/* -** -** return non-zero if the URI is absolute (includes a scheme etc.) -** -*/ - -static int is_absolute_uri(char *uri) -{ - int i = strlen(uri); - if ( (i > 7 && strncasecmp(uri, "http://", 7) == 0) - || (i > 8 && strncasecmp(uri, "https://", 8) == 0) - || (i > 9 && strncasecmp(uri, "gopher://", 9) == 0) - || (i > 6 && strncasecmp(uri, "ftp://", 6) == 0) - || (i > 5 && strncasecmp(uri, "ldap:", 5) == 0) - || (i > 5 && strncasecmp(uri, "news:", 5) == 0) - || (i > 7 && strncasecmp(uri, "mailto:", 7) == 0) ) { - return 1; - } - else { - return 0; - } -} - - -/* -** -** Expand tilde-paths (/~user) through Unix /etc/passwd -** database information (or other OS-specific database) -** -*/ -#if APR_HAS_USER -static char *expand_tildepaths(request_rec *r, char *uri) -{ - char user[LONG_STRING_LEN]; - char *newuri; - int i, j; - char *homedir; - - newuri = uri; - if (uri != NULL && strlen(uri) > 2 && uri[0] == '/' && uri[1] == '~') { - /* cut out the username */ - for (j = 0, i = 2; j < sizeof(user)-1 - && uri[i] != '\0' - && uri[i] != '/' ; ) { - user[j++] = uri[i++]; - } - user[j] = '\0'; - - /* lookup username in systems passwd file */ - if (apr_get_home_directory(&homedir, user, r->pool) == APR_SUCCESS) { - /* ok, user was found, so expand the ~user string */ - if (uri[i] != '\0') { - /* ~user/anything... has to be expanded */ - if (homedir[strlen(homedir)-1] == '/') { - homedir[strlen(homedir)-1] = '\0'; - } - newuri = apr_pstrcat(r->pool, homedir, uri+i, NULL); - } - else { - /* only ~user has to be expanded */ - newuri = homedir; - } - } - } - return newuri; -} -#endif /* if APR_HAS_USER */ - - - -/* -** +-------------------------------------------------------+ -** | | -** | DBM hashfile support -** | | -** +-------------------------------------------------------+ -*/ - - -static char *lookup_map(request_rec *r, char *name, char *key) -{ - rewrite_server_conf *conf; - apr_array_header_t *rewritemaps; - rewritemap_entry *entries; - rewritemap_entry *s; - char *value; - apr_finfo_t st; - apr_status_t rv; - int i; - - /* get map configuration */ - conf = ap_get_module_config(r->server->module_config, &rewrite_module); - rewritemaps = conf->rewritemaps; - - entries = (rewritemap_entry *)rewritemaps->elts; - for (i = 0; i < rewritemaps->nelts; i++) { - s = &entries[i]; - if (strcmp(s->name, name) == 0) { - if (s->type == MAPTYPE_TXT) { - if ((rv = apr_stat(&st, s->checkfile, - APR_FINFO_MIN, r->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "mod_rewrite: can't access text RewriteMap " - "file %s", s->checkfile); - rewritelog(r, 1, "can't open RewriteMap file, " - "see error log"); - return NULL; - } - value = get_cache_string(cachep, s->name, CACHEMODE_TS, - st.mtime, key); - if (value == NULL) { - rewritelog(r, 6, "cache lookup FAILED, forcing new " - "map lookup"); - if ((value = - lookup_map_txtfile(r, s->datafile, key)) != NULL) { - rewritelog(r, 5, "map lookup OK: map=%s key=%s[txt] " - "-> val=%s", s->name, key, value); - set_cache_string(cachep, s->name, CACHEMODE_TS, - st.mtime, key, value); - return value; - } - else { - rewritelog(r, 5, "map lookup FAILED: map=%s[txt] " - "key=%s", s->name, key); - set_cache_string(cachep, s->name, CACHEMODE_TS, - st.mtime, key, ""); - return NULL; - } - } - else { - rewritelog(r, 5, "cache lookup OK: map=%s[txt] key=%s " - "-> val=%s", s->name, key, value); - return value[0] != '\0' ? value : NULL; - } - } - else if (s->type == MAPTYPE_DBM) { -#ifndef NO_DBM_REWRITEMAP - if ((rv = apr_stat(&st, s->checkfile, - APR_FINFO_MIN, r->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "mod_rewrite: can't access DBM RewriteMap " - "file %s", s->checkfile); - rewritelog(r, 1, "can't open DBM RewriteMap file, " - "see error log"); - return NULL; - } - value = get_cache_string(cachep, s->name, CACHEMODE_TS, - st.mtime, key); - if (value == NULL) { - rewritelog(r, 6, - "cache lookup FAILED, forcing new map lookup"); - if ((value = - lookup_map_dbmfile(r, s->datafile, key)) != NULL) { - rewritelog(r, 5, "map lookup OK: map=%s[dbm] key=%s " - "-> val=%s", s->name, key, value); - set_cache_string(cachep, s->name, CACHEMODE_TS, - st.mtime, key, value); - return value; - } - else { - rewritelog(r, 5, "map lookup FAILED: map=%s[dbm] " - "key=%s", s->name, key); - set_cache_string(cachep, s->name, CACHEMODE_TS, - st.mtime, key, ""); - return NULL; - } - } - else { - rewritelog(r, 5, "cache lookup OK: map=%s[dbm] key=%s " - "-> val=%s", s->name, key, value); - return value[0] != '\0' ? value : NULL; - } -#else - return NULL; -#endif - } - else if (s->type == MAPTYPE_PRG) { - if ((value = - lookup_map_program(r, s->fpin, s->fpout, key)) != NULL) { - rewritelog(r, 5, "map lookup OK: map=%s key=%s -> val=%s", - s->name, key, value); - return value; - } - else { - rewritelog(r, 5, "map lookup FAILED: map=%s key=%s", - s->name, key); - } - } - else if (s->type == MAPTYPE_INT) { - if ((value = lookup_map_internal(r, s->func, key)) != NULL) { - rewritelog(r, 5, "map lookup OK: map=%s key=%s -> val=%s", - s->name, key, value); - return value; - } - else { - rewritelog(r, 5, "map lookup FAILED: map=%s key=%s", - s->name, key); - } - } - else if (s->type == MAPTYPE_RND) { - if ((rv = apr_stat(&st, s->checkfile, - APR_FINFO_MIN, r->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "mod_rewrite: can't access text RewriteMap " - "file %s", s->checkfile); - rewritelog(r, 1, "can't open RewriteMap file, " - "see error log"); - return NULL; - } - value = get_cache_string(cachep, s->name, CACHEMODE_TS, - st.mtime, key); - if (value == NULL) { - rewritelog(r, 6, "cache lookup FAILED, forcing new " - "map lookup"); - if ((value = - lookup_map_txtfile(r, s->datafile, key)) != NULL) { - rewritelog(r, 5, "map lookup OK: map=%s key=%s[txt] " - "-> val=%s", s->name, key, value); - set_cache_string(cachep, s->name, CACHEMODE_TS, - st.mtime, key, value); - } - else { - rewritelog(r, 5, "map lookup FAILED: map=%s[txt] " - "key=%s", s->name, key); - set_cache_string(cachep, s->name, CACHEMODE_TS, - st.mtime, key, ""); - return NULL; - } - } - else { - rewritelog(r, 5, "cache lookup OK: map=%s[txt] key=%s " - "-> val=%s", s->name, key, value); - } - if (value[0] != '\0') { - value = select_random_value_part(r, value); - rewritelog(r, 5, "randomly choosen the subvalue `%s'", value); - } - else { - value = NULL; - } - return value; - } - } - } - return NULL; -} - -static char *lookup_map_txtfile(request_rec *r, const char *file, char *key) -{ - apr_file_t *fp = NULL; - apr_status_t rc; - char line[1024]; - char *value = NULL; - char *cpT; - size_t skip; - char *curkey; - char *curval; - - rc = apr_file_open(&fp, file, APR_READ, APR_OS_DEFAULT, r->pool); - if (rc != APR_SUCCESS) { - return NULL; - } - - while (apr_file_gets(line, sizeof(line), fp) == APR_SUCCESS) { - if (line[0] == '#') - continue; /* ignore comments */ - cpT = line; - curkey = cpT; - skip = strcspn(cpT," \t\r\n"); - if (skip == 0) - continue; /* ignore lines that start with a space, tab, CR, or LF */ - cpT += skip; - *cpT = '\0'; - if (strcmp(curkey, key) != 0) - continue; /* key does not match... */ - - /* found a matching key; now extract and return the value */ - ++cpT; - skip = strspn(cpT, " \t\r\n"); - cpT += skip; - curval = cpT; - skip = strcspn(cpT, " \t\r\n"); - if (skip == 0) - continue; /* no value... */ - cpT += skip; - *cpT = '\0'; - value = apr_pstrdup(r->pool, curval); - break; - } - apr_file_close(fp); - return value; -} - -#ifndef NO_DBM_REWRITEMAP -static char *lookup_map_dbmfile(request_rec *r, const char *file, char *key) -{ - DBM *dbmfp = NULL; - datum dbmkey; - datum dbmval; - char *value = NULL; - char buf[MAX_STRING_LEN]; - - dbmkey.dptr = key; - dbmkey.dsize = strlen(key); - if ((dbmfp = dbm_open(file, O_RDONLY, 0666)) != NULL) { - dbmval = dbm_fetch(dbmfp, dbmkey); - if (dbmval.dptr != NULL) { - memcpy(buf, dbmval.dptr, - dbmval.dsize < sizeof(buf)-1 ? - dbmval.dsize : sizeof(buf)-1 ); - buf[dbmval.dsize] = '\0'; - value = apr_pstrdup(r->pool, buf); - } - dbm_close(dbmfp); - } - return value; -} -#endif - -static char *lookup_map_program(request_rec *r, apr_file_t *fpin, - apr_file_t *fpout, char *key) -{ - char buf[LONG_STRING_LEN]; - char c; - int i; - apr_size_t nbytes; - -#ifndef NO_WRITEV - struct iovec iova[2]; - apr_size_t niov; -#endif - - /* when `RewriteEngine off' was used in the per-server - * context then the rewritemap-programs were not spawned. - * In this case using such a map (usually in per-dir context) - * is useless because it is not available. - */ - if (fpin == NULL || fpout == NULL) { - return NULL; - } - - /* take the lock */ - - if (rewrite_mapr_lock_acquire) { - apr_lock_acquire(rewrite_mapr_lock_acquire); - } - - /* write out the request key */ -#ifdef NO_WRITEV - nbytes = strlen(key); - apr_file_write(fpin, key, &nbytes); - nbytes = 1; - apr_file_write(fpin, "\n", &nbytes); -#else - iova[0].iov_base = key; - iova[0].iov_len = strlen(key); - iova[1].iov_base = "\n"; - iova[1].iov_len = 1; - - niov = 2; - apr_file_writev(fpin, iova, niov, &nbytes); -#endif - - /* read in the response value */ - i = 0; - nbytes = 1; - apr_file_read(fpout, &c, &nbytes); - while (nbytes == 1 && (i < LONG_STRING_LEN-1)) { - if (c == '\n') { - break; - } - buf[i++] = c; - - apr_file_read(fpout, &c, &nbytes); - } - buf[i] = '\0'; - - /* give the lock back */ - if (rewrite_mapr_lock_acquire) { - apr_lock_release(rewrite_mapr_lock_acquire); - } - - if (strcasecmp(buf, "NULL") == 0) { - return NULL; - } - else { - return apr_pstrdup(r->pool, buf); - } -} - -static char *lookup_map_internal(request_rec *r, - char *(*func)(request_rec *, char *), - char *key) -{ - /* currently we just let the function convert - the key to a corresponding value */ - return func(r, key); -} - -static char *rewrite_mapfunc_toupper(request_rec *r, char *key) -{ - char *value, *cp; - - for (cp = value = apr_pstrdup(r->pool, key); cp != NULL && *cp != '\0'; - cp++) { - *cp = apr_toupper(*cp); - } - return value; -} - -static char *rewrite_mapfunc_tolower(request_rec *r, char *key) -{ - char *value, *cp; - - for (cp = value = apr_pstrdup(r->pool, key); cp != NULL && *cp != '\0'; - cp++) { - *cp = apr_tolower(*cp); - } - return value; -} - -static char *rewrite_mapfunc_escape(request_rec *r, char *key) -{ - char *value; - - value = ap_escape_uri(r->pool, key); - return value; -} - -static char *rewrite_mapfunc_unescape(request_rec *r, char *key) -{ - char *value; - - value = apr_pstrdup(r->pool, key); - ap_unescape_url(value); - return value; -} - -static int rewrite_rand_init_done = 0; - -static void rewrite_rand_init(void) -{ - if (!rewrite_rand_init_done) { - srand((unsigned)(getpid())); - rewrite_rand_init_done = 1; - } - return; -} - -static int rewrite_rand(int l, int h) -{ - rewrite_rand_init(); - - /* Get [0,1) and then scale to the appropriate range. Note that using - * a floating point value ensures that we use all bits of the rand() - * result. Doing an integer modulus would only use the lower-order bits - * which may not be as uniformly random. - */ - return ((double)(rand() % RAND_MAX) / RAND_MAX) * (h - l + 1) + l; -} - -static char *select_random_value_part(request_rec *r, char *value) -{ - char *buf; - int n, i, k; - - /* count number of distinct values */ - for (n = 1, i = 0; value[i] != '\0'; i++) { - if (value[i] == '|') { - n++; - } - } - - /* when only one value we have no option to choose */ - if (n == 1) { - return value; - } - - /* else randomly select one */ - k = rewrite_rand(1, n); - - /* and grep it out */ - for (n = 1, i = 0; value[i] != '\0'; i++) { - if (n == k) { - break; - } - if (value[i] == '|') { - n++; - } - } - buf = apr_pstrdup(r->pool, &value[i]); - for (i = 0; buf[i] != '\0' && buf[i] != '|'; i++) - ; - buf[i] = '\0'; - return buf; -} - - -/* -** +-------------------------------------------------------+ -** | | -** | rewriting logfile support -** | | -** +-------------------------------------------------------+ -*/ - - -static void open_rewritelog(server_rec *s, apr_pool_t *p) -{ - rewrite_server_conf *conf; - const char *fname; - apr_status_t rc; - piped_log *pl; - int rewritelog_flags = ( APR_WRITE | APR_APPEND | APR_CREATE ); - apr_fileperms_t rewritelog_mode = ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD ); - - conf = ap_get_module_config(s->module_config, &rewrite_module); - - if (conf->rewritelogfile == NULL) { - return; - } - if (*(conf->rewritelogfile) == '\0') { - return; - } - if (conf->rewritelogfp != NULL) { - return; /* virtual log shared w/ main server */ - } - - fname = ap_server_root_relative(p, conf->rewritelogfile); - - if (*conf->rewritelogfile == '|') { - if ((pl = ap_open_piped_log(p, conf->rewritelogfile+1)) == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, s, - "mod_rewrite: could not open reliable pipe " - "to RewriteLog filter %s", conf->rewritelogfile+1); - exit(1); - } - conf->rewritelogfp = ap_piped_log_write_fd(pl); - } - else if (*conf->rewritelogfile != '\0') { - rc = apr_file_open(&conf->rewritelogfp, fname, rewritelog_flags, rewritelog_mode, p); - if (rc != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, - "mod_rewrite: could not open RewriteLog " - "file %s", fname); - exit(1); - } - } - return; -} - -static void rewritelog(request_rec *r, int level, const char *text, ...) -{ - rewrite_server_conf *conf; - conn_rec *conn; - char *str1; - char str2[512]; - char str3[1024]; - char type[20]; - char redir[20]; - va_list ap; - int i; - apr_size_t nbytes; - request_rec *req; - char *ruser; - const char *rhost; - - va_start(ap, text); - conf = ap_get_module_config(r->server->module_config, &rewrite_module); - conn = r->connection; - - if (conf->rewritelogfp == NULL) { - return; - } - if (conf->rewritelogfile == NULL) { - return; - } - if (*(conf->rewritelogfile) == '\0') { - return; - } - - if (level > conf->rewriteloglevel) { - return; - } - - if (r->user == NULL) { - ruser = "-"; - } - else if (strlen(r->user) != 0) { - ruser = r->user; - } - else { - ruser = "\"\""; - } - - rhost = ap_get_remote_host(conn, r->server->module_config, - REMOTE_NOLOOKUP, NULL); - if (rhost == NULL) { - rhost = "UNKNOWN-HOST"; - } - - str1 = apr_pstrcat(r->pool, rhost, " ", - (conn->remote_logname != NULL ? - conn->remote_logname : "-"), " ", - ruser, NULL); - apr_vsnprintf(str2, sizeof(str2), text, ap); - - if (r->main == NULL) { - strcpy(type, "initial"); - } - else { - strcpy(type, "subreq"); - } - - for (i = 0, req = r; req->prev != NULL; req = req->prev) { - i++; - } - if (i == 0) { - redir[0] = '\0'; - } - else { - apr_snprintf(redir, sizeof(redir), "/redir#%d", i); - } - - apr_snprintf(str3, sizeof(str3), - "%s %s [%s/sid#%lx][rid#%lx/%s%s] (%d) %s\n", str1, - current_logtime(r), ap_get_server_name(r), - (unsigned long)(r->server), (unsigned long)r, - type, redir, level, str2); - - apr_lock_acquire(rewrite_log_lock); - nbytes = strlen(str3); - apr_file_write(conf->rewritelogfp, str3, &nbytes); - apr_lock_release(rewrite_log_lock); - - va_end(ap); - return; -} - -static char *current_logtime(request_rec *r) -{ - apr_exploded_time_t t; - char tstr[80]; - apr_size_t len; - - apr_explode_localtime(&t, apr_time_now()); - - apr_strftime(tstr, &len, 80, "[%d/%b/%Y:%H:%M:%S ", &t); - apr_snprintf(tstr + strlen(tstr), 80-strlen(tstr), "%c%.2d%.2d]", - t.tm_gmtoff < 0 ? '-' : '+', - t.tm_gmtoff / (60*60), t.tm_gmtoff % (60*60)); - return apr_pstrdup(r->pool, tstr); -} - - - - -/* -** +-------------------------------------------------------+ -** | | -** | rewriting lockfile support -** | | -** +-------------------------------------------------------+ -*/ - -#define REWRITELOCK_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD ) - -static void rewritelock_create(server_rec *s, apr_pool_t *p) -{ - apr_status_t rc; - - /* only operate if a lockfile is used */ - if (lockname == NULL || *(lockname) == '\0') { - return; - } - - /* fixup the path, especially for rewritelock_remove() */ - lockname = ap_server_root_relative(p, lockname); - - /* create the lockfile */ - rc = apr_lock_create (&rewrite_mapr_lock_acquire, APR_MUTEX, APR_LOCKALL, lockname, p); - if (rc != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, - "mod_rewrite: Parent could not create RewriteLock " - "file %s", lockname); - exit(1); - } - - return; -} - -static apr_status_t rewritelock_remove(void *data) -{ - /* only operate if a lockfile is used */ - if (lockname == NULL || *(lockname) == '\0') { - return APR_SUCCESS; - } - - /* destroy the rewritelock */ - apr_lock_destroy (rewrite_mapr_lock_acquire); - rewrite_mapr_lock_acquire = NULL; - lockname = NULL; - return(0); -} - - -/* -** +-------------------------------------------------------+ -** | | -** | program map support -** | | -** +-------------------------------------------------------+ -*/ - -static void run_rewritemap_programs(server_rec *s, apr_pool_t *p) -{ - rewrite_server_conf *conf; - apr_file_t *fpin = NULL; - apr_file_t *fpout = NULL; - apr_file_t *fperr = NULL; - apr_array_header_t *rewritemaps; - rewritemap_entry *entries; - rewritemap_entry *map; - int i; - apr_status_t rc; - - conf = ap_get_module_config(s->module_config, &rewrite_module); - - /* If the engine isn't turned on, - * don't even try to do anything. - */ - if (conf->state == ENGINE_DISABLED) { - return; - } - - rewritemaps = conf->rewritemaps; - entries = (rewritemap_entry *)rewritemaps->elts; - for (i = 0; i < rewritemaps->nelts; i++) { - map = &entries[i]; - if (map->type != MAPTYPE_PRG) { - continue; - } - if (map->datafile == NULL - || *(map->datafile) == '\0' - || map->fpin != NULL - || map->fpout != NULL ) { - continue; - } - fpin = NULL; - fpout = NULL; - rc = rewritemap_program_child(p, map->datafile, - &fpout, &fpin, &fperr); - if (rc != APR_SUCCESS || fpin == NULL || fpout == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, - "mod_rewrite: could not fork child for " - "RewriteMap process"); - exit(1); - } - map->fpin = fpin; - map->fpout = fpout; - map->fperr = fperr; - } - return; -} - -/* child process code */ -static apr_status_t rewritemap_program_child(apr_pool_t *p, const char *progname, - apr_file_t **fpout, apr_file_t **fpin, - apr_file_t **fperr) -{ - apr_status_t rc; - apr_procattr_t *procattr; - apr_proc_t *procnew; - -#ifdef SIGHUP - apr_signal(SIGHUP, SIG_IGN); -#endif - - - if (((rc = apr_procattr_create(&procattr, p)) != APR_SUCCESS) || - ((rc = apr_procattr_io_set(procattr, APR_FULL_BLOCK, - APR_FULL_NONBLOCK, - APR_FULL_NONBLOCK)) != APR_SUCCESS) || - ((rc = apr_procattr_dir_set(procattr, - ap_make_dirstr_parent(p, progname))) - != APR_SUCCESS) || - ((rc = apr_procattr_cmdtype_set(procattr, APR_PROGRAM)) != APR_SUCCESS)) { - /* Something bad happened, give up and go away. */ - } - else { - procnew = apr_pcalloc(p, sizeof(*procnew)); - rc = apr_proc_create(procnew, progname, NULL, NULL, procattr, p); - - if (rc == APR_SUCCESS) { - apr_pool_note_subprocess(p, procnew, kill_after_timeout); - - if (fpin) { - (*fpin) = procnew->in; - } - - if (fpout) { - (*fpout) = procnew->out; - } - - if (fperr) { - (*fperr) = procnew->err; - } - } - } - - return (rc); -} - - - - -/* -** +-------------------------------------------------------+ -** | | -** | environment variable support -** | | -** +-------------------------------------------------------+ -*/ - - -static char *lookup_variable(request_rec *r, char *var) -{ - const char *result; - char resultbuf[LONG_STRING_LEN]; - apr_exploded_time_t tm; - request_rec *rsub; - - result = NULL; - - /* HTTP headers */ - if (strcasecmp(var, "HTTP_USER_AGENT") == 0) { - result = lookup_header(r, "User-Agent"); - } - else if (strcasecmp(var, "HTTP_REFERER") == 0) { - result = lookup_header(r, "Referer"); - } - else if (strcasecmp(var, "HTTP_COOKIE") == 0) { - result = lookup_header(r, "Cookie"); - } - else if (strcasecmp(var, "HTTP_FORWARDED") == 0) { - result = lookup_header(r, "Forwarded"); - } - else if (strcasecmp(var, "HTTP_HOST") == 0) { - result = lookup_header(r, "Host"); - } - else if (strcasecmp(var, "HTTP_PROXY_CONNECTION") == 0) { - result = lookup_header(r, "Proxy-Connection"); - } - else if (strcasecmp(var, "HTTP_ACCEPT") == 0) { - result = lookup_header(r, "Accept"); - } - /* all other headers from which we are still not know about */ - else if (strlen(var) > 5 && strncasecmp(var, "HTTP:", 5) == 0) { - result = lookup_header(r, var+5); - } - - /* connection stuff */ - else if (strcasecmp(var, "REMOTE_ADDR") == 0) { - result = r->connection->remote_ip; - } - else if (strcasecmp(var, "REMOTE_HOST") == 0) { - result = (char *)ap_get_remote_host(r->connection, - r->per_dir_config, REMOTE_NAME, NULL); - } - else if (strcasecmp(var, "REMOTE_USER") == 0) { - result = r->user; - } - else if (strcasecmp(var, "REMOTE_IDENT") == 0) { - result = (char *)ap_get_remote_logname(r); - } - - /* request stuff */ - else if (strcasecmp(var, "THE_REQUEST") == 0) { /* non-standard */ - result = r->the_request; - } - else if (strcasecmp(var, "REQUEST_METHOD") == 0) { - result = r->method; - } - else if (strcasecmp(var, "REQUEST_URI") == 0) { /* non-standard */ - result = r->uri; - } - else if (strcasecmp(var, "SCRIPT_FILENAME") == 0 || - strcasecmp(var, "REQUEST_FILENAME") == 0 ) { - result = r->filename; - } - else if (strcasecmp(var, "PATH_INFO") == 0) { - result = r->path_info; - } - else if (strcasecmp(var, "QUERY_STRING") == 0) { - result = r->args; - } - else if (strcasecmp(var, "AUTH_TYPE") == 0) { - result = r->ap_auth_type; - } - else if (strcasecmp(var, "IS_SUBREQ") == 0) { /* non-standard */ - result = (r->main != NULL ? "true" : "false"); - } - - /* internal server stuff */ - else if (strcasecmp(var, "DOCUMENT_ROOT") == 0) { - result = ap_document_root(r); - } - else if (strcasecmp(var, "SERVER_ADMIN") == 0) { - result = r->server->server_admin; - } - else if (strcasecmp(var, "SERVER_NAME") == 0) { - result = ap_get_server_name(r); - } - else if (strcasecmp(var, "SERVER_ADDR") == 0) { /* non-standard */ - result = r->connection->local_ip; - } - else if (strcasecmp(var, "SERVER_PORT") == 0) { - apr_snprintf(resultbuf, sizeof(resultbuf), "%u", ap_get_server_port(r)); - result = resultbuf; - } - else if (strcasecmp(var, "SERVER_PROTOCOL") == 0) { - result = r->protocol; - } - else if (strcasecmp(var, "SERVER_SOFTWARE") == 0) { - result = ap_get_server_version(); - } - else if (strcasecmp(var, "API_VERSION") == 0) { /* non-standard */ - apr_snprintf(resultbuf, sizeof(resultbuf), "%d:%d", - MODULE_MAGIC_NUMBER_MAJOR, MODULE_MAGIC_NUMBER_MINOR); - result = resultbuf; - } - -/* XXX: wow this has gotta be slow if you actually use it for a lot, recalculates exploded time for each variable */ - /* underlaying Unix system stuff */ - else if (strcasecmp(var, "TIME_YEAR") == 0) { - apr_explode_localtime(&tm, apr_time_now()); - apr_snprintf(resultbuf, sizeof(resultbuf), "%04d", tm.tm_year + 1900); - result = resultbuf; - } -#define MKTIMESTR(format, tmfield) \ - apr_explode_localtime(&tm, apr_time_now()); \ - apr_snprintf(resultbuf, sizeof(resultbuf), format, tm.tmfield); \ - result = resultbuf; - else if (strcasecmp(var, "TIME_MON") == 0) { - MKTIMESTR("%02d", tm_mon+1) - } - else if (strcasecmp(var, "TIME_DAY") == 0) { - MKTIMESTR("%02d", tm_mday) - } - else if (strcasecmp(var, "TIME_HOUR") == 0) { - MKTIMESTR("%02d", tm_hour) - } - else if (strcasecmp(var, "TIME_MIN") == 0) { - MKTIMESTR("%02d", tm_min) - } - else if (strcasecmp(var, "TIME_SEC") == 0) { - MKTIMESTR("%02d", tm_sec) - } - else if (strcasecmp(var, "TIME_WDAY") == 0) { - MKTIMESTR("%d", tm_wday) - } - else if (strcasecmp(var, "TIME") == 0) { - apr_explode_localtime(&tm, apr_time_now()); - apr_snprintf(resultbuf, sizeof(resultbuf), - "%04d%02d%02d%02d%02d%02d", tm.tm_year + 1900, - tm.tm_mon+1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - result = resultbuf; - rewritelog(r, 1, "RESULT='%s'", result); - } - - /* all other env-variables from the parent Apache process */ - else if (strlen(var) > 4 && strncasecmp(var, "ENV:", 4) == 0) { - /* first try the internal Apache notes structure */ - result = apr_table_get(r->notes, var+4); - /* second try the internal Apache env structure */ - if (result == NULL) { - result = apr_table_get(r->subprocess_env, var+4); - } - /* third try the external OS env */ - if (result == NULL) { - result = getenv(var+4); - } - } - -#define LOOKAHEAD(subrecfunc) \ - if ( \ - /* filename is safe to use */ \ - r->filename != NULL \ - /* - and we're either not in a subrequest */ \ - && ( r->main == NULL \ - /* - or in a subrequest where paths are non-NULL... */ \ - || ( r->main->uri != NULL && r->uri != NULL \ - /* ...and sub and main paths differ */ \ - && strcmp(r->main->uri, r->uri) != 0))) { \ - /* process a file-based subrequest */ \ - rsub = subrecfunc(r->filename, r, NULL); \ - /* now recursively lookup the variable in the sub_req */ \ - result = lookup_variable(rsub, var+5); \ - /* copy it up to our scope before we destroy sub_req's apr_pool_t */ \ - result = apr_pstrdup(r->pool, result); \ - /* cleanup by destroying the subrequest */ \ - ap_destroy_sub_req(rsub); \ - /* log it */ \ - rewritelog(r, 5, "lookahead: path=%s var=%s -> val=%s", \ - r->filename, var+5, result); \ - /* return ourself to prevent re-pstrdup */ \ - return (char *)result; \ - } - - /* look-ahead for parameter through URI-based sub-request */ - else if (strlen(var) > 5 && strncasecmp(var, "LA-U:", 5) == 0) { - LOOKAHEAD(ap_sub_req_lookup_uri) - } - /* look-ahead for parameter through file-based sub-request */ - else if (strlen(var) > 5 && strncasecmp(var, "LA-F:", 5) == 0) { - LOOKAHEAD(ap_sub_req_lookup_file) - } - - /* file stuff */ - else if (strcasecmp(var, "SCRIPT_USER") == 0) { - result = "<unknown>"; - if (r->finfo.valid & APR_FINFO_USER) { - apr_get_username((char **)&result, r->finfo.user, r->pool); - } - } - else if (strcasecmp(var, "SCRIPT_GROUP") == 0) { - result = "<unknown>"; - if (r->finfo.valid & APR_FINFO_GROUP) { - apr_get_groupname((char **)&result, r->finfo.group, r->pool); - } - } - - if (result == NULL) { - return apr_pstrdup(r->pool, ""); - } - else { - return apr_pstrdup(r->pool, result); - } -} - -static char *lookup_header(request_rec *r, const char *name) -{ - apr_array_header_t *hdrs_arr; - apr_table_entry_t *hdrs; - int i; - - hdrs_arr = apr_table_elts(r->headers_in); - hdrs = (apr_table_entry_t *)hdrs_arr->elts; - for (i = 0; i < hdrs_arr->nelts; ++i) { - if (hdrs[i].key == NULL) { - continue; - } - if (strcasecmp(hdrs[i].key, name) == 0) { - apr_table_merge(r->notes, VARY_KEY_THIS, name); - return hdrs[i].val; - } - } - return NULL; -} - - - - -/* -** +-------------------------------------------------------+ -** | | -** | caching support -** | | -** +-------------------------------------------------------+ -*/ - - -static cache *init_cache(apr_pool_t *p) -{ - cache *c; - - c = (cache *)apr_palloc(p, sizeof(cache)); - if (apr_pool_create(&c->pool, p) != APR_SUCCESS) - return NULL; - c->lists = apr_array_make(c->pool, 2, sizeof(cachelist)); - return c; -} - -static void set_cache_string(cache *c, const char *res, int mode, apr_time_t t, - char *key, char *value) -{ - cacheentry ce; - - ce.time = t; - ce.key = key; - ce.value = value; - store_cache_string(c, res, &ce); - return; -} - -static char *get_cache_string(cache *c, const char *res, int mode, - apr_time_t t, char *key) -{ - cacheentry *ce; - - ce = retrieve_cache_string(c, res, key); - if (ce == NULL) { - return NULL; - } - if (mode & CACHEMODE_TS) { - if (t != ce->time) { - return NULL; - } - } - else if (mode & CACHEMODE_TTL) { - if (t > ce->time) { - return NULL; - } - } - return apr_pstrdup(c->pool, ce->value); -} - -static int cache_tlb_hash(char *key) -{ - unsigned long n; - char *p; - - n = 0; - for (p = key; *p != '\0'; p++) { - n = ((n << 5) + n) ^ (unsigned long)(*p++); - } - - return n % CACHE_TLB_ROWS; -} - -static cacheentry *cache_tlb_lookup(cachetlbentry *tlb, cacheentry *elt, - char *key) -{ - int ix = cache_tlb_hash(key); - int i; - int j; - - for (i=0; i < CACHE_TLB_COLS; ++i) { - j = tlb[ix].t[i]; - if (j < 0) - return NULL; - if (strcmp(elt[j].key, key) == 0) - return &elt[j]; - } - return NULL; -} - -static void cache_tlb_replace(cachetlbentry *tlb, cacheentry *elt, - cacheentry *e) -{ - int ix = cache_tlb_hash(e->key); - int i; - - tlb = &tlb[ix]; - - for (i=1; i < CACHE_TLB_COLS; ++i) - tlb->t[i] = tlb->t[i-1]; - - tlb->t[0] = e - elt; -} - -static void store_cache_string(cache *c, const char *res, cacheentry *ce) -{ - int i; - int j; - cachelist *l; - cacheentry *e; - cachetlbentry *t; - int found_list; - - found_list = 0; - /* first try to edit an existing entry */ - for (i = 0; i < c->lists->nelts; i++) { - l = &(((cachelist *)c->lists->elts)[i]); - if (strcmp(l->resource, res) == 0) { - found_list = 1; - - e = cache_tlb_lookup((cachetlbentry *)l->tlb->elts, - (cacheentry *)l->entries->elts, ce->key); - if (e != NULL) { - e->time = ce->time; - e->value = apr_pstrdup(c->pool, ce->value); - return; - } - - for (j = 0; j < l->entries->nelts; j++) { - e = &(((cacheentry *)l->entries->elts)[j]); - if (strcmp(e->key, ce->key) == 0) { - e->time = ce->time; - e->value = apr_pstrdup(c->pool, ce->value); - cache_tlb_replace((cachetlbentry *)l->tlb->elts, - (cacheentry *)l->entries->elts, e); - return; - } - } - } - } - - /* create a needed new list */ - if (!found_list) { - l = apr_array_push(c->lists); - l->resource = apr_pstrdup(c->pool, res); - l->entries = apr_array_make(c->pool, 2, sizeof(cacheentry)); - l->tlb = apr_array_make(c->pool, CACHE_TLB_ROWS, - sizeof(cachetlbentry)); - for (i=0; i<CACHE_TLB_ROWS; ++i) { - t = &((cachetlbentry *)l->tlb->elts)[i]; - for (j=0; j<CACHE_TLB_COLS; ++j) - t->t[j] = -1; - } - } - - /* create the new entry */ - for (i = 0; i < c->lists->nelts; i++) { - l = &(((cachelist *)c->lists->elts)[i]); - if (strcmp(l->resource, res) == 0) { - e = apr_array_push(l->entries); - e->time = ce->time; - e->key = apr_pstrdup(c->pool, ce->key); - e->value = apr_pstrdup(c->pool, ce->value); - cache_tlb_replace((cachetlbentry *)l->tlb->elts, - (cacheentry *)l->entries->elts, e); - return; - } - } - - /* not reached, but when it is no problem... */ - return; -} - -static cacheentry *retrieve_cache_string(cache *c, const char *res, char *key) -{ - int i; - int j; - cachelist *l; - cacheentry *e; - - for (i = 0; i < c->lists->nelts; i++) { - l = &(((cachelist *)c->lists->elts)[i]); - if (strcmp(l->resource, res) == 0) { - - e = cache_tlb_lookup((cachetlbentry *)l->tlb->elts, - (cacheentry *)l->entries->elts, key); - if (e != NULL) - return e; - - for (j = 0; j < l->entries->nelts; j++) { - e = &(((cacheentry *)l->entries->elts)[j]); - if (strcmp(e->key, key) == 0) { - return e; - } - } - } - } - return NULL; -} - - - - -/* -** +-------------------------------------------------------+ -** | | -** | misc functions -** | | -** +-------------------------------------------------------+ -*/ - -static char *subst_prefix_path(request_rec *r, char *input, char *match, - const char *subst) -{ - char matchbuf[LONG_STRING_LEN]; - char substbuf[LONG_STRING_LEN]; - char *output; - int l; - - output = input; - - /* first create a match string which always has a trailing slash */ - l = apr_cpystrn(matchbuf, match, sizeof(matchbuf)) - matchbuf; - if (matchbuf[l-1] != '/') { - matchbuf[l] = '/'; - matchbuf[l+1] = '\0'; - l++; - } - /* now compare the prefix */ - if (strncmp(input, matchbuf, l) == 0) { - rewritelog(r, 5, "strip matching prefix: %s -> %s", output, output+l); - output = apr_pstrdup(r->pool, output+l); - - /* and now add the base-URL as replacement prefix */ - l = apr_cpystrn(substbuf, subst, sizeof(substbuf)) - substbuf; - if (substbuf[l-1] != '/') { - substbuf[l] = '/'; - substbuf[l+1] = '\0'; - l++; - } - if (output[0] == '/') { - rewritelog(r, 4, "add subst prefix: %s -> %s%s", - output, substbuf, output+1); - output = apr_pstrcat(r->pool, substbuf, output+1, NULL); - } - else { - rewritelog(r, 4, "add subst prefix: %s -> %s%s", - output, substbuf, output); - output = apr_pstrcat(r->pool, substbuf, output, NULL); - } - } - return output; -} - - -/* -** -** own command line parser which don't have the '\\' problem -** -*/ - -static int parseargline(char *str, char **a1, char **a2, char **a3) -{ - char *cp; - int isquoted; - -#define SKIP_WHITESPACE(cp) \ - for ( ; *cp == ' ' || *cp == '\t'; ) { \ - cp++; \ - }; - -#define CHECK_QUOTATION(cp,isquoted) \ - isquoted = 0; \ - if (*cp == '"') { \ - isquoted = 1; \ - cp++; \ - } - -#define DETERMINE_NEXTSTRING(cp,isquoted) \ - for ( ; *cp != '\0'; cp++) { \ - if ( (isquoted && (*cp == ' ' || *cp == '\t')) \ - || (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t'))) { \ - cp++; \ - continue; \ - } \ - if ( (!isquoted && (*cp == ' ' || *cp == '\t')) \ - || (isquoted && *cp == '"') ) { \ - break; \ - } \ - } - - cp = str; - SKIP_WHITESPACE(cp); - - /* determine first argument */ - CHECK_QUOTATION(cp, isquoted); - *a1 = cp; - DETERMINE_NEXTSTRING(cp, isquoted); - if (*cp == '\0') { - return 1; - } - *cp++ = '\0'; - - SKIP_WHITESPACE(cp); - - /* determine second argument */ - CHECK_QUOTATION(cp, isquoted); - *a2 = cp; - DETERMINE_NEXTSTRING(cp, isquoted); - if (*cp == '\0') { - *cp++ = '\0'; - *a3 = NULL; - return 0; - } - *cp++ = '\0'; - - SKIP_WHITESPACE(cp); - - /* again check if there are only two arguments */ - if (*cp == '\0') { - *cp++ = '\0'; - *a3 = NULL; - return 0; - } - - /* determine second argument */ - CHECK_QUOTATION(cp, isquoted); - *a3 = cp; - DETERMINE_NEXTSTRING(cp, isquoted); - *cp++ = '\0'; - - return 0; -} - - -static void add_env_variable(request_rec *r, char *s) -{ - char var[MAX_STRING_LEN]; - char val[MAX_STRING_LEN]; - char *cp; - int n; - - if ((cp = strchr(s, ':')) != NULL) { - n = ((cp-s) > MAX_STRING_LEN-1 ? MAX_STRING_LEN-1 : (cp-s)); - memcpy(var, s, n); - var[n] = '\0'; - apr_cpystrn(val, cp+1, sizeof(val)); - apr_table_set(r->subprocess_env, var, val); - rewritelog(r, 5, "setting env variable '%s' to '%s'", var, val); - } -} - - -/* -** -** check that a subrequest won't cause infinite recursion -** -*/ - -static int subreq_ok(request_rec *r) -{ - /* - * either not in a subrequest, or in a subrequest - * and URIs aren't NULL and sub/main URIs differ - */ - return (r->main == NULL || - (r->main->uri != NULL && r->uri != NULL && - strcmp(r->main->uri, r->uri) != 0)); -} - - -/* -** -** stat() for only the prefix of a path -** -*/ - -static int prefix_stat(const char *path, apr_finfo_t *sb) -{ - char curpath[LONG_STRING_LEN]; - char *cp; - - apr_cpystrn(curpath, path, sizeof(curpath)); - if (curpath[0] != '/') { - return 0; - } - if ((cp = strchr(curpath+1, '/')) != NULL) { - *cp = '\0'; - } - if (apr_stat(sb, curpath, APR_FINFO_MIN, NULL) == APR_SUCCESS) { - return 1; - } - else { - return 0; - } -} - - -/* -** -** Lexicographic Compare -** -*/ - -static int compare_lexicography(char *cpNum1, char *cpNum2) -{ - int i; - int n1, n2; - - n1 = strlen(cpNum1); - n2 = strlen(cpNum2); - if (n1 > n2) { - return 1; - } - if (n1 < n2) { - return -1; - } - for (i = 0; i < n1; i++) { - if (cpNum1[i] > cpNum2[i]) { - return 1; - } - if (cpNum1[i] < cpNum2[i]) { - return -1; - } - } - return 0; -} - -/* -** -** Bracketed expression handling -** s points after the opening bracket -** -*/ - -static char *find_closing_bracket(char *s, int left, int right) -{ - int depth; - - for (depth = 1; *s; ++s) { - if (*s == right && --depth == 0) { - return s; - } - else if (*s == left) { - ++depth; - } - } - return NULL; -} - -static char *find_char_in_brackets(char *s, int c, int left, int right) -{ - int depth; - - for (depth = 1; *s; ++s) { - if (*s == c && depth == 1) { - return s; - } - else if (*s == right && --depth == 0) { - return NULL; - } - else if (*s == left) { - ++depth; - } - } - return NULL; -} - -/* -** -** Module paraphernalia -** -*/ - -#ifdef NETWARE -int main(int argc, char *argv[]) -{ - ExitThread(TSR_THREAD, 0); -} -#endif - - /* the apr_table_t of commands we provide */ -static const command_rec command_table[] = { - AP_INIT_FLAG( "RewriteEngine", cmd_rewriteengine, NULL, OR_FILEINFO, - "On or Off to enable or disable (default) the whole " - "rewriting engine"), - AP_INIT_ITERATE( "RewriteOptions", cmd_rewriteoptions, NULL, OR_FILEINFO, - "List of option strings to set"), - AP_INIT_TAKE1( "RewriteBase", cmd_rewritebase, NULL, OR_FILEINFO, - "the base URL of the per-directory context"), - AP_INIT_RAW_ARGS("RewriteCond", cmd_rewritecond, NULL, OR_FILEINFO, - "an input string and a to be applied regexp-pattern"), - AP_INIT_RAW_ARGS("RewriteRule", cmd_rewriterule, NULL, OR_FILEINFO, - "an URL-applied regexp-pattern and a substitution URL"), - AP_INIT_TAKE2( "RewriteMap", cmd_rewritemap, NULL, RSRC_CONF, - "a mapname and a filename"), - AP_INIT_TAKE1( "RewriteLock", cmd_rewritelock, NULL, RSRC_CONF, - "the filename of a lockfile used for inter-process " - "synchronization"), - AP_INIT_TAKE1( "RewriteLog", cmd_rewritelog, NULL, RSRC_CONF, - "the filename of the rewriting logfile"), - AP_INIT_TAKE1( "RewriteLogLevel", cmd_rewriteloglevel, NULL, RSRC_CONF, - "the level of the rewriting logfile verbosity " - "(0=none, 1=std, .., 9=max)"), - { NULL } -}; - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_handler(handler_redirect, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_config(init_module,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_child_init(init_child,NULL,NULL,APR_HOOK_MIDDLE); - - ap_hook_fixups(hook_fixup,NULL,NULL,APR_HOOK_FIRST); - ap_hook_translate_name(hook_uri2file,NULL,NULL,APR_HOOK_FIRST); - ap_hook_type_checker(hook_mimetype,NULL,NULL,APR_HOOK_MIDDLE); -} - - /* the main config structure */ -module AP_MODULE_DECLARE_DATA rewrite_module = { - STANDARD20_MODULE_STUFF, - config_perdir_create, /* create per-dir config structures */ - config_perdir_merge, /* merge per-dir config structures */ - config_server_create, /* create per-server config structures */ - config_server_merge, /* merge per-server config structures */ - command_table, /* apr_table_t of config file commands */ - register_hooks /* register hooks */ -}; - -/*EOF*/ diff --git a/modules/mappers/mod_rewrite.dsp b/modules/mappers/mod_rewrite.dsp deleted file mode 100644 index b88f0b0fce..0000000000 --- a/modules/mappers/mod_rewrite.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_rewrite" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_rewrite - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_rewrite.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_rewrite.mak" CFG="mod_rewrite - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_rewrite - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_rewrite - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_rewrite - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "NO_DBM_REWRITEMAP" /Fd"Release\mod_rewrite" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_rewrite.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_rewrite -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_rewrite.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_rewrite - -!ELSEIF "$(CFG)" == "mod_rewrite - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "NO_DBM_REWRITEMAP" /Fd"Debug\mod_rewrite" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_rewrite.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_rewrite -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_rewrite.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_rewrite - -!ENDIF - -# Begin Target - -# Name "mod_rewrite - Win32 Release" -# Name "mod_rewrite - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_rewrite.c -# End Source File -# End Target -# End Project diff --git a/modules/mappers/mod_rewrite.exp b/modules/mappers/mod_rewrite.exp deleted file mode 100644 index 8f2165bfe0..0000000000 --- a/modules/mappers/mod_rewrite.exp +++ /dev/null @@ -1 +0,0 @@ -rewrite_module diff --git a/modules/mappers/mod_rewrite.h b/modules/mappers/mod_rewrite.h deleted file mode 100644 index f139877978..0000000000 --- a/modules/mappers/mod_rewrite.h +++ /dev/null @@ -1,473 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef MOD_REWRITE_H -#define MOD_REWRITE_H 1 - -/* -** _ _ _ -** _ __ ___ ___ __| | _ __ _____ ___ __(_) |_ ___ -** | '_ ` _ \ / _ \ / _` | | '__/ _ \ \ /\ / / '__| | __/ _ \ -** | | | | | | (_) | (_| | | | | __/\ V V /| | | | || __/ -** |_| |_| |_|\___/ \__,_|___|_| \___| \_/\_/ |_| |_|\__\___| -** |_____| -** -** URL Rewriting Module -** -** This module uses a rule-based rewriting engine (based on a -** regular-expression parser) to rewrite requested URLs on the fly. -** -** It supports an unlimited number of additional rule conditions (which can -** operate on a lot of variables, even on HTTP headers) for granular -** matching and even external database lookups (either via plain text -** tables, DBM hash files or even external processes) for advanced URL -** substitution. -** -** It operates on the full URLs (including the PATH_INFO part) both in -** per-server context (httpd.conf) and per-dir context (.htaccess) and even -** can generate QUERY_STRING parts on result. The rewriting result finally -** can lead to internal subprocessing, external request redirection or even -** to internal proxy throughput. -** -** This module was originally written in April 1996 and -** gifted exclusively to the The Apache Software Foundation in July 1997 by -** -** Ralf S. Engelschall -** rse@engelschall.com -** www.engelschall.com -*/ - -#include "apr.h" - -#define APR_WANT_STRFUNC -#define APR_WANT_MEMFUNC -#include "apr_want.h" - - /* Include from the underlaying Unix system ... */ -#if APR_HAVE_STDARG_H -#include <stdarg.h> -#endif -#if APR_HAVE_STDLIB_H -#include <stdlib.h> -#endif -#if APR_HAVE_CTYPE_H -#include <ctype.h> -#endif -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#include "ap_config.h" - - /* Include from the Apache server ... */ -#define CORE_PRIVATE -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_log.h" -#include "http_vhost.h" - - /* - * The key in the r->notes apr_table_t wherein we store our accumulated - * Vary values, and the one used for per-condition checks in a chain. - */ -#define VARY_KEY "rewrite-Vary" -#define VARY_KEY_THIS "rewrite-Vary-this" - - /* The NDBM support: - * We support only NDBM files. - * But we have to stat the file for the mtime, - * so we also need to know the file extension - */ -#ifndef NO_DBM_REWRITEMAP -#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) \ - && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 -#include <db1/ndbm.h> -#else -#include <ndbm.h> -#endif -#if defined(DBM_SUFFIX) -#define NDBM_FILE_SUFFIX DBM_SUFFIX -#elif defined(__FreeBSD__) || (defined(DB_LOCK) && defined(DB_SHMEM)) -#define NDBM_FILE_SUFFIX ".db" -#else -#define NDBM_FILE_SUFFIX ".pag" -#endif -#endif - - -/* -** -** Some defines -** -*/ - -#define ENVVAR_SCRIPT_URL "SCRIPT_URL" -#define ENVVAR_SCRIPT_URI "SCRIPT_URI" - -#ifndef SUPPORT_DBM_REWRITEMAP -#define SUPPORT_DBM_REWRITEMAP 0 -#endif - -#define REWRITE_FORCED_MIMETYPE_NOTEVAR "rewrite-forced-mimetype" - -#define CONDFLAG_NONE 1<<0 -#define CONDFLAG_NOCASE 1<<1 -#define CONDFLAG_NOTMATCH 1<<2 -#define CONDFLAG_ORNEXT 1<<3 - -#define RULEFLAG_NONE 1<<0 -#define RULEFLAG_FORCEREDIRECT 1<<1 -#define RULEFLAG_LASTRULE 1<<2 -#define RULEFLAG_NEWROUND 1<<3 -#define RULEFLAG_CHAIN 1<<4 -#define RULEFLAG_IGNOREONSUBREQ 1<<5 -#define RULEFLAG_NOTMATCH 1<<6 -#define RULEFLAG_PROXY 1<<7 -#define RULEFLAG_PASSTHROUGH 1<<8 -#define RULEFLAG_FORBIDDEN 1<<9 -#define RULEFLAG_GONE 1<<10 -#define RULEFLAG_QSAPPEND 1<<11 -#define RULEFLAG_NOCASE 1<<12 - -#define MAPTYPE_TXT 1<<0 -#define MAPTYPE_DBM 1<<1 -#define MAPTYPE_PRG 1<<2 -#define MAPTYPE_INT 1<<3 -#define MAPTYPE_RND 1<<4 - -#define ENGINE_DISABLED 1<<0 -#define ENGINE_ENABLED 1<<1 - -#define OPTION_NONE 1<<0 -#define OPTION_INHERIT 1<<1 - -#define CACHEMODE_TS 1<<0 -#define CACHEMODE_TTL 1<<1 - -#define CACHE_TLB_ROWS 1024 -#define CACHE_TLB_COLS 4 - -#ifndef FALSE -#define FALSE 0 -#define TRUE !FALSE -#endif - -#ifndef NO -#define NO FALSE -#define YES TRUE -#endif - -#ifndef RAND_MAX -#define RAND_MAX 32767 -#endif - -#ifndef LONG_STRING_LEN -#define LONG_STRING_LEN 2048 -#endif - -#define MAX_ENV_FLAGS 15 - -#define MAX_NMATCH 10 - -/* -** -** our private data structures we handle with -** -*/ - - /* the list structures for holding the mapfile information - * and the rewrite rules - */ -typedef struct { - const char *name; /* the name of the map */ - const char *datafile; /* filename for map data files */ - const char *checkfile; /* filename to check for map existence */ - int type; /* the type of the map */ - apr_file_t *fpin; /* in file pointer for program maps */ - apr_file_t *fpout; /* out file pointer for program maps */ - apr_file_t *fperr; /* err file pointer for program maps */ - char *(*func)(request_rec *, /* function pointer for internal maps */ - char *); -} rewritemap_entry; - -typedef struct { - char *input; /* Input string of RewriteCond */ - char *pattern; /* the RegExp pattern string */ - regex_t *regexp; - int flags; /* Flags which control the match */ -} rewritecond_entry; - -typedef struct { - apr_array_header_t *rewriteconds; /* the corresponding RewriteCond entries */ - char *pattern; /* the RegExp pattern string */ - regex_t *regexp; /* the RegExp pattern compilation */ - char *output; /* the Substitution string */ - int flags; /* Flags which control the substitution */ - char *forced_mimetype; /* forced MIME type of substitution */ - int forced_responsecode; /* forced HTTP redirect response status */ - char *env[MAX_ENV_FLAGS+1]; /* added environment variables */ - int skip; /* number of next rules to skip */ -} rewriterule_entry; - - - /* the per-server or per-virtual-server configuration - * statically generated once on startup for every server - */ -typedef struct { - int state; /* the RewriteEngine state */ - int options; /* the RewriteOption state */ - const char *rewritelogfile; /* the RewriteLog filename */ - apr_file_t *rewritelogfp; /* the RewriteLog open filepointer */ - int rewriteloglevel; /* the RewriteLog level of verbosity */ - apr_array_header_t *rewritemaps; /* the RewriteMap entries */ - apr_array_header_t *rewriteconds; /* the RewriteCond entries (temporary) */ - apr_array_header_t *rewriterules; /* the RewriteRule entries */ - server_rec *server; /* the corresponding server indicator */ -} rewrite_server_conf; - - - /* the per-directory configuration - * generated on-the-fly by Apache server for current request - */ -typedef struct { - int state; /* the RewriteEngine state */ - int options; /* the RewriteOption state */ - apr_array_header_t *rewriteconds; /* the RewriteCond entries (temporary) */ - apr_array_header_t *rewriterules; /* the RewriteRule entries */ - char *directory; /* the directory where it applies */ - const char *baseurl; /* the base-URL where it applies */ -} rewrite_perdir_conf; - - - /* the cache structures, - * a 4-way hash apr_table_t with LRU functionality - */ -typedef struct cacheentry { - apr_time_t time; - char *key; - char *value; -} cacheentry; - -typedef struct tlbentry { - int t[CACHE_TLB_COLS]; -} cachetlbentry; - -typedef struct cachelist { - char *resource; - apr_array_header_t *entries; - apr_array_header_t *tlb; -} cachelist; - -typedef struct cache { - apr_pool_t *pool; - apr_array_header_t *lists; -} cache; - - - /* the regex structure for the - * substitution of backreferences - */ -typedef struct backrefinfo { - char *source; - int nsub; - regmatch_t regmatch[10]; -} backrefinfo; - - -/* -** -** forward declarations -** -*/ - - /* config structure handling */ -static void *config_server_create(apr_pool_t *p, server_rec *s); -static void *config_server_merge (apr_pool_t *p, void *basev, void *overridesv); -static void *config_perdir_create(apr_pool_t *p, char *path); -static void *config_perdir_merge (apr_pool_t *p, void *basev, void *overridesv); - - /* config directive handling */ -static const char *cmd_rewriteengine(cmd_parms *cmd, - void *dconf, int flag); -static const char *cmd_rewriteoptions(cmd_parms *cmd, - void *dconf, - const char *option); -static const char *cmd_rewriteoptions_setoption(apr_pool_t *p, int *options, - const char *name); -static const char *cmd_rewritelog (cmd_parms *cmd, void *dconf, const char *a1); -static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, const char *a1); -static const char *cmd_rewritemap (cmd_parms *cmd, void *dconf, - const char *a1, const char *a2); -static const char *cmd_rewritelock(cmd_parms *cmd, void *dconf, const char *a1); -static const char *cmd_rewritebase(cmd_parms *cmd, void *dconf, - const char *a1); -static const char *cmd_rewritecond(cmd_parms *cmd, void *dconf, - const char *str); -static const char *cmd_rewritecond_parseflagfield(apr_pool_t *p, - rewritecond_entry *new, - char *str); -static const char *cmd_rewritecond_setflag(apr_pool_t *p, rewritecond_entry *cfg, - char *key, char *val); -static const char *cmd_rewriterule(cmd_parms *cmd, void *dconf, - const char *str); -static const char *cmd_rewriterule_parseflagfield(apr_pool_t *p, - rewriterule_entry *new, - char *str); -static const char *cmd_rewriterule_setflag(apr_pool_t *p, rewriterule_entry *cfg, - char *key, char *val); - - /* initialisation */ -static void init_module(apr_pool_t *p, - apr_pool_t *plog, - apr_pool_t *ptemp, - server_rec *s); -static void init_child(apr_pool_t *p, server_rec *s); - - /* runtime hooks */ -static int hook_uri2file (request_rec *r); -static int hook_mimetype (request_rec *r); -static int hook_fixup (request_rec *r); -static int handler_redirect(request_rec *r); - - /* rewriting engine */ -static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules, - char *perdir); -static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p, - char *perdir); -static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p, - char *perdir, backrefinfo *briRR, - backrefinfo *briRC); - -static void do_expand(request_rec *r, char *input, char *buffer, int nbuf, - backrefinfo *briRR, backrefinfo *briRC); -static void do_expand_env(request_rec *r, char *env[], - backrefinfo *briRR, backrefinfo *briRC); - - /* URI transformation function */ -static void splitout_queryargs(request_rec *r, int qsappend); -static void fully_qualify_uri(request_rec *r); -static void reduce_uri(request_rec *r); -static int is_absolute_uri(char *uri); -static char *expand_tildepaths(request_rec *r, char *uri); - - /* rewrite map support functions */ -static char *lookup_map(request_rec *r, char *name, char *key); -static char *lookup_map_txtfile(request_rec *r, const char *file, char *key); -#ifndef NO_DBM_REWRITEMAP -static char *lookup_map_dbmfile(request_rec *r, const char *file, char *key); -#endif -static char *lookup_map_program(request_rec *r, apr_file_t *fpin, - apr_file_t *fpout, char *key); -static char *lookup_map_internal(request_rec *r, - char *(*func)(request_rec *r, char *key), - char *key); -static char *rewrite_mapfunc_toupper(request_rec *r, char *key); -static char *rewrite_mapfunc_tolower(request_rec *r, char *key); -static char *rewrite_mapfunc_escape(request_rec *r, char *key); -static char *rewrite_mapfunc_unescape(request_rec *r, char *key); -static char *select_random_value_part(request_rec *r, char *value); -static void rewrite_rand_init(void); -static int rewrite_rand(int l, int h); - - /* rewriting logfile support */ -static void open_rewritelog(server_rec *s, apr_pool_t *p); -static void rewritelog(request_rec *r, int level, const char *text, ...) - __attribute__((format(printf,3,4))); -static char *current_logtime(request_rec *r); - - /* rewriting lockfile support */ -static void rewritelock_create(server_rec *s, apr_pool_t *p); -static apr_status_t rewritelock_remove(void *data); - - /* program map support */ -static void run_rewritemap_programs(server_rec *s, apr_pool_t *p); -static apr_status_t rewritemap_program_child(apr_pool_t *p, const char *progname, - apr_file_t **fpout, apr_file_t **fpin, - apr_file_t **fperr); - - /* env variable support */ -static char *lookup_variable(request_rec *r, char *var); -static char *lookup_header(request_rec *r, const char *name); - - /* caching functions */ -static cache *init_cache(apr_pool_t *p); -static char *get_cache_string(cache *c, const char *res, int mode, apr_time_t mtime, - char *key); -static void set_cache_string(cache *c, const char *res, int mode, apr_time_t mtime, - char *key, char *value); -static cacheentry *retrieve_cache_string(cache *c, const char *res, char *key); -static void store_cache_string(cache *c, const char *res, cacheentry *ce); - - /* misc functions */ -static char *subst_prefix_path(request_rec *r, char *input, char *match, - const char *subst); -static int parseargline(char *str, char **a1, char **a2, char **a3); -static int prefix_stat(const char *path, apr_finfo_t *sb); -static void add_env_variable(request_rec *r, char *s); -static int subreq_ok(request_rec *r); - - /* Lexicographic Comparison */ -static int compare_lexicography(char *cpNum1, char *cpNum2); - - /* Bracketed expression handling */ -static char *find_closing_bracket(char *s, int left, int right); -static char *find_char_in_brackets(char *s, int c, int left, int right); - -#endif /* MOD_REWRITE_H */ diff --git a/modules/mappers/mod_rewrite.mak b/modules/mappers/mod_rewrite.mak deleted file mode 100644 index 135063b48d..0000000000 --- a/modules/mappers/mod_rewrite.mak +++ /dev/null @@ -1,335 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_rewrite.dsp -!IF "$(CFG)" == "" -CFG=mod_rewrite - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_rewrite - Win32 Release. -!ENDIF - -!IF "$(CFG)" != "mod_rewrite - Win32 Release" && "$(CFG)" !=\ - "mod_rewrite - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_rewrite.mak" CFG="mod_rewrite - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_rewrite - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_rewrite - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_rewrite - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_rewrite.so" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libapr - Win32 Release"\ - "$(OUTDIR)\mod_rewrite.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_rewrite.idb" - -@erase "$(INTDIR)\mod_rewrite.obj" - -@erase "$(OUTDIR)\mod_rewrite.exp" - -@erase "$(OUTDIR)\mod_rewrite.lib" - -@erase "$(OUTDIR)\mod_rewrite.map" - -@erase "$(OUTDIR)\mod_rewrite.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D\ - "WIN32" /D "_WINDOWS" /D "NO_DBM_REWRITEMAP" /Fo"$(INTDIR)\\"\ - /Fd"$(INTDIR)\mod_rewrite" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_rewrite.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_rewrite.pdb" /map:"$(INTDIR)\mod_rewrite.map" /machine:I386\ - /out:"$(OUTDIR)\mod_rewrite.so" /implib:"$(OUTDIR)\mod_rewrite.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_rewrite -LINK32_OBJS= \ - "$(INTDIR)\mod_rewrite.obj" \ - "..\..\Release\libhttpd.lib" \ - "..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_rewrite.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_rewrite - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_rewrite.so" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libapr - Win32 Debug"\ - "$(OUTDIR)\mod_rewrite.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_rewrite.idb" - -@erase "$(INTDIR)\mod_rewrite.obj" - -@erase "$(OUTDIR)\mod_rewrite.exp" - -@erase "$(OUTDIR)\mod_rewrite.lib" - -@erase "$(OUTDIR)\mod_rewrite.map" - -@erase "$(OUTDIR)\mod_rewrite.pdb" - -@erase "$(OUTDIR)\mod_rewrite.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D\ - "WIN32" /D "_WINDOWS" /D "NO_DBM_REWRITEMAP" /Fo"$(INTDIR)\\"\ - /Fd"$(INTDIR)\mod_rewrite" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_rewrite.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_rewrite.pdb" /map:"$(INTDIR)\mod_rewrite.map" /debug\ - /machine:I386 /out:"$(OUTDIR)\mod_rewrite.so"\ - /implib:"$(OUTDIR)\mod_rewrite.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_rewrite -LINK32_OBJS= \ - "$(INTDIR)\mod_rewrite.obj" \ - "..\..\Debug\libhttpd.lib" \ - "..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_rewrite.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_rewrite - Win32 Release" || "$(CFG)" ==\ - "mod_rewrite - Win32 Debug" - -!IF "$(CFG)" == "mod_rewrite - Win32 Release" - -"libapr - Win32 Release" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Release" - cd "..\..\modules\mappers" - -"libapr - Win32 ReleaseCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\mappers" - -!ELSEIF "$(CFG)" == "mod_rewrite - Win32 Debug" - -"libapr - Win32 Debug" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Debug" - cd "..\..\modules\mappers" - -"libapr - Win32 DebugCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\mappers" - -!ENDIF - -!IF "$(CFG)" == "mod_rewrite - Win32 Release" - -"libhttpd - Win32 Release" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Release" - cd ".\modules\mappers" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Release"\ - RECURSE=1 - cd ".\modules\mappers" - -!ELSEIF "$(CFG)" == "mod_rewrite - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Debug" - cd ".\modules\mappers" - -"libhttpd - Win32 DebugCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\mappers" - -!ENDIF - -SOURCE=.\mod_rewrite.c -DEP_CPP_MOD_R=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\http_request.h"\ - "..\..\include\http_vhost.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\srclib\apr-util\include\apu.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_dso.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_lock.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_signal.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\include\apr_user.h"\ - "..\..\srclib\apr\include\apr_want.h"\ - ".\mod_rewrite.h"\ - -NODEP_CPP_MOD_R=\ - "..\..\include\ap_config_auto.h"\ - ".\unixd.h"\ - - -"$(INTDIR)\mod_rewrite.obj" : $(SOURCE) $(DEP_CPP_MOD_R) "$(INTDIR)" - - - -!ENDIF - diff --git a/modules/mappers/mod_so.c b/modules/mappers/mod_so.c deleted file mode 100644 index ba9466f622..0000000000 --- a/modules/mappers/mod_so.c +++ /dev/null @@ -1,353 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * This module is used to load Apache modules at runtime. This means that the - * server functionality can be extended without recompiling and even without - * taking the server down at all. Only a HUP or WINCH signal needs to be send - * to the server to reload the dynamically loaded modules. - * - * To use, you'll first need to build your module as a shared library, then - * update your configuration (httpd.conf) to get the Apache core to load the - * module at start-up. - * - * The easiest way to build a module as a shared library is to use the - * `SharedModule' command in the Configuration file, instead of `AddModule'. - * You should also change the file extension from `.o' to `.so'. So, for - * example, to build the status module as a shared library edit Configuration - * and change - * AddModule modules/standard/mod_status.o - * to - * SharedModule modules/standard/mod_status.so - * - * Run Configure and make. Now Apache's httpd binary will _not_ include - * mod_status. Instead a shared object called mod_status.so will be build, in - * the modules/standard directory. You can build most of the modules as shared - * libraries like this. - * - * To use the shared module, move the .so file(s) into an appropriate - * directory. You might like to create a directory called "modules" under you - * server root for this (e.g. /usr/local/httpd/modules). - * - * Then edit your conf/httpd.conf file, and add LoadModule lines. For - * example - * LoadModule status_module modules/mod_status.so - * - * The first argument is the module's structure name (look at the end of the - * module source to find this). The second option is the path to the module - * file, relative to the server root. Put these directives right at the top - * of your httpd.conf file. - * - * Now you can start Apache. A message will be logged at "debug" level to your - * error_log to confirm that the module(s) are loaded (use "LogLevel debug" - * directive to get these log messages). - * - * If you edit the LoadModule directives while the server is live you can get - * Apache to re-load the modules by sending it a HUP or WINCH signal as normal. - * You can use this to dynamically change the capability of your server - * without bringing it down. - * - * Because currently there is only limited builtin support in the Configure - * script for creating the shared library files (`.so'), please consult your - * vendors cc(1), ld(1) and dlopen(3) manpages to find out the appropriate - * compiler and linker flags and insert them manually into the Configuration - * file under CFLAGS_SHLIB, LDFLAGS_SHLIB and LDFLAGS_SHLIB_EXPORT. - * - * If you still have problems figuring out the flags both try the paper - * http://developer.netscape.com/library/documentation/enterprise - * /unix/svrplug.htm#1013807 - * or install a Perl 5 interpreter on your platform and then run the command - * - * $ perl -V:usedl -V:ccdlflags -V:cccdlflags -V:lddlflags - * - * This gives you what type of dynamic loading Perl 5 uses on your platform - * and which compiler and linker flags Perl 5 uses to create the shared object - * files. - * - * Another location where you can find useful hints is the `ltconfig' script - * of the GNU libtool 1.2 package. Search for your platform name inside the - * various "case" constructs. - * - */ - -#include "apr.h" -#include "apr_dso.h" -#include "apr_strings.h" -#include "apr_errno.h" - -#define CORE_PRIVATE -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "ap_config.h" - -module AP_MODULE_DECLARE_DATA so_module; - - -/* - * Server configuration to keep track of actually - * loaded modules and the corresponding module name. - */ - -typedef struct moduleinfo { - const char *name; - module *modp; -} moduleinfo; - -typedef struct so_server_conf { - apr_array_header_t *loaded_modules; -} so_server_conf; - -static void *so_sconf_create(apr_pool_t *p, server_rec *s) -{ - so_server_conf *soc; - - soc = (so_server_conf *)apr_pcalloc(p, sizeof(so_server_conf)); - soc->loaded_modules = apr_array_make(p, DYNAMIC_MODULE_LIMIT, - sizeof(moduleinfo)); - - return (void *)soc; -} - -#ifndef NO_DLOPEN - -/* - * This is the cleanup for a loaded shared object. It unloads the module. - * This is called as a cleanup function from the core. - */ - -static apr_status_t unload_module(void *data) -{ - moduleinfo *modi = (moduleinfo*)data; - - /* only unload if module information is still existing */ - if (modi->modp == NULL) - return APR_SUCCESS; - - /* remove the module pointer from the core structure */ - ap_remove_loaded_module(modi->modp); - - /* destroy the module information */ - modi->modp = NULL; - modi->name = NULL; - return APR_SUCCESS; -} - -/* - * This is called for the directive LoadModule and actually loads - * a shared object file into the address space of the server process. - */ - -static const char *load_module(cmd_parms *cmd, void *dummy, - const char *modname, const char *filename) -{ - apr_dso_handle_t *modhandle; - apr_dso_handle_sym_t modsym; - module *modp; - const char *szModuleFile=ap_server_root_relative(cmd->pool, filename); - so_server_conf *sconf; - moduleinfo *modi; - moduleinfo *modie; - int i; - - /* we need to setup this value for dummy to make sure that we don't try - * to add a non-existant tree into the build when we return to - * execute_now. - */ - *(ap_directive_t **)dummy = NULL; - - /* - * check for already existing module - * If it already exists, we have nothing to do - */ - sconf = (so_server_conf *)ap_get_module_config(cmd->server->module_config, - &so_module); - modie = (moduleinfo *)sconf->loaded_modules->elts; - for (i = 0; i < sconf->loaded_modules->nelts; i++) { - modi = &modie[i]; - if (modi->name != NULL && strcmp(modi->name, modname) == 0) - return NULL; - } - modi = apr_array_push(sconf->loaded_modules); - modi->name = modname; - - /* - * Load the file into the Apache address space - */ - if (apr_dso_load(&modhandle, szModuleFile, cmd->pool) != APR_SUCCESS) { - char my_error[256]; - - return apr_pstrcat(cmd->pool, "Cannot load ", szModuleFile, - " into server: ", - apr_dso_error(modhandle, my_error, sizeof(my_error)), - NULL); - } - ap_log_perror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->pool, - "loaded module %s", modname); - - /* - * Retrieve the pointer to the module structure through the module name: - * First with the hidden variant (prefix `AP_') and then with the plain - * symbol name. - */ - if (apr_dso_sym(&modsym, modhandle, modname) != APR_SUCCESS) { - char my_error[256]; - - return apr_pstrcat(cmd->pool, "Can't locate API module structure `", - modname, "' in file ", szModuleFile, ": ", - apr_dso_error(modhandle, my_error, sizeof(my_error)), - NULL); - } - modp = (module*) modsym; - modp->dynamic_load_handle = (apr_dso_handle_t *)modhandle; - modi->modp = modp; - - /* - * Make sure the found module structure is really a module structure - * - */ - if (modp->magic != MODULE_MAGIC_COOKIE) { - return apr_pstrcat(cmd->pool, "API module structure `", modname, - "' in file ", szModuleFile, " is garbled -" - " perhaps this is not an Apache module DSO?", NULL); - } - - /* - * Add this module to the Apache core structures - */ - ap_add_loaded_module(modp, cmd->pool); - - /* - * Register a cleanup in the config apr_pool_t (normally pconf). When - * we do a restart (or shutdown) this cleanup will cause the - * shared object to be unloaded. - */ - apr_pool_cleanup_register(cmd->pool, modi, unload_module, apr_pool_cleanup_null); - - /* - * Finally we need to run the configuration process for the module - */ - ap_single_module_configure(cmd->pool, cmd->server, modp); - - return NULL; -} - -/* - * This implements the LoadFile directive and loads an arbitrary - * shared object file into the adress space of the server process. - */ - -static const char *load_file(cmd_parms *cmd, void *dummy, const char *filename) -{ - apr_dso_handle_t *handle; - const char *file; - - file = ap_server_root_relative(cmd->pool, filename); - - if (apr_dso_load(&handle, file, cmd->pool) != APR_SUCCESS) { - char my_error[256]; - - return apr_pstrcat(cmd->pool, "Cannot load ", filename, - " into server: ", - apr_dso_error(handle, my_error, sizeof(my_error)), - NULL); - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, - "loaded file %s", filename); - - return NULL; -} - -#else /* not NO_DLOPEN */ - -static const char *load_file(cmd_parms *cmd, void *dummy, const char *filename) -{ - ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, cmd->pool, - "WARNING: LoadFile not supported on this platform"); - return NULL; -} - -static const char *load_module(cmd_parms *cmd, void *dummy, - const char *modname, const char *filename) -{ - ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, cmd->pool, - "WARNING: LoadModule not supported on this platform"); - return NULL; -} - -#endif /* NO_DLOPEN */ - -static const command_rec so_cmds[] = { - AP_INIT_TAKE2("LoadModule", load_module, NULL, RSRC_CONF | EXEC_ON_READ, - "a module name and the name of a shared object file to load it from"), - AP_INIT_ITERATE("LoadFile", load_file, NULL, RSRC_CONF, - "shared object file or library to load into the server at runtime"), - { NULL } -}; - -module AP_MODULE_DECLARE_DATA so_module = { - STANDARD20_MODULE_STUFF, - NULL, /* create per-dir config */ - NULL, /* merge per-dir config */ - so_sconf_create, /* server config */ - NULL, /* merge server config */ - so_cmds, /* command apr_table_t */ - NULL /* register hooks */ -}; diff --git a/modules/mappers/mod_speling.c b/modules/mappers/mod_speling.c deleted file mode 100644 index d89a86923d..0000000000 --- a/modules/mappers/mod_speling.c +++ /dev/null @@ -1,569 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr.h" -#include "apr_file_io.h" -#include "apr_strings.h" -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#define WANT_BASENAME_MATCH - -#include "httpd.h" -#include "http_core.h" -#include "http_config.h" -#include "http_request.h" -#include "http_log.h" - -/* mod_speling.c - by Alexei Kosut <akosut@organic.com> June, 1996 - * - * This module is transparent, and simple. It attempts to correct - * misspellings of URLs that users might have entered, namely by checking - * capitalizations. If it finds a match, it sends a redirect. - * - * 08-Aug-1997 <Martin.Kraemer@Mch.SNI.De> - * o Upgraded module interface to apache_1.3a2-dev API (more NULL's in - * speling_module). - * o Integrated tcsh's "spelling correction" routine which allows one - * misspelling (character insertion/omission/typo/transposition). - * Rewrote it to ignore case as well. This ought to catch the majority - * of misspelled requests. - * o Commented out the second pass where files' suffixes are stripped. - * Given the better hit rate of the first pass, this rather ugly - * (request index.html, receive index.db ?!?!) solution can be - * omitted. - * o wrote a "kind of" html page for mod_speling - * - * Activate it with "CheckSpelling On" - */ - -AP_MODULE_DECLARE_DATA module speling_module; - -typedef struct { - int enabled; -} spconfig; - -/* - * Create a configuration specific to this module for a server or directory - * location, and fill it with the default settings. - * - * The API says that in the absence of a merge function, the record for the - * closest ancestor is used exclusively. That's what we want, so we don't - * bother to have such a function. - */ - -static void *mkconfig(apr_pool_t *p) -{ - spconfig *cfg = apr_pcalloc(p, sizeof(spconfig)); - - cfg->enabled = 0; - return cfg; -} - -/* - * Respond to a callback to create configuration record for a server or - * vhost environment. - */ -static void *create_mconfig_for_server(apr_pool_t *p, server_rec *s) -{ - return mkconfig(p); -} - -/* - * Respond to a callback to create a config record for a specific directory. - */ -static void *create_mconfig_for_directory(apr_pool_t *p, char *dir) -{ - return mkconfig(p); -} - -/* - * Handler for the CheckSpelling directive, which is FLAG. - */ -static const char *set_speling(cmd_parms *cmd, void *mconfig, int arg) -{ - spconfig *cfg = (spconfig *) mconfig; - - cfg->enabled = arg; - return NULL; -} - -/* - * Define the directives specific to this module. This structure is referenced - * later by the 'module' structure. - */ -static const command_rec speling_cmds[] = -{ - AP_INIT_FLAG("CheckSpelling", set_speling, NULL, OR_OPTIONS, - "whether or not to fix miscapitalized/misspelled requests"), - { NULL } -}; - -typedef enum { - SP_IDENTICAL = 0, - SP_MISCAPITALIZED = 1, - SP_TRANSPOSITION = 2, - SP_MISSINGCHAR = 3, - SP_EXTRACHAR = 4, - SP_SIMPLETYPO = 5, - SP_VERYDIFFERENT = 6 -} sp_reason; - -static const char *sp_reason_str[] = -{ - "identical", - "miscapitalized", - "transposed characters", - "character missing", - "extra character", - "mistyped character", - "common basename", -}; - -typedef struct { - const char *name; - sp_reason quality; -} misspelled_file; - -/* - * spdist() is taken from Kernighan & Pike, - * _The_UNIX_Programming_Environment_ - * and adapted somewhat to correspond better to psychological reality. - * (Note the changes to the return values) - * - * According to Pollock and Zamora, CACM April 1984 (V. 27, No. 4), - * page 363, the correct order for this is: - * OMISSION = TRANSPOSITION > INSERTION > SUBSTITUTION - * thus, it was exactly backwards in the old version. -- PWP - * - * This routine was taken out of tcsh's spelling correction code - * (tcsh-6.07.04) and re-converted to apache data types ("char" type - * instead of tcsh's NLS'ed "Char"). Plus it now ignores the case - * during comparisons, so is a "approximate strcasecmp()". - * NOTE that is still allows only _one_ real "typo", - * it does NOT try to correct multiple errors. - */ - -static sp_reason spdist(const char *s, const char *t) -{ - for (; apr_tolower(*s) == apr_tolower(*t); t++, s++) { - if (*t == '\0') { - return SP_MISCAPITALIZED; /* exact match (sans case) */ - } - } - if (*s) { - if (*t) { - if (s[1] && t[1] && apr_tolower(*s) == apr_tolower(t[1]) - && apr_tolower(*t) == apr_tolower(s[1]) - && strcasecmp(s + 2, t + 2) == 0) { - return SP_TRANSPOSITION; /* transposition */ - } - if (strcasecmp(s + 1, t + 1) == 0) { - return SP_SIMPLETYPO; /* 1 char mismatch */ - } - } - if (strcasecmp(s + 1, t) == 0) { - return SP_EXTRACHAR; /* extra character */ - } - } - if (*t && strcasecmp(s, t + 1) == 0) { - return SP_MISSINGCHAR; /* missing character */ - } - return SP_VERYDIFFERENT; /* distance too large to fix. */ -} - -static int sort_by_quality(const void *left, const void *rite) -{ - return (int) (((misspelled_file *) left)->quality) - - (int) (((misspelled_file *) rite)->quality); -} - -static int check_speling(request_rec *r) -{ - spconfig *cfg; - char *good, *bad, *postgood, *url; - apr_finfo_t dirent; - int filoc, dotloc, urlen, pglen; - apr_array_header_t *candidates = NULL; - apr_dir_t *dir; - - cfg = ap_get_module_config(r->per_dir_config, &speling_module); - if (!cfg->enabled) { - return DECLINED; - } - - /* We only want to worry about GETs */ - if (r->method_number != M_GET) { - return DECLINED; - } - - /* We've already got a file of some kind or another */ - if (r->proxyreq || (r->finfo.filetype != 0)) { - return DECLINED; - } - - /* This is a sub request - don't mess with it */ - if (r->main) { - return DECLINED; - } - - /* - * The request should end up looking like this: - * r->uri: /correct-url/mispelling/more - * r->filename: /correct-file/mispelling r->path_info: /more - * - * So we do this in steps. First break r->filename into two pieces - */ - - filoc = ap_rind(r->filename, '/'); - /* - * Don't do anything if the request doesn't contain a slash, or - * requests "/" - */ - if (filoc == -1 || strcmp(r->uri, "/") == 0) { - return DECLINED; - } - - /* good = /correct-file */ - good = apr_pstrndup(r->pool, r->filename, filoc); - /* bad = mispelling */ - bad = apr_pstrdup(r->pool, r->filename + filoc + 1); - /* postgood = mispelling/more */ - postgood = apr_pstrcat(r->pool, bad, r->path_info, NULL); - - urlen = strlen(r->uri); - pglen = strlen(postgood); - - /* Check to see if the URL pieces add up */ - if (strcmp(postgood, r->uri + (urlen - pglen))) { - return DECLINED; - } - - /* url = /correct-url */ - url = apr_pstrndup(r->pool, r->uri, (urlen - pglen)); - - /* Now open the directory and do ourselves a check... */ - if (apr_dir_open(&dir, good, r->pool) != APR_SUCCESS) { - /* Oops, not a directory... */ - return DECLINED; - } - - candidates = apr_array_make(r->pool, 2, sizeof(misspelled_file)); - - dotloc = ap_ind(bad, '.'); - if (dotloc == -1) { - dotloc = strlen(bad); - } - - while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dir) == APR_SUCCESS) { - sp_reason q; - - /* - * If we end up with a "fixed" URL which is identical to the - * requested one, we must have found a broken symlink or some such. - * Do _not_ try to redirect this, it causes a loop! - */ - if (strcmp(bad, dirent.name) == 0) { - apr_dir_close(dir); - return OK; - } - - /* - * miscapitalization errors are checked first (like, e.g., lower case - * file, upper case request) - */ - else if (strcasecmp(bad, dirent.name) == 0) { - misspelled_file *sp_new; - - sp_new = (misspelled_file *) apr_array_push(candidates); - sp_new->name = apr_pstrdup(r->pool, dirent.name); - sp_new->quality = SP_MISCAPITALIZED; - } - - /* - * simple typing errors are checked next (like, e.g., - * missing/extra/transposed char) - */ - else if ((q = spdist(bad, dirent.name)) != SP_VERYDIFFERENT) { - misspelled_file *sp_new; - - sp_new = (misspelled_file *) apr_array_push(candidates); - sp_new->name = apr_pstrdup(r->pool, dirent.name); - sp_new->quality = q; - } - - /* - * The spdist() should have found the majority of the misspelled - * requests. It is of questionable use to continue looking for - * files with the same base name, but potentially of totally wrong - * type (index.html <-> index.db). - * I would propose to not set the WANT_BASENAME_MATCH define. - * 08-Aug-1997 <Martin.Kraemer@Mch.SNI.De> - * - * However, Alexei replied giving some reasons to add it anyway: - * > Oh, by the way, I remembered why having the - * > extension-stripping-and-matching stuff is a good idea: - * > - * > If you're using MultiViews, and have a file named foobar.html, - * > which you refer to as "foobar", and someone tried to access - * > "Foobar", mod_speling won't find it, because it won't find - * > anything matching that spelling. With the extension-munging, - * > it would locate "foobar.html". Not perfect, but I ran into - * > that problem when I first wrote the module. - */ - else { -#ifdef WANT_BASENAME_MATCH - /* - * Okay... we didn't find anything. Now we take out the hard-core - * power tools. There are several cases here. Someone might have - * entered a wrong extension (.htm instead of .html or vice - * versa) or the document could be negotiated. At any rate, now - * we just compare stuff before the first dot. If it matches, we - * figure we got us a match. This can result in wrong things if - * there are files of different content types but the same prefix - * (e.g. foo.gif and foo.html) This code will pick the first one - * it finds. Better than a Not Found, though. - */ - int entloc = ap_ind(dirent.name, '.'); - if (entloc == -1) { - entloc = strlen(dirent.name); - } - - if ((dotloc == entloc) - && !strncasecmp(bad, dirent.name, dotloc)) { - misspelled_file *sp_new; - - sp_new = (misspelled_file *) apr_array_push(candidates); - sp_new->name = apr_pstrdup(r->pool, dirent.name); - sp_new->quality = SP_VERYDIFFERENT; - } -#endif - } - } - apr_dir_close(dir); - - if (candidates->nelts != 0) { - /* Wow... we found us a mispelling. Construct a fixed url */ - char *nuri; - const char *ref; - misspelled_file *variant = (misspelled_file *) candidates->elts; - int i; - - ref = apr_table_get(r->headers_in, "Referer"); - - qsort((void *) candidates->elts, candidates->nelts, - sizeof(misspelled_file), sort_by_quality); - - /* - * Conditions for immediate redirection: - * a) the first candidate was not found by stripping the suffix - * AND b) there exists only one candidate OR the best match is not - * ambiguous - * then return a redirection right away. - */ - if (variant[0].quality != SP_VERYDIFFERENT - && (candidates->nelts == 1 - || variant[0].quality != variant[1].quality)) { - - nuri = ap_escape_uri(r->pool, apr_pstrcat(r->pool, url, - variant[0].name, - r->path_info, NULL)); - if (r->parsed_uri.query) - nuri = apr_pstrcat(r->pool, nuri, "?", r->parsed_uri.query, NULL); - - apr_table_setn(r->headers_out, "Location", - ap_construct_url(r->pool, nuri, r)); - - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_INFO, APR_SUCCESS, - r, - ref ? "Fixed spelling: %s to %s from %s" - : "Fixed spelling: %s to %s", - r->uri, nuri, ref); - - return HTTP_MOVED_PERMANENTLY; - } - /* - * Otherwise, a "[300] Multiple Choices" list with the variants is - * returned. - */ - else { - apr_pool_t *p; - apr_table_t *notes; - apr_pool_t *sub_pool; - apr_array_header_t *t; - apr_array_header_t *v; - - - if (r->main == NULL) { - p = r->pool; - notes = r->notes; - } - else { - p = r->main->pool; - notes = r->main->notes; - } - - if (apr_pool_create(&sub_pool, p) != APR_SUCCESS) - return DECLINED; - - t = apr_array_make(sub_pool, candidates->nelts * 8 + 8, - sizeof(char *)); - v = apr_array_make(sub_pool, candidates->nelts * 5, - sizeof(char *)); - - /* Generate the response text. */ - - *(const char **)apr_array_push(t) = - "The document name you requested (<code>"; - *(const char **)apr_array_push(t) = ap_escape_html(sub_pool, r->uri); - *(const char **)apr_array_push(t) = - "</code>) could not be found on this server.\n" - "However, we found documents with names similar " - "to the one you requested.<p>" - "Available documents:\n<ul>\n"; - - for (i = 0; i < candidates->nelts; ++i) { - char *vuri; - const char *reason; - - reason = sp_reason_str[(int) (variant[i].quality)]; - /* The format isn't very neat... */ - vuri = apr_pstrcat(sub_pool, url, variant[i].name, r->path_info, - (r->parsed_uri.query != NULL) ? "?" : "", - (r->parsed_uri.query != NULL) - ? r->parsed_uri.query : "", - NULL); - *(const char **)apr_array_push(v) = "\""; - *(const char **)apr_array_push(v) = ap_escape_uri(sub_pool, vuri); - *(const char **)apr_array_push(v) = "\";\""; - *(const char **)apr_array_push(v) = reason; - *(const char **)apr_array_push(v) = "\""; - - *(const char **)apr_array_push(t) = "<li><a href=\""; - *(const char **)apr_array_push(t) = ap_escape_uri(sub_pool, vuri); - *(const char **)apr_array_push(t) = "\">"; - *(const char **)apr_array_push(t) = ap_escape_html(sub_pool, vuri); - *(const char **)apr_array_push(t) = "</a> ("; - *(const char **)apr_array_push(t) = reason; - *(const char **)apr_array_push(t) = ")\n"; - - /* - * when we have printed the "close matches" and there are - * more "distant matches" (matched by stripping the suffix), - * then we insert an additional separator text to suggest - * that the user LOOK CLOSELY whether these are really the - * files she wanted. - */ - if (i > 0 && i < candidates->nelts - 1 - && variant[i].quality != SP_VERYDIFFERENT - && variant[i + 1].quality == SP_VERYDIFFERENT) { - *(const char **)apr_array_push(t) = - "</ul>\nFurthermore, the following related " - "documents were found:\n<ul>\n"; - } - } - *(const char **)apr_array_push(t) = "</ul>\n"; - - /* If we know there was a referring page, add a note: */ - if (ref != NULL) { - *(const char **)apr_array_push(t) = - "Please consider informing the owner of the " - "<a href=\""; - *(const char **)apr_array_push(t) = ap_escape_uri(sub_pool, ref); - *(const char **)apr_array_push(t) = "\">referring page</a> " - "about the broken link.\n"; - } - - - /* Pass our apr_table_t to http_protocol.c (see mod_negotiation): */ - apr_table_setn(notes, "variant-list", apr_array_pstrcat(p, t, 0)); - - apr_table_mergen(r->subprocess_env, "VARIANTS", - apr_array_pstrcat(p, v, ',')); - - apr_pool_destroy(sub_pool); - - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_INFO, 0, r, - ref ? "Spelling fix: %s: %d candidates from %s" - : "Spelling fix: %s: %d candidates", - r->uri, candidates->nelts, ref); - - return HTTP_MULTIPLE_CHOICES; - } - } - - return OK; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_fixups(check_speling,NULL,NULL,APR_HOOK_LAST); -} - -module AP_MODULE_DECLARE_DATA speling_module = -{ - STANDARD20_MODULE_STUFF, - create_mconfig_for_directory, /* create per-dir config */ - NULL, /* merge per-dir config */ - create_mconfig_for_server, /* server config */ - NULL, /* merge server config */ - speling_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/mappers/mod_speling.dsp b/modules/mappers/mod_speling.dsp deleted file mode 100644 index 15c098ca02..0000000000 --- a/modules/mappers/mod_speling.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_speling" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_speling - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_speling.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_speling.mak" CFG="mod_speling - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_speling - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_speling - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_speling - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_speling" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_speling.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_speling -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_speling.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_speling - -!ELSEIF "$(CFG)" == "mod_speling - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_speling" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_speling.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_speling -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_speling.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_speling - -!ENDIF - -# Begin Target - -# Name "mod_speling - Win32 Release" -# Name "mod_speling - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_speling.c -# End Source File -# End Target -# End Project diff --git a/modules/mappers/mod_speling.exp b/modules/mappers/mod_speling.exp deleted file mode 100644 index a6ee8b5034..0000000000 --- a/modules/mappers/mod_speling.exp +++ /dev/null @@ -1 +0,0 @@ -speling_module diff --git a/modules/mappers/mod_speling.mak b/modules/mappers/mod_speling.mak deleted file mode 100644 index bc9460d0c3..0000000000 --- a/modules/mappers/mod_speling.mak +++ /dev/null @@ -1,325 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_speling.dsp -!IF "$(CFG)" == "" -CFG=mod_speling - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_speling - Win32 Release. -!ENDIF - -!IF "$(CFG)" != "mod_speling - Win32 Release" && "$(CFG)" !=\ - "mod_speling - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_speling.mak" CFG="mod_speling - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_speling - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_speling - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_speling - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_speling.so" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libapr - Win32 Release"\ - "$(OUTDIR)\mod_speling.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_speling.idb" - -@erase "$(INTDIR)\mod_speling.obj" - -@erase "$(OUTDIR)\mod_speling.exp" - -@erase "$(OUTDIR)\mod_speling.lib" - -@erase "$(OUTDIR)\mod_speling.map" - -@erase "$(OUTDIR)\mod_speling.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_speling" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_speling.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_speling.pdb" /map:"$(INTDIR)\mod_speling.map" /machine:I386\ - /out:"$(OUTDIR)\mod_speling.so" /implib:"$(OUTDIR)\mod_speling.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_speling -LINK32_OBJS= \ - "$(INTDIR)\mod_speling.obj" \ - "..\..\Release\libhttpd.lib" \ - "..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_speling.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_speling - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_speling.so" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libapr - Win32 Debug"\ - "$(OUTDIR)\mod_speling.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_speling.idb" - -@erase "$(INTDIR)\mod_speling.obj" - -@erase "$(OUTDIR)\mod_speling.exp" - -@erase "$(OUTDIR)\mod_speling.lib" - -@erase "$(OUTDIR)\mod_speling.map" - -@erase "$(OUTDIR)\mod_speling.pdb" - -@erase "$(OUTDIR)\mod_speling.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_speling" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_speling.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_speling.pdb" /map:"$(INTDIR)\mod_speling.map" /debug\ - /machine:I386 /out:"$(OUTDIR)\mod_speling.so"\ - /implib:"$(OUTDIR)\mod_speling.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_speling -LINK32_OBJS= \ - "$(INTDIR)\mod_speling.obj" \ - "..\..\Debug\libhttpd.lib" \ - "..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_speling.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_speling - Win32 Release" || "$(CFG)" ==\ - "mod_speling - Win32 Debug" - -!IF "$(CFG)" == "mod_speling - Win32 Release" - -"libapr - Win32 Release" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Release" - cd "..\..\modules\mappers" - -"libapr - Win32 ReleaseCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\mappers" - -!ELSEIF "$(CFG)" == "mod_speling - Win32 Debug" - -"libapr - Win32 Debug" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Debug" - cd "..\..\modules\mappers" - -"libapr - Win32 DebugCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\mappers" - -!ENDIF - -!IF "$(CFG)" == "mod_speling - Win32 Release" - -"libhttpd - Win32 Release" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Release" - cd ".\modules\mappers" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Release"\ - RECURSE=1 - cd ".\modules\mappers" - -!ELSEIF "$(CFG)" == "mod_speling - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Debug" - cd ".\modules\mappers" - -"libhttpd - Win32 DebugCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\mappers" - -!ENDIF - -SOURCE=.\mod_speling.c -DEP_CPP_MOD_S=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_request.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\srclib\apr-util\include\apu.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\include\apr_user.h"\ - "..\..\srclib\apr\include\apr_want.h"\ - -NODEP_CPP_MOD_S=\ - "..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\mod_speling.obj" : $(SOURCE) $(DEP_CPP_MOD_S) "$(INTDIR)" - - - -!ENDIF - diff --git a/modules/mappers/mod_userdir.c b/modules/mappers/mod_userdir.c deleted file mode 100644 index baf8a51b12..0000000000 --- a/modules/mappers/mod_userdir.c +++ /dev/null @@ -1,399 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_userdir... implement the UserDir command. Broken away from the - * Alias stuff for a couple of good and not-so-good reasons: - * - * 1) It shows a real minimal working example of how to do something like - * this. - * 2) I know people who are actually interested in changing this *particular* - * aspect of server functionality without changing the rest of it. That's - * what this whole modular arrangement is supposed to be good at... - * - * Modified by Alexei Kosut to support the following constructs - * (server running at www.foo.com, request for /~bar/one/two.html) - * - * UserDir public_html -> ~bar/public_html/one/two.html - * UserDir /usr/web -> /usr/web/bar/one/two.html - * UserDir /home/ * /www -> /home/bar/www/one/two.html - * NOTE: theses ^ ^ space only added allow it to work in a comment, ignore - * UserDir http://x/users -> (302) http://x/users/bar/one/two.html - * UserDir http://x/ * /y -> (302) http://x/bar/y/one/two.html - * NOTE: here also ^ ^ - * - * In addition, you can use multiple entries, to specify alternate - * user directories (a la Directory Index). For example: - * - * UserDir public_html /usr/web http://www.xyz.com/users - * - * Modified by Ken Coar to provide for the following: - * - * UserDir disable[d] username ... - * UserDir enable[d] username ... - * - * If "disabled" has no other arguments, *all* ~<username> references are - * disabled, except those explicitly turned on with the "enabled" keyword. - */ - -#include "apr_strings.h" -#include "apr_user.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" - -#if !defined(WIN32) && !defined(OS2) && !defined(BEOS) -#define HAVE_UNIX_SUEXEC -#endif - -#ifdef HAVE_UNIX_SUEXEC -#include "unixd.h" /* Contains the suexec_identity hook used on Unix */ -#endif - - -/* The default directory in user's home dir */ -#ifndef DEFAULT_USER_DIR -#define DEFAULT_USER_DIR "public_html" -#endif - -module userdir_module; - -typedef struct { - int globally_disabled; - char *userdir; - apr_table_t *enabled_users; - apr_table_t *disabled_users; -} userdir_config; - -/* - * Server config for this module: global disablement flag, a list of usernames - * ineligible for UserDir access, a list of those immune to global (but not - * explicit) disablement, and the replacement string for all others. - */ - -static void *create_userdir_config(apr_pool_t *p, server_rec *s) -{ - userdir_config *newcfg = apr_pcalloc(p, sizeof(*newcfg)); - - newcfg->globally_disabled = 0; - newcfg->userdir = DEFAULT_USER_DIR; - newcfg->enabled_users = apr_table_make(p, 4); - newcfg->disabled_users = apr_table_make(p, 4); - - return newcfg; -} - -#define O_DEFAULT 0 -#define O_ENABLE 1 -#define O_DISABLE 2 - -static const char *set_user_dir(cmd_parms *cmd, void *dummy, const char *arg) -{ - userdir_config *s_cfg = ap_get_module_config(cmd->server->module_config, - &userdir_module); - char *username; - const char *usernames = arg; - char *kw = ap_getword_conf(cmd->pool, &usernames); - apr_table_t *usertable; - - /* - * Let's do the comparisons once. - */ - if ((!strcasecmp(kw, "disable")) || (!strcasecmp(kw, "disabled"))) { - /* - * If there are no usernames specified, this is a global disable - we - * need do no more at this point than record the fact. - */ - if (strlen(usernames) == 0) { - s_cfg->globally_disabled = 1; - return NULL; - } - usertable = s_cfg->disabled_users; - } - else if ((!strcasecmp(kw, "enable")) || (!strcasecmp(kw, "enabled"))) { - /* - * The "disable" keyword can stand alone or take a list of names, but - * the "enable" keyword requires the list. Whinge if it doesn't have - * it. - */ - if (strlen(usernames) == 0) { - return "UserDir \"enable\" keyword requires a list of usernames"; - } - usertable = s_cfg->enabled_users; - } - else { - /* - * If the first (only?) value isn't one of our keywords, just copy - * the string to the userdir string. - */ - s_cfg->userdir = apr_pstrdup(cmd->pool, arg); - return NULL; - } - /* - * Now we just take each word in turn from the command line and add it to - * the appropriate table. - */ - while (*usernames) { - username = ap_getword_conf(cmd->pool, &usernames); - apr_table_setn(usertable, username, kw); - } - return NULL; -} - -static const command_rec userdir_cmds[] = { - AP_INIT_RAW_ARGS("UserDir", set_user_dir, NULL, RSRC_CONF, - "the public subdirectory in users' home directories, or " - "'disabled', or 'disabled username username...', or " - "'enabled username username...'"), - {NULL} -}; - -static int translate_userdir(request_rec *r) -{ - ap_conf_vector_t *server_conf = r->server->module_config; - const userdir_config *s_cfg = ap_get_module_config(server_conf, - &userdir_module); - char *name = r->uri; - const char *userdirs = s_cfg->userdir; - const char *w, *dname; - char *redirect; - char *x = NULL; - apr_finfo_t statbuf; - - /* - * If the URI doesn't match our basic pattern, we've nothing to do with - * it. - */ - if (s_cfg->userdir == NULL || name[0] != '/' || name[1] != '~') { - return DECLINED; - } - - dname = name + 2; - w = ap_getword(r->pool, &dname, '/'); - - /* - * The 'dname' funny business involves backing it up to capture the '/' - * delimiting the "/~user" part from the rest of the URL, in case there - * was one (the case where there wasn't being just "GET /~user HTTP/1.0", - * for which we don't want to tack on a '/' onto the filename). - */ - - if (dname[-1] == '/') { - --dname; - } - - /* - * If there's no username, it's not for us. Ignore . and .. as well. - */ - if (w[0] == '\0' || (w[1] == '.' && (w[2] == '\0' || (w[2] == '.' && w[3] == '\0')))) { - return DECLINED; - } - /* - * Nor if there's an username but it's in the disabled list. - */ - if (apr_table_get(s_cfg->disabled_users, w) != NULL) { - return DECLINED; - } - /* - * If there's a global interdiction on UserDirs, check to see if this - * name is one of the Blessed. - */ - if (s_cfg->globally_disabled - && apr_table_get(s_cfg->enabled_users, w) == NULL) { - return DECLINED; - } - - /* - * Special cases all checked, onward to normal substitution processing. - */ - - while (*userdirs) { - const char *userdir = ap_getword_conf(r->pool, &userdirs); - char *filename = NULL; - apr_status_t rv; - - if (ap_strchr_c(userdir, '*')) - x = ap_getword(r->pool, &userdir, '*'); - - if (userdir[0] == '\0' || ap_os_is_path_absolute(userdir)) { - if (x) { -#ifdef HAVE_DRIVE_LETTERS - /* - * Crummy hack. Need to figure out whether we have been - * redirected to a URL or to a file on some drive. Since I - * know of no protocols that are a single letter, ignore - * a : as the first or second character, and assume a file - * was specified - * - * XXX: Still no good for NETWARE, since : is embedded (sys:/home) - */ - if (strchr(x + 2, ':')) -#else - if (strchr(x, ':')) -#endif /* HAVE_DRIVE_LETTERS */ - { - redirect = apr_pstrcat(r->pool, x, w, userdir, dname, NULL); - apr_table_setn(r->headers_out, "Location", redirect); - return HTTP_MOVED_TEMPORARILY; - } - else - filename = apr_pstrcat(r->pool, x, w, userdir, NULL); - } - else - filename = apr_pstrcat(r->pool, userdir, "/", w, NULL); - } - else if (ap_strchr_c(userdir, ':')) { - redirect = apr_pstrcat(r->pool, userdir, "/", w, dname, NULL); - apr_table_setn(r->headers_out, "Location", redirect); - return HTTP_MOVED_TEMPORARILY; - } - else { -#if APR_HAS_USER - char *homedir; - - if (apr_get_home_directory(&homedir, w, r->pool) == APR_SUCCESS) { - filename = apr_pstrcat(r->pool, homedir, "/", userdir, NULL); - } - else { - return DECLINED; - } -#else - return DECLINED; -#endif - } - - /* - * Now see if it exists, or we're at the last entry. If we are at the - * last entry, then use the filename generated (if there is one) - * anyway, in the hope that some handler might handle it. This can be - * used, for example, to run a CGI script for the user. - */ - if (filename && (!*userdirs - || ((rv = apr_stat(&statbuf, filename, APR_FINFO_MIN, - r->pool)) == APR_SUCCESS - || rv == APR_INCOMPLETE))) { - r->filename = apr_pstrcat(r->pool, filename, dname, NULL); - /* XXX: Does this walk us around FollowSymLink rules? - * When statbuf contains info on r->filename we can save a syscall - * by copying it to r->finfo - */ - if (*userdirs && dname[0] == 0) - r->finfo = statbuf; - - /* For use in the get_suexec_identity phase */ - apr_table_setn(r->notes, "mod_userdir_user", w); - - return OK; - } - } - - return DECLINED; -} - -#ifdef HAVE_UNIX_SUEXEC -static ap_unix_identity_t *get_suexec_id_doer(const request_rec *r) -{ - ap_unix_identity_t *ugid = NULL; -#if APR_HAS_USER - const char *username = apr_table_get(r->notes, "mod_userdir_user"); - - if (username == NULL) { - return NULL; - } - - if ((ugid = apr_palloc(r->pool, sizeof(ap_unix_identity_t *))) == NULL) { - return NULL; - } - - if (apr_get_userid(&ugid->uid, &ugid->gid, username, r->pool) != APR_SUCCESS) { - return NULL; - } - -#endif - return ugid; -} -#endif /* HAVE_UNIX_SUEXEC */ - -static void register_hooks(apr_pool_t *p) -{ - static const char * const aszSucc[]={ "mod_alias.c",NULL }; - - ap_hook_translate_name(translate_userdir,NULL,aszSucc,APR_HOOK_MIDDLE); -#ifdef HAVE_UNIX_SUEXEC - ap_hook_get_suexec_identity(get_suexec_id_doer,NULL,NULL,APR_HOOK_MIDDLE); -#endif -} - -module userdir_module = { - STANDARD20_MODULE_STUFF, - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - create_userdir_config, /* server config */ - NULL, /* merge server config */ - userdir_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/mappers/mod_userdir.exp b/modules/mappers/mod_userdir.exp deleted file mode 100644 index 6b8b81d5c3..0000000000 --- a/modules/mappers/mod_userdir.exp +++ /dev/null @@ -1 +0,0 @@ -userdir_module diff --git a/modules/mappers/mod_vhost_alias.c b/modules/mappers/mod_vhost_alias.c deleted file mode 100644 index 09994fb7a4..0000000000 --- a/modules/mappers/mod_vhost_alias.c +++ /dev/null @@ -1,490 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_vhost_alias.c: support for dynamically configured mass virtual hosting - * - * Copyright (c) 1998-1999 Demon Internet Ltd. - * - * This software was submitted by Demon Internet to the Apache Software Foundation - * in May 1999. Future revisions and derivatives of this source code - * must acknowledge Demon Internet as the original contributor of - * this module. All other licensing and usage conditions are those - * of the Apache Software Foundation. - * - * Originally written by Tony Finch <fanf@demon.net> <dot@dotat.at>. - * - * Implementation ideas were taken from mod_alias.c. The overall - * concept is derived from the OVERRIDE_DOC_ROOT/OVERRIDE_CGIDIR - * patch to Apache 1.3b3 and a similar feature in Demon's thttpd, - * both written by James Grinter <jrg@blodwen.demon.co.uk>. - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_hooks.h" -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_request.h" /* for ap_hook_translate_name */ - - -module AP_MODULE_DECLARE_DATA vhost_alias_module; - - -/* - * basic configuration things - * we abbreviate "mod_vhost_alias" to "mva" for shorter names - */ - -typedef enum { - VHOST_ALIAS_UNSET, VHOST_ALIAS_NONE, VHOST_ALIAS_NAME, VHOST_ALIAS_IP -} mva_mode_e; - -/* - * Per-server module config record. - */ -typedef struct mva_sconf_t { - const char *doc_root; - const char *cgi_root; - mva_mode_e doc_root_mode; - mva_mode_e cgi_root_mode; -} mva_sconf_t; - -static void *mva_create_server_config(apr_pool_t *p, server_rec *s) -{ - mva_sconf_t *conf; - - conf = (mva_sconf_t *) apr_pcalloc(p, sizeof(mva_sconf_t)); - conf->doc_root = NULL; - conf->cgi_root = NULL; - conf->doc_root_mode = VHOST_ALIAS_UNSET; - conf->cgi_root_mode = VHOST_ALIAS_UNSET; - return conf; -} - -static void *mva_merge_server_config(apr_pool_t *p, void *parentv, void *childv) -{ - mva_sconf_t *parent = (mva_sconf_t *) parentv; - mva_sconf_t *child = (mva_sconf_t *) childv; - mva_sconf_t *conf; - - conf = (mva_sconf_t *) apr_pcalloc(p, sizeof(*conf)); - if (child->doc_root_mode == VHOST_ALIAS_UNSET) { - conf->doc_root_mode = parent->doc_root_mode; - conf->doc_root = parent->doc_root; - } - else { - conf->doc_root_mode = child->doc_root_mode; - conf->doc_root = child->doc_root; - } - if (child->cgi_root_mode == VHOST_ALIAS_UNSET) { - conf->cgi_root_mode = parent->cgi_root_mode; - conf->cgi_root = parent->cgi_root; - } - else { - conf->cgi_root_mode = child->cgi_root_mode; - conf->cgi_root = child->cgi_root; - } - return conf; -} - - -/* - * These are just here to tell us what vhost_alias_set should do. - * We don't put anything into them; we just use the cell addresses. - */ -static int vhost_alias_set_doc_root_ip, - vhost_alias_set_cgi_root_ip, - vhost_alias_set_doc_root_name, - vhost_alias_set_cgi_root_name; - -static const char *vhost_alias_set(cmd_parms *cmd, void *dummy, const char *map) -{ - mva_sconf_t *conf; - mva_mode_e mode, *pmode; - const char **pmap; - const char *p; - - conf = (mva_sconf_t *) ap_get_module_config(cmd->server->module_config, - &vhost_alias_module); - /* there ought to be a better way of doing this */ - if (&vhost_alias_set_doc_root_ip == cmd->info) { - mode = VHOST_ALIAS_IP; - pmap = &conf->doc_root; - pmode = &conf->doc_root_mode; - } - else if (&vhost_alias_set_cgi_root_ip == cmd->info) { - mode = VHOST_ALIAS_IP; - pmap = &conf->cgi_root; - pmode = &conf->cgi_root_mode; - } - else if (&vhost_alias_set_doc_root_name == cmd->info) { - mode = VHOST_ALIAS_NAME; - pmap = &conf->doc_root; - pmode = &conf->doc_root_mode; - } - else if (&vhost_alias_set_cgi_root_name == cmd->info) { - mode = VHOST_ALIAS_NAME; - pmap = &conf->cgi_root; - pmode = &conf->cgi_root_mode; - } - else { - return "INTERNAL ERROR: unknown command info"; - } - - if (*map != '/') { - if (strcasecmp(map, "none")) { - return "format string must start with '/' or be 'none'"; - } - *pmap = NULL; - *pmode = VHOST_ALIAS_NONE; - return NULL; - } - - /* sanity check */ - p = map; - while (*p != '\0') { - if (*p++ != '%') { - continue; - } - /* we just found a '%' */ - if (*p == 'p' || *p == '%') { - ++p; - continue; - } - /* optional dash */ - if (*p == '-') { - ++p; - } - /* digit N */ - if (apr_isdigit(*p)) { - ++p; - } - else { - return "syntax error in format string"; - } - /* optional plus */ - if (*p == '+') { - ++p; - } - /* do we end here? */ - if (*p != '.') { - continue; - } - ++p; - /* optional dash */ - if (*p == '-') { - ++p; - } - /* digit M */ - if (apr_isdigit(*p)) { - ++p; - } - else { - return "syntax error in format string"; - } - /* optional plus */ - if (*p == '+') { - ++p; - } - } - *pmap = map; - *pmode = mode; - return NULL; -} - -static const command_rec mva_commands[] = -{ - AP_INIT_TAKE1("VirtualScriptAlias", vhost_alias_set, - &vhost_alias_set_cgi_root_name, RSRC_CONF, - "how to create a ScriptAlias based on the host"), - AP_INIT_TAKE1("VirtualDocumentRoot", vhost_alias_set, - &vhost_alias_set_doc_root_name, RSRC_CONF, - "how to create the DocumentRoot based on the host"), - AP_INIT_TAKE1("VirtualScriptAliasIP", vhost_alias_set, - &vhost_alias_set_cgi_root_ip, RSRC_CONF, - "how to create a ScriptAlias based on the host"), - AP_INIT_TAKE1("VirtualDocumentRootIP", vhost_alias_set, - &vhost_alias_set_doc_root_ip, RSRC_CONF, - "how to create the DocumentRoot based on the host"), - { NULL } -}; - - -/* - * This really wants to be a nested function - * but C is too feeble to support them. - */ -static APR_INLINE void vhost_alias_checkspace(request_rec *r, char *buf, - char **pdest, int size) -{ - /* XXX: what if size > HUGE_STRING_LEN? */ - if (*pdest + size > buf + HUGE_STRING_LEN) { - **pdest = '\0'; - if (r->filename) { - r->filename = apr_pstrcat(r->pool, r->filename, buf, NULL); - } - else { - r->filename = apr_pstrdup(r->pool, buf); - } - *pdest = buf; - } -} - -static void vhost_alias_interpolate(request_rec *r, const char *name, - const char *map, const char *uri) -{ - /* 0..9 9..0 */ - enum { MAXDOTS = 19 }; - const char *dots[MAXDOTS+1]; - int ndots; - - char buf[HUGE_STRING_LEN]; - char *dest, last; - - int N, M, Np, Mp, Nd, Md; - const char *start, *end; - - const char *p; - - ndots = 0; - dots[ndots++] = name-1; /* slightly naughty */ - for (p = name; *p; ++p){ - if (*p == '.' && ndots < MAXDOTS) { - dots[ndots++] = p; - } - } - dots[ndots] = p; - - r->filename = NULL; - - dest = buf; - last = '\0'; - while (*map) { - if (*map != '%') { - /* normal characters */ - vhost_alias_checkspace(r, buf, &dest, 1); - last = *dest++ = *map++; - continue; - } - /* we are in a format specifier */ - ++map; - /* can't be a slash */ - last = '\0'; - /* %% -> % */ - if (*map == '%') { - ++map; - vhost_alias_checkspace(r, buf, &dest, 1); - *dest++ = '%'; - continue; - } - /* port number */ - if (*map == 'p') { - ++map; - /* no. of decimal digits in a short plus one */ - vhost_alias_checkspace(r, buf, &dest, 7); - dest += apr_snprintf(dest, 7, "%d", ap_get_server_port(r)); - continue; - } - /* deal with %-N+.-M+ -- syntax is already checked */ - N = M = 0; /* value */ - Np = Mp = 0; /* is there a plus? */ - Nd = Md = 0; /* is there a dash? */ - if (*map == '-') ++map, Nd = 1; - N = *map++ - '0'; - if (*map == '+') ++map, Np = 1; - if (*map == '.') { - ++map; - if (*map == '-') { - ++map, Md = 1; - } - M = *map++ - '0'; - if (*map == '+') { - ++map, Mp = 1; - } - } - /* note that N and M are one-based indices, not zero-based */ - start = dots[0]+1; /* ptr to the first character */ - end = dots[ndots]; /* ptr to the character after the last one */ - if (N != 0) { - if (N > ndots) { - start = "_"; - end = start+1; - } - else if (!Nd) { - start = dots[N-1]+1; - if (!Np) { - end = dots[N]; - } - } - else { - if (!Np) { - start = dots[ndots-N]+1; - } - end = dots[ndots-N+1]; - } - } - if (M != 0) { - if (M > end - start) { - start = "_"; - end = start+1; - } - else if (!Md) { - start = start+M-1; - if (!Mp) { - end = start+1; - } - } - else { - if (!Mp) { - start = end-M; - } - end = end-M+1; - } - } - vhost_alias_checkspace(r, buf, &dest, end - start); - for (p = start; p < end; ++p) { - *dest++ = apr_tolower(*p); - } - } - *dest = '\0'; - /* no double slashes */ - if (last == '/') { - ++uri; - } - if (r->filename) { - r->filename = apr_pstrcat(r->pool, r->filename, buf, uri, NULL); - } - else { - r->filename = apr_pstrcat(r->pool, buf, uri, NULL); - } -} - -static int mva_translate(request_rec *r) -{ - mva_sconf_t *conf; - const char *name, *map, *uri; - mva_mode_e mode; - const char *cgi; - - conf = (mva_sconf_t *) ap_get_module_config(r->server->module_config, - &vhost_alias_module); - cgi = NULL; - if (conf->cgi_root) { - cgi = strstr(r->uri, "cgi-bin/"); - if (cgi && cgi - r->uri != strspn(r->uri, "/")) { - cgi = NULL; - } - } - if (cgi) { - mode = conf->cgi_root_mode; - map = conf->cgi_root; - uri = cgi + strlen("cgi-bin"); - } - else if (r->uri[0] == '/') { - mode = conf->doc_root_mode; - map = conf->doc_root; - uri = r->uri; - } - else { - return DECLINED; - } - - if (mode == VHOST_ALIAS_NAME) { - name = ap_get_server_name(r); - } - else if (mode == VHOST_ALIAS_IP) { - name = r->connection->local_ip; - } - else { - return DECLINED; - } - - vhost_alias_interpolate(r, name, map, uri); - - if (cgi) { - /* see is_scriptaliased() in mod_cgi */ - r->handler = "cgi-script"; - apr_table_setn(r->notes, "alias-forced-type", r->handler); - } - - return OK; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_translate_name(mva_translate, NULL, NULL, APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA vhost_alias_module = -{ - STANDARD20_MODULE_STUFF, - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - mva_create_server_config, /* server config */ - mva_merge_server_config, /* merge server configs */ - mva_commands, /* command apr_table_t */ - register_hooks /* register hooks */ -}; - diff --git a/modules/metadata/.cvsignore b/modules/metadata/.cvsignore deleted file mode 100644 index 65f0cc30cf..0000000000 --- a/modules/metadata/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -.deps -.libs -*.la -modules.mk -Makefile -*.lo -*.slo -*.so -Debug -Release diff --git a/modules/metadata/.indent.pro b/modules/metadata/.indent.pro deleted file mode 100644 index a9fbe9f9a1..0000000000 --- a/modules/metadata/.indent.pro +++ /dev/null @@ -1,54 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 --TBUFF --TFILE --TTRANS --TUINT4 --T_trans --Tallow_options_t --Tapache_sfio --Tarray_header --Tbool_int --Tbuf_area --Tbuff_struct --Tbuffy --Tcmd_how --Tcmd_parms --Tcommand_rec --Tcommand_struct --Tconn_rec --Tcore_dir_config --Tcore_server_config --Tdir_maker_func --Tevent --Tglobals_s --Thandler_func --Thandler_rec --Tjoblist_s --Tlisten_rec --Tmerger_func --Tmode_t --Tmodule --Tmodule_struct --Tmutex --Tn_long --Tother_child_rec --Toverrides_t --Tparent_score --Tpid_t --Tpiped_log --Tpool --Trequest_rec --Trequire_line --Trlim_t --Tscoreboard --Tsemaphore --Tserver_addr_rec --Tserver_rec --Tserver_rec_chain --Tshort_score --Ttable --Ttable_entry --Tthread --Tu_wide_int --Tvtime_t --Twide_int diff --git a/modules/metadata/Makefile.in b/modules/metadata/Makefile.in deleted file mode 100644 index 167b343d0d..0000000000 --- a/modules/metadata/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ - -include $(top_srcdir)/build/special.mk - diff --git a/modules/metadata/config.m4 b/modules/metadata/config.m4 deleted file mode 100644 index d1bfb56d5b..0000000000 --- a/modules/metadata/config.m4 +++ /dev/null @@ -1,23 +0,0 @@ -dnl modules enabled in this directory by default - -dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]]) - -APACHE_MODPATH_INIT(metadata) - -APACHE_MODULE(env, clearing/setting of ENV vars, , , yes) -APACHE_MODULE(mime_magic, automagically determining MIME type) -APACHE_MODULE(cern_meta, CERN-type meta files) -APACHE_MODULE(expires, Expires header control, , , most) -APACHE_MODULE(headers, HTTP header control, , , most) - -APACHE_MODULE(usertrack, user-session tracking, , , , [ - AC_CHECK_HEADERS(sys/times.h) - AC_CHECK_FUNCS(times) -]) - -APACHE_MODULE(unique_id, per-request unique ids) -APACHE_MODULE(setenvif, basing ENV vars on headers, , , yes) - -APR_ADDTO(LTFLAGS,-export-dynamic) - -APACHE_MODPATH_FINISH diff --git a/modules/metadata/mod_cern_meta.c b/modules/metadata/mod_cern_meta.c deleted file mode 100644 index 44a1ebae3e..0000000000 --- a/modules/metadata/mod_cern_meta.c +++ /dev/null @@ -1,406 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_cern_meta.c - * version 0.1.0 - * status beta - * - * Andrew Wilson <Andrew.Wilson@cm.cf.ac.uk> 25.Jan.96 - * - * *** IMPORTANT *** - * This version of mod_cern_meta.c controls Meta File behaviour on a - * per-directory basis. Previous versions of the module defined behaviour - * on a per-server basis. The upshot is that you'll need to revisit your - * configuration files in order to make use of the new module. - * *** - * - * Emulate the CERN HTTPD Meta file semantics. Meta files are HTTP - * headers that can be output in addition to the normal range of - * headers for each file accessed. They appear rather like the Apache - * .asis files, and are able to provide a crude way of influencing - * the Expires: header, as well as providing other curiosities. - * There are many ways to manage meta information, this one was - * chosen because there is already a large number of CERN users - * who can exploit this module. It should be noted that there are probably - * more sensitive ways of managing the Expires: header specifically. - * - * The module obeys the following directives, which can appear - * in the server's .conf files and in .htaccess files. - * - * MetaFiles <on|off> - * - * turns on|off meta file processing for any directory. - * Default value is off - * - * # turn on MetaFiles in this directory - * MetaFiles on - * - * MetaDir <directory name> - * - * specifies the name of the directory in which Apache can find - * meta information files. The directory is usually a 'hidden' - * subdirectory of the directory that contains the file being - * accessed. eg: - * - * # .meta files are in the *same* directory as the - * # file being accessed - * MetaDir . - * - * the default is to look in a '.web' subdirectory. This is the - * same as for CERN 3.+ webservers and behaviour is the same as - * for the directive: - * - * MetaDir .web - * - * MetaSuffix <meta file suffix> - * - * specifies the file name suffix for the file containing the - * meta information. eg: - * - * # our meta files are suffixed with '.cern_meta' - * MetaSuffix .cern_meta - * - * the default is to look for files with the suffix '.meta'. This - * behaviour is the same as for the directive: - * - * MetaSuffix .meta - * - * When accessing the file - * - * DOCUMENT_ROOT/somedir/index.html - * - * this module will look for the file - * - * DOCUMENT_ROOT/somedir/.web/index.html.meta - * - * and will use its contents to generate additional MIME header - * information. - * - * For more information on the CERN Meta file semantics see: - * - * http://www.w3.org/hypertext/WWW/Daemon/User/Config/General.html#MetaDir - * - * Change-log: - * 29.Jan.96 pfopen/pfclose instead of fopen/fclose - * DECLINE when real file not found, we may be checking each - * of the index.html/index.shtml/index.htm variants and don't - * need to report missing ones as spurious errors. - * 31.Jan.96 log_error reports about a malformed .meta file, rather - * than a script error. - * 20.Jun.96 MetaFiles <on|off> default off, added, so that module - * can be configured per-directory. Prior to this the module - * was running for each request anywhere on the server, naughty.. - * 29.Jun.96 All directives made per-directory. - */ - -#include "apr.h" -#include "apr_strings.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "util_script.h" -#include "http_log.h" -#include "http_request.h" -#include "apr_lib.h" - -#define DIR_CMD_PERMS OR_INDEXES - -#define DEFAULT_METADIR ".web" -#define DEFAULT_METASUFFIX ".meta" -#define DEFAULT_METAFILES 0 - -module AP_MODULE_DECLARE_DATA cern_meta_module; - -typedef struct { - const char *metadir; - const char *metasuffix; - int metafiles; -} cern_meta_dir_config; - -static void *create_cern_meta_dir_config(apr_pool_t *p, char *dummy) -{ - cern_meta_dir_config *new = - (cern_meta_dir_config *) apr_palloc(p, sizeof(cern_meta_dir_config)); - - new->metadir = NULL; - new->metasuffix = NULL; - new->metafiles = DEFAULT_METAFILES; - - return new; -} - -static void *merge_cern_meta_dir_configs(apr_pool_t *p, void *basev, void *addv) -{ - cern_meta_dir_config *base = (cern_meta_dir_config *) basev; - cern_meta_dir_config *add = (cern_meta_dir_config *) addv; - cern_meta_dir_config *new = - (cern_meta_dir_config *) apr_palloc(p, sizeof(cern_meta_dir_config)); - - new->metadir = add->metadir ? add->metadir : base->metadir; - new->metasuffix = add->metasuffix ? add->metasuffix : base->metasuffix; - new->metafiles = add->metafiles; - - return new; -} - -static const char *set_metadir(cmd_parms *parms, void *in_dconf, const char *arg) -{ - cern_meta_dir_config *dconf = in_dconf; - - dconf->metadir = arg; - return NULL; -} - -static const char *set_metasuffix(cmd_parms *parms, void *in_dconf, const char *arg) -{ - cern_meta_dir_config *dconf = in_dconf; - - dconf->metasuffix = arg; - return NULL; -} - -static const char *set_metafiles(cmd_parms *parms, void *in_dconf, int arg) -{ - cern_meta_dir_config *dconf = in_dconf; - - dconf->metafiles = arg; - return NULL; -} - - -static const command_rec cern_meta_cmds[] = -{ - AP_INIT_FLAG("MetaFiles", set_metafiles, NULL, DIR_CMD_PERMS, - "Limited to 'on' or 'off'"), - AP_INIT_TAKE1("MetaDir", set_metadir, NULL, DIR_CMD_PERMS, - "the name of the directory containing meta files"), - AP_INIT_TAKE1("MetaSuffix", set_metasuffix, NULL, DIR_CMD_PERMS, - "the filename suffix for meta files"), - {NULL} -}; - -/* XXX: this is very similar to ap_scan_script_header_err_core... - * are the differences deliberate, or just a result of bit rot? - */ -static int scan_meta_file(request_rec *r, apr_file_t *f) -{ - char w[MAX_STRING_LEN]; - char *l; - int p; - apr_table_t *tmp_headers; - - tmp_headers = apr_table_make(r->pool, 5); - while (apr_file_gets(w, MAX_STRING_LEN - 1, f) == APR_SUCCESS) { - - /* Delete terminal (CR?)LF */ - - p = strlen(w); - if (p > 0 && w[p - 1] == '\n') { - if (p > 1 && w[p - 2] == '\015') - w[p - 2] = '\0'; - else - w[p - 1] = '\0'; - } - - if (w[0] == '\0') { - return OK; - } - - /* if we see a bogus header don't ignore it. Shout and scream */ - - if (!(l = strchr(w, ':'))) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "malformed header in meta file: %s", r->filename); - return HTTP_INTERNAL_SERVER_ERROR; - } - - *l++ = '\0'; - while (*l && apr_isspace(*l)) - ++l; - - if (!strcasecmp(w, "Content-type")) { - char *tmp; - /* Nuke trailing whitespace */ - - char *endp = l + strlen(l) - 1; - while (endp > l && apr_isspace(*endp)) - *endp-- = '\0'; - - tmp = apr_pstrdup(r->pool, l); - ap_content_type_tolower(tmp); - r->content_type = tmp; - } - else if (!strcasecmp(w, "Status")) { - sscanf(l, "%d", &r->status); - r->status_line = apr_pstrdup(r->pool, l); - } - else { - apr_table_set(tmp_headers, w, l); - } - } - apr_table_overlap(r->headers_out, tmp_headers, APR_OVERLAP_TABLES_SET); - return OK; -} - -static int add_cern_meta_data(request_rec *r) -{ - char *metafilename; - char *last_slash; - char *real_file; - char *scrap_book; - apr_file_t *f = NULL; - apr_status_t retcode; - cern_meta_dir_config *dconf; - int rv; - request_rec *rr; - - dconf = ap_get_module_config(r->per_dir_config, &cern_meta_module); - - if (!dconf->metafiles) { - return DECLINED; - }; - - /* if ./.web/$1.meta exists then output 'asis' */ - - if (r->finfo.filetype == 0) { - return DECLINED; - }; - - /* is this a directory? */ - if (r->finfo.filetype == APR_DIR || r->uri[strlen(r->uri) - 1] == '/') { - return DECLINED; - }; - - /* what directory is this file in? */ - scrap_book = apr_pstrdup(r->pool, r->filename); - /* skip leading slash, recovered in later processing */ - scrap_book++; - last_slash = strrchr(scrap_book, '/'); - if (last_slash != NULL) { - /* skip over last slash */ - real_file = last_slash; - real_file++; - *last_slash = '\0'; - } - else { - /* no last slash, buh?! */ - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "internal error in mod_cern_meta: %s", r->filename); - /* should really barf, but hey, let's be friends... */ - return DECLINED; - }; - - metafilename = apr_pstrcat(r->pool, "/", scrap_book, "/", - dconf->metadir ? dconf->metadir : DEFAULT_METADIR, - "/", real_file, - dconf->metasuffix ? dconf->metasuffix : DEFAULT_METASUFFIX, - NULL); - - /* XXX: it sucks to require this subrequest to complete, because this - * means people must leave their meta files accessible to the world. - * A better solution might be a "safe open" feature of pfopen to avoid - * pipes, symlinks, and crap like that. - */ - rr = ap_sub_req_lookup_file(metafilename, r, NULL); - if (rr->status != HTTP_OK) { - ap_destroy_sub_req(rr); - return DECLINED; - } - ap_destroy_sub_req(rr); - - retcode = apr_file_open(&f, metafilename, APR_READ | APR_CREATE, APR_OS_DEFAULT, r->pool); - if (retcode != APR_SUCCESS) { - if (APR_STATUS_IS_ENOENT(retcode)) { - return DECLINED; - } - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "meta file permissions deny server access: %s", metafilename); - return HTTP_FORBIDDEN; - }; - - /* read the headers in */ - rv = scan_meta_file(r, f); - apr_file_close(f); - - return rv; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_fixups(add_cern_meta_data,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA cern_meta_module = -{ - STANDARD20_MODULE_STUFF, - create_cern_meta_dir_config,/* dir config creater */ - merge_cern_meta_dir_configs,/* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server configs */ - cern_meta_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/metadata/mod_cern_meta.dsp b/modules/metadata/mod_cern_meta.dsp deleted file mode 100644 index 789970ced3..0000000000 --- a/modules/metadata/mod_cern_meta.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_cern_meta" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_cern_meta - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_cern_meta.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_cern_meta.mak" CFG="mod_cern_meta - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_cern_meta - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_cern_meta - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_cern_meta - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_cern_meta" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_cern_meta.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_cern_meta -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_cern_meta.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_cern_meta - -!ELSEIF "$(CFG)" == "mod_cern_meta - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_cern_meta" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_cern_meta.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_cern_meta -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_cern_meta.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_cern_meta - -!ENDIF - -# Begin Target - -# Name "mod_cern_meta - Win32 Release" -# Name "mod_cern_meta - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_cern_meta.c -# End Source File -# End Target -# End Project diff --git a/modules/metadata/mod_cern_meta.exp b/modules/metadata/mod_cern_meta.exp deleted file mode 100644 index d36e2be6a8..0000000000 --- a/modules/metadata/mod_cern_meta.exp +++ /dev/null @@ -1 +0,0 @@ -cern_meta_module diff --git a/modules/metadata/mod_cern_meta.mak b/modules/metadata/mod_cern_meta.mak deleted file mode 100644 index c21fe9c48c..0000000000 --- a/modules/metadata/mod_cern_meta.mak +++ /dev/null @@ -1,327 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_cern_meta.dsp -!IF "$(CFG)" == "" -CFG=mod_cern_meta - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_cern_meta - Win32\ - Release. -!ENDIF - -!IF "$(CFG)" != "mod_cern_meta - Win32 Release" && "$(CFG)" !=\ - "mod_cern_meta - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_cern_meta.mak" CFG="mod_cern_meta - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_cern_meta - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_cern_meta - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_cern_meta - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_cern_meta.so" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libapr - Win32 Release"\ - "$(OUTDIR)\mod_cern_meta.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_cern_meta.idb" - -@erase "$(INTDIR)\mod_cern_meta.obj" - -@erase "$(OUTDIR)\mod_cern_meta.exp" - -@erase "$(OUTDIR)\mod_cern_meta.lib" - -@erase "$(OUTDIR)\mod_cern_meta.map" - -@erase "$(OUTDIR)\mod_cern_meta.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_cern_meta" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_cern_meta.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_cern_meta.pdb" /map:"$(INTDIR)\mod_cern_meta.map"\ - /machine:I386 /out:"$(OUTDIR)\mod_cern_meta.so"\ - /implib:"$(OUTDIR)\mod_cern_meta.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_cern_meta -LINK32_OBJS= \ - "$(INTDIR)\mod_cern_meta.obj" \ - "..\..\Release\libhttpd.lib" \ - "..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_cern_meta.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_cern_meta - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_cern_meta.so" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libapr - Win32 Debug"\ - "$(OUTDIR)\mod_cern_meta.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_cern_meta.idb" - -@erase "$(INTDIR)\mod_cern_meta.obj" - -@erase "$(OUTDIR)\mod_cern_meta.exp" - -@erase "$(OUTDIR)\mod_cern_meta.lib" - -@erase "$(OUTDIR)\mod_cern_meta.map" - -@erase "$(OUTDIR)\mod_cern_meta.pdb" - -@erase "$(OUTDIR)\mod_cern_meta.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_cern_meta" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_cern_meta.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_cern_meta.pdb" /map:"$(INTDIR)\mod_cern_meta.map" /debug\ - /machine:I386 /out:"$(OUTDIR)\mod_cern_meta.so"\ - /implib:"$(OUTDIR)\mod_cern_meta.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_cern_meta -LINK32_OBJS= \ - "$(INTDIR)\mod_cern_meta.obj" \ - "..\..\Debug\libhttpd.lib" \ - "..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_cern_meta.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_cern_meta - Win32 Release" || "$(CFG)" ==\ - "mod_cern_meta - Win32 Debug" - -!IF "$(CFG)" == "mod_cern_meta - Win32 Release" - -"libapr - Win32 Release" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Release" - cd "..\..\modules\metadata" - -"libapr - Win32 ReleaseCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\metadata" - -!ELSEIF "$(CFG)" == "mod_cern_meta - Win32 Debug" - -"libapr - Win32 Debug" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Debug" - cd "..\..\modules\metadata" - -"libapr - Win32 DebugCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\metadata" - -!ENDIF - -!IF "$(CFG)" == "mod_cern_meta - Win32 Release" - -"libhttpd - Win32 Release" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Release" - cd ".\modules\metadata" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Release"\ - RECURSE=1 - cd ".\modules\metadata" - -!ELSEIF "$(CFG)" == "mod_cern_meta - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Debug" - cd ".\modules\metadata" - -"libhttpd - Win32 DebugCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\metadata" - -!ENDIF - -SOURCE=.\mod_cern_meta.c -DEP_CPP_MOD_C=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_request.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_script.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\srclib\apr-util\include\apu.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\include\apr_user.h"\ - "..\..\srclib\apr\include\apr_want.h"\ - -NODEP_CPP_MOD_C=\ - "..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\mod_cern_meta.obj" : $(SOURCE) $(DEP_CPP_MOD_C) "$(INTDIR)" - - - -!ENDIF - diff --git a/modules/metadata/mod_env.c b/modules/metadata/mod_env.c deleted file mode 100644 index ebe112b859..0000000000 --- a/modules/metadata/mod_env.c +++ /dev/null @@ -1,276 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_env.c - * version 0.0.5 - * status beta - * Pass environment variables to CGI/SSI scripts. - * - * Andrew Wilson <Andrew.Wilson@cm.cf.ac.uk> 06.Dec.95 - * - * Change log: - * 08.Dec.95 Now allows PassEnv directive to appear more than once in - * conf files. - * 10.Dec.95 optimisation. getenv() only called at startup and used - * to build a fast-to-access table. apr_table_t used to build - * per-server environment for each request. - * robustness. better able to handle errors in configuration - * files: - * 1) PassEnv directive present, but no environment variable listed - * 2) PassEnv FOO present, but $FOO not present in environment - * 3) no PassEnv directive present - * 23.Dec.95 Now allows SetEnv directive with same semantics as 'sh' setenv: - * SetEnv Var sets Var to the empty string - * SetEnv Var Val sets Var to the value Val - * Values containing whitespace should be quoted, eg: - * SetEnv Var "this is some text" - * Environment variables take their value from the last instance - * of PassEnv / SetEnv to be reached in the configuration file. - * For example, the sequence: - * PassEnv FOO - * SetEnv FOO override - * Causes FOO to take the value 'override'. - * 23.Feb.96 Added UnsetEnv directive to allow environment variables - * to be removed. - * Virtual hosts now 'inherit' parent server environment which - * they're able to overwrite with their own directives or - * selectively ignore with UnsetEnv. - * *** IMPORTANT - the way that virtual hosts inherit their *** - * *** environment variables from the default server's *** - * *** configuration has changed. You should test your *** - * *** configuration carefully before accepting this *** - * *** version of the module in a live webserver which used *** - * *** older versions of the module. *** - */ - -#include "apr.h" -#include "apr_strings.h" - -#if APR_HAVE_STDLIB_H -#include <stdlib.h> -#endif - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" - - -typedef struct { - apr_table_t *vars; - const char *unsetenv; - int vars_present; -} env_dir_config_rec; - -module AP_MODULE_DECLARE_DATA env_module; - -static void *create_env_dir_config(apr_pool_t *p, char *dummy) -{ - env_dir_config_rec *conf = apr_palloc(p, sizeof(*conf)); - - conf->vars = apr_table_make(p, 50); - conf->unsetenv = ""; - conf->vars_present = 0; - - return conf; -} - -static void *merge_env_dir_configs(apr_pool_t *p, void *basev, void *addv) -{ - env_dir_config_rec *base = basev; - env_dir_config_rec *add = addv; - env_dir_config_rec *newconf = apr_palloc(p, sizeof(*newconf)); - - apr_table_t *new_table; - apr_table_entry_t *elts; - apr_array_header_t *arr; - - int i; - const char *uenv, *unset; - - /* - * new_table = copy_table( p, base->vars ); - * foreach $element ( @add->vars ) { - * table_set( new_table, $element.key, $element.val ); - * }; - * foreach $unsetenv ( @UNSETENV ) { - * table_unset( new_table, $unsetenv ); - * } - */ - - new_table = apr_table_copy(p, base->vars); - - arr = apr_table_elts(add->vars); - elts = (apr_table_entry_t *)arr->elts; - - for (i = 0; i < arr->nelts; ++i) { - apr_table_setn(new_table, elts[i].key, elts[i].val); - } - - unset = add->unsetenv; - uenv = ap_getword_conf(p, &unset); - while (uenv[0] != '\0') { - apr_table_unset(new_table, uenv); - uenv = ap_getword_conf(p, &unset); - } - - newconf->vars = new_table; - - newconf->vars_present = base->vars_present || add->vars_present; - - return newconf; -} - -static const char *add_env_module_vars_passed(cmd_parms *cmd, void *sconf_, - const char *arg) -{ - env_dir_config_rec *sconf = sconf_; - apr_table_t *vars = sconf->vars; - char *env_var; - char *name_ptr; - - while (*arg) { - name_ptr = ap_getword_conf(cmd->pool, &arg); - env_var = getenv(name_ptr); - if (env_var != NULL) { - sconf->vars_present = 1; - apr_table_setn(vars, name_ptr, apr_pstrdup(cmd->pool, env_var)); - } - } - return NULL; -} - -static const char *add_env_module_vars_set(cmd_parms *cmd, void *sconf_, - const char *arg) -{ - env_dir_config_rec *sconf = sconf_; - apr_table_t *vars = sconf->vars; - char *name, *value; - - name = ap_getword_conf(cmd->pool, &arg); - value = ap_getword_conf(cmd->pool, &arg); - - /* name is mandatory, value is optional. no value means - * set the variable to an empty string - */ - - - if ((*name == '\0') || (*arg != '\0')) { - return "SetEnv takes one or two arguments. An environment variable name and an optional value to pass to CGI."; - } - - sconf->vars_present = 1; - apr_table_setn(vars, name, value); - - return NULL; -} - -static const char *add_env_module_vars_unset(cmd_parms *cmd, void *sconf_, - const char *arg) -{ - env_dir_config_rec *sconf = sconf_; - - sconf->unsetenv = sconf->unsetenv - ? apr_pstrcat(cmd->pool, sconf->unsetenv, " ", arg, NULL) - : arg; - - return NULL; -} - -static const command_rec env_module_cmds[] = -{ -AP_INIT_RAW_ARGS("PassEnv", add_env_module_vars_passed, NULL, - OR_FILEINFO, "a list of environment variables to pass to CGI."), -AP_INIT_RAW_ARGS("SetEnv", add_env_module_vars_set, NULL, - OR_FILEINFO, "an environment variable name and a value to pass to CGI."), -AP_INIT_RAW_ARGS("UnsetEnv", add_env_module_vars_unset, NULL, - OR_FILEINFO, "a list of variables to remove from the CGI environment."), - {NULL}, -}; - -static int fixup_env_module(request_rec *r) -{ - apr_table_t *e = r->subprocess_env; - env_dir_config_rec *sconf = ap_get_module_config(r->per_dir_config, - &env_module); - apr_table_t *vars = sconf->vars; - - if (!sconf->vars_present) - return DECLINED; - - r->subprocess_env = apr_table_overlay(r->pool, e, vars); - - return OK; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_fixups(fixup_env_module, NULL, NULL, APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA env_module = -{ - STANDARD20_MODULE_STUFF, - create_env_dir_config, /* dir config creater */ - merge_env_dir_configs, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server configs */ - env_module_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/metadata/mod_env.exp b/modules/metadata/mod_env.exp deleted file mode 100644 index b487bf09c8..0000000000 --- a/modules/metadata/mod_env.exp +++ /dev/null @@ -1 +0,0 @@ -env_module diff --git a/modules/metadata/mod_expires.c b/modules/metadata/mod_expires.c deleted file mode 100644 index 068c03cf2e..0000000000 --- a/modules/metadata/mod_expires.c +++ /dev/null @@ -1,520 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_expires.c - * version 0.0.11 - * status beta - * - * Andrew Wilson <Andrew.Wilson@cm.cf.ac.uk> 26.Jan.96 - * - * This module allows you to control the form of the Expires: header - * that Apache issues for each access. Directives can appear in - * configuration files or in .htaccess files so expiry semantics can - * be defined on a per-directory basis. - * - * DIRECTIVE SYNTAX - * - * Valid directives are: - * - * ExpiresActive on | off - * ExpiresDefault <code><seconds> - * ExpiresByType type/encoding <code><seconds> - * - * Valid values for <code> are: - * - * 'M' expires header shows file modification date + <seconds> - * 'A' expires header shows access time + <seconds> - * - * [I'm not sure which of these is best under different - * circumstances, I guess it's for other people to explore. - * The effects may be indistinguishable for a number of cases] - * - * <seconds> should be an integer value [acceptable to atoi()] - * - * There is NO space between the <code> and <seconds>. - * - * For example, a directory which contains information which changes - * frequently might contain: - * - * # reports generated by cron every hour. don't let caches - * # hold onto stale information - * ExpiresDefault M3600 - * - * Another example, our html pages can change all the time, the gifs - * tend not to change often: - * - * # pages are hot (1 week), images are cold (1 month) - * ExpiresByType text/html A604800 - * ExpiresByType image/gif A2592000 - * - * Expires can be turned on for all URLs on the server by placing the - * following directive in a conf file: - * - * ExpiresActive on - * - * ExpiresActive can also appear in .htaccess files, enabling the - * behaviour to be turned on or off for each chosen directory. - * - * # turn off Expires behaviour in this directory - * # and subdirectories - * ExpiresActive off - * - * Directives defined for a directory are valid in subdirectories - * unless explicitly overridden by new directives in the subdirectory - * .htaccess files. - * - * ALTERNATIVE DIRECTIVE SYNTAX - * - * Directives can also be defined in a more readable syntax of the form: - * - * ExpiresDefault "<base> [plus] {<num> <type>}*" - * ExpiresByType type/encoding "<base> [plus] {<num> <type>}*" - * - * where <base> is one of: - * access - * now equivalent to 'access' - * modification - * - * where the 'plus' keyword is optional - * - * where <num> should be an integer value [acceptable to atoi()] - * - * where <type> is one of: - * years - * months - * weeks - * days - * hours - * minutes - * seconds - * - * For example, any of the following directives can be used to make - * documents expire 1 month after being accessed, by default: - * - * ExpiresDefault "access plus 1 month" - * ExpiresDefault "access plus 4 weeks" - * ExpiresDefault "access plus 30 days" - * - * The expiry time can be fine-tuned by adding several '<num> <type>' - * clauses: - * - * ExpiresByType text/html "access plus 1 month 15 days 2 hours" - * ExpiresByType image/gif "modification plus 5 hours 3 minutes" - * - * --- - * - * Change-log: - * 29.Jan.96 Hardened the add_* functions. Server will now bail out - * if bad directives are given in the conf files. - * 02.Feb.96 Returns DECLINED if not 'ExpiresActive on', giving other - * expires-aware modules a chance to play with the same - * directives. [Michael Rutman] - * 03.Feb.96 Call tzset() before localtime(). Trying to get the module - * to work properly in non GMT timezones. - * 12.Feb.96 Modified directive syntax to allow more readable commands: - * ExpiresDefault "now plus 10 days 20 seconds" - * ExpiresDefault "access plus 30 days" - * ExpiresDefault "modification plus 1 year 10 months 30 days" - * 13.Feb.96 Fix call to table_get() with NULL 2nd parameter [Rob Hartill] - * 19.Feb.96 Call gm_timestr_822() to get time formatted correctly, can't - * rely on presence of HTTP_TIME_FORMAT in Apache 1.1+. - * 21.Feb.96 This version (0.0.9) reverses assumptions made in 0.0.8 - * about star/star handlers. Reverting to 0.0.7 behaviour. - * 08.Jun.96 allows ExpiresDefault to be used with responses that use - * the DefaultType by not DECLINING, but instead skipping - * the table_get check and then looking for an ExpiresDefault. - * [Rob Hartill] - * 04.Nov.96 'const' definitions added. - * - * TODO - * add support for Cache-Control: max-age=20 from the HTTP/1.1 - * proposal (in this case, a ttl of 20 seconds) [ask roy] - * add per-file expiry and explicit expiry times - duplicates some - * of the mod_cern_meta.c functionality. eg: - * ExpiresExplicit index.html "modification plus 30 days" - * - * BUGS - * Hi, welcome to the internet. - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "http_request.h" - -typedef struct { - int active; - char *expiresdefault; - apr_table_t *expiresbytype; -} expires_dir_config; - -/* from mod_dir, why is this alias used? - */ -#define DIR_CMD_PERMS OR_INDEXES - -#define ACTIVE_ON 1 -#define ACTIVE_OFF 0 -#define ACTIVE_DONTCARE 2 - -module AP_MODULE_DECLARE_DATA expires_module; - -static void *create_dir_expires_config(apr_pool_t *p, char *dummy) -{ - expires_dir_config *new = - (expires_dir_config *) apr_pcalloc(p, sizeof(expires_dir_config)); - new->active = ACTIVE_DONTCARE; - new->expiresdefault = ""; - new->expiresbytype = apr_table_make(p, 4); - return (void *) new; -} - -static const char *set_expiresactive(cmd_parms *cmd, void *in_dir_config, int arg) -{ - expires_dir_config *dir_config = in_dir_config; - - /* if we're here at all it's because someone explicitly - * set the active flag - */ - dir_config->active = ACTIVE_ON; - if (arg == 0) { - dir_config->active = ACTIVE_OFF; - }; - return NULL; -} - -/* check_code() parse 'code' and return NULL or an error response - * string. If we return NULL then real_code contains code converted - * to the cnnnn format. - */ -static char *check_code(apr_pool_t *p, const char *code, char **real_code) -{ - char *word; - char base = 'X'; - int modifier = 0; - int num = 0; - int factor = 0; - - /* 0.0.4 compatibility? - */ - if ((code[0] == 'A') || (code[0] == 'M')) { - *real_code = (char *)code; - return NULL; - }; - - /* <base> [plus] {<num> <type>}* - */ - - /* <base> - */ - word = ap_getword_conf(p, &code); - if (!strncasecmp(word, "now", 1) || - !strncasecmp(word, "access", 1)) { - base = 'A'; - } - else if (!strncasecmp(word, "modification", 1)) { - base = 'M'; - } - else { - return apr_pstrcat(p, "bad expires code, unrecognised <base> '", - word, "'", NULL); - }; - - /* [plus] - */ - word = ap_getword_conf(p, &code); - if (!strncasecmp(word, "plus", 1)) { - word = ap_getword_conf(p, &code); - }; - - /* {<num> <type>}* - */ - while (word[0]) { - /* <num> - */ - if (apr_isdigit(word[0])) { - num = atoi(word); - } - else { - return apr_pstrcat(p, "bad expires code, numeric value expected <num> '", - word, "'", NULL); - }; - - /* <type> - */ - word = ap_getword_conf(p, &code); - if (word[0]) { - /* do nothing */ - } - else { - return apr_pstrcat(p, "bad expires code, missing <type>", NULL); - }; - - factor = 0; - if (!strncasecmp(word, "years", 1)) { - factor = 60 * 60 * 24 * 365; - } - else if (!strncasecmp(word, "months", 2)) { - factor = 60 * 60 * 24 * 30; - } - else if (!strncasecmp(word, "weeks", 1)) { - factor = 60 * 60 * 24 * 7; - } - else if (!strncasecmp(word, "days", 1)) { - factor = 60 * 60 * 24; - } - else if (!strncasecmp(word, "hours", 1)) { - factor = 60 * 60; - } - else if (!strncasecmp(word, "minutes", 2)) { - factor = 60; - } - else if (!strncasecmp(word, "seconds", 1)) { - factor = 1; - } - else { - return apr_pstrcat(p, "bad expires code, unrecognised <type>", - "'", word, "'", NULL); - }; - - modifier = modifier + factor * num; - - /* next <num> - */ - word = ap_getword_conf(p, &code); - }; - - *real_code = apr_psprintf(p, "%c%d", base, modifier); - - return NULL; -} - -static const char *set_expiresbytype(cmd_parms *cmd, void *in_dir_config, - const char *mime, const char *code) -{ - expires_dir_config *dir_config = in_dir_config; - char *response, *real_code; - - if ((response = check_code(cmd->pool, code, &real_code)) == NULL) { - apr_table_setn(dir_config->expiresbytype, mime, real_code); - return NULL; - }; - return apr_pstrcat(cmd->pool, - "'ExpiresByType ", mime, " ", code, "': ", response, NULL); -} - -static const char *set_expiresdefault(cmd_parms *cmd, void *in_dir_config, - const char *code) -{ - expires_dir_config * dir_config = in_dir_config; - char *response, *real_code; - - if ((response = check_code(cmd->pool, code, &real_code)) == NULL) { - dir_config->expiresdefault = real_code; - return NULL; - }; - return apr_pstrcat(cmd->pool, - "'ExpiresDefault ", code, "': ", response, NULL); -} - -static const command_rec expires_cmds[] = -{ - AP_INIT_FLAG("ExpiresActive", set_expiresactive, NULL, DIR_CMD_PERMS, - "Limited to 'on' or 'off'"), - AP_INIT_TAKE2("ExpiresBytype", set_expiresbytype, NULL, DIR_CMD_PERMS, - "a MIME type followed by an expiry date code"), - AP_INIT_TAKE1("ExpiresDefault", set_expiresdefault, NULL, DIR_CMD_PERMS, - "an expiry date code"), - {NULL} -}; - -static void *merge_expires_dir_configs(apr_pool_t *p, void *basev, void *addv) -{ - expires_dir_config *new = (expires_dir_config *) apr_pcalloc(p, sizeof(expires_dir_config)); - expires_dir_config *base = (expires_dir_config *) basev; - expires_dir_config *add = (expires_dir_config *) addv; - - if (add->active == ACTIVE_DONTCARE) { - new->active = base->active; - } - else { - new->active = add->active; - }; - - if (add->expiresdefault != '\0') { - new->expiresdefault = add->expiresdefault; - }; - - new->expiresbytype = apr_table_overlay(p, add->expiresbytype, - base->expiresbytype); - return new; -} - -static int add_expires(request_rec *r) -{ - expires_dir_config *conf; - char *code; - apr_time_t base; - apr_time_t additional; - apr_time_t expires; - char *timestr; - - if (ap_is_HTTP_ERROR(r->status)) /* Don't add Expires headers to errors */ - return DECLINED; - - if (r->main != NULL) /* Say no to subrequests */ - return DECLINED; - - conf = (expires_dir_config *) ap_get_module_config(r->per_dir_config, &expires_module); - if (conf == NULL) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "internal error: %s", r->filename); - return HTTP_INTERNAL_SERVER_ERROR; - }; - - if (conf->active != ACTIVE_ON) - return DECLINED; - - /* we perhaps could use the default_type(r) in its place but that - * may be 2nd guesing the desired configuration... calling table_get - * with a NULL key will SEGV us - * - * I still don't know *why* r->content_type would ever be NULL, this - * is possibly a result of fixups being called in many different - * places. Fixups is probably the wrong place to be doing all this - * work... Bah. - * - * Changed as of 08.Jun.96 don't DECLINE, look for an ExpiresDefault. - */ - if (r->content_type == NULL) - code = NULL; - else - code = (char *) apr_table_get(conf->expiresbytype, - ap_field_noparam(r->pool, r->content_type)); - - if (code == NULL) { - /* no expires defined for that type, is there a default? */ - code = conf->expiresdefault; - - if (code[0] == '\0') - return OK; - }; - - /* we have our code */ - - switch (code[0]) { - case 'M': - if (r->finfo.filetype == 0) { - /* file doesn't exist on disk, so we can't do anything based on - * modification time. Note that this does _not_ log an error. - */ - return DECLINED; - } - base = r->finfo.mtime; - additional = atoi(&code[1]); - break; - case 'A': - /* there's been some discussion and it's possible that - * 'access time' will be stored in request structure - */ - base = r->request_time; - additional = atoi(&code[1]); - break; - default: - /* expecting the add_* routines to be case-hardened this - * is just a reminder that module is beta - */ - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "internal error: bad expires code: %s", r->filename); - return HTTP_INTERNAL_SERVER_ERROR; - }; - - expires = base + additional; - apr_table_mergen(r->headers_out, "Cache-Control", - apr_psprintf(r->pool, "max-age=%qd", - (expires - r->request_time) - / APR_USEC_PER_SEC)); - timestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN); - apr_rfc822_date(timestr, expires); - apr_table_setn(r->headers_out, "Expires", timestr); - return OK; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_fixups(add_expires,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA expires_module = -{ - STANDARD20_MODULE_STUFF, - create_dir_expires_config, /* dir config creater */ - merge_expires_dir_configs, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server configs */ - expires_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/metadata/mod_expires.dsp b/modules/metadata/mod_expires.dsp deleted file mode 100644 index a0fac42270..0000000000 --- a/modules/metadata/mod_expires.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_expires" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_expires - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_expires.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_expires.mak" CFG="mod_expires - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_expires - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_expires - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_expires - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_expires" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_expires.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_expires -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_expires.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_expires - -!ELSEIF "$(CFG)" == "mod_expires - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_expires" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_expires.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_expires -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_expires.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_expires - -!ENDIF - -# Begin Target - -# Name "mod_expires - Win32 Release" -# Name "mod_expires - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_expires.c -# End Source File -# End Target -# End Project diff --git a/modules/metadata/mod_expires.exp b/modules/metadata/mod_expires.exp deleted file mode 100644 index 863a96878e..0000000000 --- a/modules/metadata/mod_expires.exp +++ /dev/null @@ -1 +0,0 @@ -expires_module diff --git a/modules/metadata/mod_expires.mak b/modules/metadata/mod_expires.mak deleted file mode 100644 index 2dcc652d05..0000000000 --- a/modules/metadata/mod_expires.mak +++ /dev/null @@ -1,324 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_expires.dsp -!IF "$(CFG)" == "" -CFG=mod_expires - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_expires - Win32 Release. -!ENDIF - -!IF "$(CFG)" != "mod_expires - Win32 Release" && "$(CFG)" !=\ - "mod_expires - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_expires.mak" CFG="mod_expires - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_expires - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_expires - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_expires - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_expires.so" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libapr - Win32 Release"\ - "$(OUTDIR)\mod_expires.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_expires.idb" - -@erase "$(INTDIR)\mod_expires.obj" - -@erase "$(OUTDIR)\mod_expires.exp" - -@erase "$(OUTDIR)\mod_expires.lib" - -@erase "$(OUTDIR)\mod_expires.map" - -@erase "$(OUTDIR)\mod_expires.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_expires" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_expires.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_expires.pdb" /map:"$(INTDIR)\mod_expires.map" /machine:I386\ - /out:"$(OUTDIR)\mod_expires.so" /implib:"$(OUTDIR)\mod_expires.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_expires -LINK32_OBJS= \ - "$(INTDIR)\mod_expires.obj" \ - "..\..\Release\libhttpd.lib" \ - "..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_expires.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_expires - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_expires.so" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libapr - Win32 Debug"\ - "$(OUTDIR)\mod_expires.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_expires.idb" - -@erase "$(INTDIR)\mod_expires.obj" - -@erase "$(OUTDIR)\mod_expires.exp" - -@erase "$(OUTDIR)\mod_expires.lib" - -@erase "$(OUTDIR)\mod_expires.map" - -@erase "$(OUTDIR)\mod_expires.pdb" - -@erase "$(OUTDIR)\mod_expires.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_expires" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_expires.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_expires.pdb" /map:"$(INTDIR)\mod_expires.map" /debug\ - /machine:I386 /out:"$(OUTDIR)\mod_expires.so"\ - /implib:"$(OUTDIR)\mod_expires.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_expires -LINK32_OBJS= \ - "$(INTDIR)\mod_expires.obj" \ - "..\..\Debug\libhttpd.lib" \ - "..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_expires.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_expires - Win32 Release" || "$(CFG)" ==\ - "mod_expires - Win32 Debug" - -!IF "$(CFG)" == "mod_expires - Win32 Release" - -"libapr - Win32 Release" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Release" - cd "..\..\modules\metadata" - -"libapr - Win32 ReleaseCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\metadata" - -!ELSEIF "$(CFG)" == "mod_expires - Win32 Debug" - -"libapr - Win32 Debug" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Debug" - cd "..\..\modules\metadata" - -"libapr - Win32 DebugCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\metadata" - -!ENDIF - -!IF "$(CFG)" == "mod_expires - Win32 Release" - -"libhttpd - Win32 Release" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Release" - cd ".\modules\metadata" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Release"\ - RECURSE=1 - cd ".\modules\metadata" - -!ELSEIF "$(CFG)" == "mod_expires - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Debug" - cd ".\modules\metadata" - -"libhttpd - Win32 DebugCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\metadata" - -!ENDIF - -SOURCE=.\mod_expires.c -DEP_CPP_MOD_E=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_request.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\srclib\apr-util\include\apu.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\include\apr_user.h"\ - "..\..\srclib\apr\include\apr_want.h"\ - -NODEP_CPP_MOD_E=\ - "..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\mod_expires.obj" : $(SOURCE) $(DEP_CPP_MOD_E) "$(INTDIR)" - - - -!ENDIF - diff --git a/modules/metadata/mod_headers.c b/modules/metadata/mod_headers.c deleted file mode 100644 index 20edf23ae1..0000000000 --- a/modules/metadata/mod_headers.c +++ /dev/null @@ -1,269 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_headers.c: Add/append/remove HTTP response headers - * Written by Paul Sutton, paul@ukweb.com, 1 Oct 1996 - * - * New directive, Header, can be used to add/replace/remove HTTP headers. - * Valid in both per-server and per-dir configurations. - * - * Syntax is: - * - * Header action header value - * - * Where action is one of: - * set - set this header, replacing any old value - * add - add this header, possible resulting in two or more - * headers with the same name - * append - append this text onto any existing header of this same - * unset - remove this header - * - * Where action is unset, the third argument (value) should not be given. - * The header name can include the colon, or not. - * - * The Header directive can only be used where allowed by the FileInfo - * override. - * - * When the request is processed, the header directives are processed in - * this order: firstly, the main server, then the virtual server handling - * this request (if any), then any <Directory> sections (working downwards - * from the root dir), then an <Location> sections (working down from - * shortest URL component), the any <File> sections. This order is - * important if any 'set' or 'unset' actions are used. For example, - * the following two directives have different effect if applied in - * the reverse order: - * - * Header append Author "John P. Doe" - * Header unset Author - * - * Examples: - * - * To set the "Author" header, use - * Header add Author "John P. Doe" - * - * To remove a header: - * Header unset Author - * - */ - -#include "apr.h" -#include "apr_strings.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" - - -typedef enum { - hdr_add = 'a', /* add header (could mean multiple hdrs) */ - hdr_set = 's', /* set (replace old value) */ - hdr_append = 'm', /* append (merge into any old value) */ - hdr_unset = 'u' /* unset header */ -} hdr_actions; - -typedef struct { - hdr_actions action; - char *header; - const char *value; -} header_entry; - -/* - * headers_conf is our per-module configuration. This is used as both - * a per-dir and per-server config - */ -typedef struct { - apr_array_header_t *headers; -} headers_conf; - -module AP_MODULE_DECLARE_DATA headers_module; - -static void *create_headers_config(apr_pool_t *p, server_rec *s) -{ - headers_conf *conf = apr_pcalloc(p, sizeof(*conf)); - - conf->headers = apr_array_make(p, 2, sizeof(header_entry)); - - return conf; -} - -static void *create_headers_dir_config(apr_pool_t *p, char *d) -{ - return create_headers_config(p, NULL); -} - -static void *merge_headers_config(apr_pool_t *p, void *basev, void *overridesv) -{ - headers_conf *newconf = apr_pcalloc(p, sizeof(*newconf)); - headers_conf *base = basev; - headers_conf *overrides = overridesv; - - newconf->headers = apr_array_append(p, base->headers, overrides->headers); - - return newconf; -} - - -static const char *header_cmd(cmd_parms *cmd, void *indirconf, - const char *action, const char *inhdr, - const char *value) -{ - headers_conf *dirconf = indirconf; - char *hdr = apr_pstrdup(cmd->pool, inhdr); - header_entry *new; - server_rec *s = cmd->server; - headers_conf *serverconf = ap_get_module_config(s->module_config, - &headers_module); - char *colon; - - if (cmd->path) { - new = (header_entry *) apr_array_push(dirconf->headers); - } - else { - new = (header_entry *) apr_array_push(serverconf->headers); - } - - if (!strcasecmp(action, "set")) - new->action = hdr_set; - else if (!strcasecmp(action, "add")) - new->action = hdr_add; - else if (!strcasecmp(action, "append")) - new->action = hdr_append; - else if (!strcasecmp(action, "unset")) - new->action = hdr_unset; - else - return "first argument must be add, set, append or unset."; - - if (new->action == hdr_unset) { - if (value) - return "Header unset takes two arguments"; - } - else if (!value) - return "Header requires three arguments"; - - if ((colon = strchr(hdr, ':'))) - *colon = '\0'; - - new->header = hdr; - new->value = value; - - return NULL; -} - -static const command_rec headers_cmds[] = -{ - AP_INIT_TAKE23("Header", header_cmd, NULL, OR_FILEINFO, - "an action, header and value"), - {NULL} -}; - -static void do_headers_fixup(request_rec *r, apr_array_header_t *headers) -{ - int i; - - for (i = 0; i < headers->nelts; ++i) { - header_entry *hdr = &((header_entry *) (headers->elts))[i]; - switch (hdr->action) { - case hdr_add: - apr_table_addn(r->headers_out, hdr->header, hdr->value); - break; - case hdr_append: - apr_table_mergen(r->headers_out, hdr->header, hdr->value); - break; - case hdr_set: - apr_table_setn(r->headers_out, hdr->header, hdr->value); - break; - case hdr_unset: - apr_table_unset(r->headers_out, hdr->header); - break; - } - } - -} - -static int fixup_headers(request_rec *r) -{ - headers_conf *serverconf = ap_get_module_config(r->server->module_config, - &headers_module); - headers_conf *dirconf = ap_get_module_config(r->per_dir_config, - &headers_module); - - do_headers_fixup(r, serverconf->headers); - do_headers_fixup(r, dirconf->headers); - - return DECLINED; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_fixups(fixup_headers, NULL, NULL, APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA headers_module = -{ - STANDARD20_MODULE_STUFF, - create_headers_dir_config, /* dir config creater */ - merge_headers_config, /* dir merger --- default is to override */ - create_headers_config, /* server config */ - merge_headers_config, /* merge server configs */ - headers_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/metadata/mod_headers.dsp b/modules/metadata/mod_headers.dsp deleted file mode 100644 index 0575868143..0000000000 --- a/modules/metadata/mod_headers.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_headers" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_headers - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_headers.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_headers.mak" CFG="mod_headers - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_headers - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_headers - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_headers - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_headers" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_headers.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_headers -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_headers.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_headers - -!ELSEIF "$(CFG)" == "mod_headers - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_headers" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_headers.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_headers -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_headers.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_headers - -!ENDIF - -# Begin Target - -# Name "mod_headers - Win32 Release" -# Name "mod_headers - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_headers.c -# End Source File -# End Target -# End Project diff --git a/modules/metadata/mod_headers.exp b/modules/metadata/mod_headers.exp deleted file mode 100644 index 3f3063808a..0000000000 --- a/modules/metadata/mod_headers.exp +++ /dev/null @@ -1 +0,0 @@ -headers_module diff --git a/modules/metadata/mod_headers.mak b/modules/metadata/mod_headers.mak deleted file mode 100644 index 8544faa05c..0000000000 --- a/modules/metadata/mod_headers.mak +++ /dev/null @@ -1,321 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_headers.dsp -!IF "$(CFG)" == "" -CFG=mod_headers - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_headers - Win32 Release. -!ENDIF - -!IF "$(CFG)" != "mod_headers - Win32 Release" && "$(CFG)" !=\ - "mod_headers - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_headers.mak" CFG="mod_headers - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_headers - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_headers - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_headers - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_headers.so" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libapr - Win32 Release"\ - "$(OUTDIR)\mod_headers.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_headers.idb" - -@erase "$(INTDIR)\mod_headers.obj" - -@erase "$(OUTDIR)\mod_headers.exp" - -@erase "$(OUTDIR)\mod_headers.lib" - -@erase "$(OUTDIR)\mod_headers.map" - -@erase "$(OUTDIR)\mod_headers.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_headers" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_headers.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_headers.pdb" /map:"$(INTDIR)\mod_headers.map" /machine:I386\ - /out:"$(OUTDIR)\mod_headers.so" /implib:"$(OUTDIR)\mod_headers.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_headers -LINK32_OBJS= \ - "$(INTDIR)\mod_headers.obj" \ - "..\..\Release\libhttpd.lib" \ - "..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_headers.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_headers - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_headers.so" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libapr - Win32 Debug"\ - "$(OUTDIR)\mod_headers.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_headers.idb" - -@erase "$(INTDIR)\mod_headers.obj" - -@erase "$(OUTDIR)\mod_headers.exp" - -@erase "$(OUTDIR)\mod_headers.lib" - -@erase "$(OUTDIR)\mod_headers.map" - -@erase "$(OUTDIR)\mod_headers.pdb" - -@erase "$(OUTDIR)\mod_headers.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_headers" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_headers.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_headers.pdb" /map:"$(INTDIR)\mod_headers.map" /debug\ - /machine:I386 /out:"$(OUTDIR)\mod_headers.so"\ - /implib:"$(OUTDIR)\mod_headers.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_headers -LINK32_OBJS= \ - "$(INTDIR)\mod_headers.obj" \ - "..\..\Debug\libhttpd.lib" \ - "..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_headers.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_headers - Win32 Release" || "$(CFG)" ==\ - "mod_headers - Win32 Debug" - -!IF "$(CFG)" == "mod_headers - Win32 Release" - -"libapr - Win32 Release" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Release" - cd "..\..\modules\metadata" - -"libapr - Win32 ReleaseCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\metadata" - -!ELSEIF "$(CFG)" == "mod_headers - Win32 Debug" - -"libapr - Win32 Debug" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Debug" - cd "..\..\modules\metadata" - -"libapr - Win32 DebugCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\metadata" - -!ENDIF - -!IF "$(CFG)" == "mod_headers - Win32 Release" - -"libhttpd - Win32 Release" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Release" - cd ".\modules\metadata" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Release"\ - RECURSE=1 - cd ".\modules\metadata" - -!ELSEIF "$(CFG)" == "mod_headers - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Debug" - cd ".\modules\metadata" - -"libhttpd - Win32 DebugCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\metadata" - -!ENDIF - -SOURCE=.\mod_headers.c -DEP_CPP_MOD_H=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_request.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\srclib\apr-util\include\apu.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\include\apr_user.h"\ - "..\..\srclib\apr\include\apr_want.h"\ - -NODEP_CPP_MOD_H=\ - "..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\mod_headers.obj" : $(SOURCE) $(DEP_CPP_MOD_H) "$(INTDIR)" - - - -!ENDIF - diff --git a/modules/metadata/mod_mime_magic.c b/modules/metadata/mod_mime_magic.c deleted file mode 100644 index 36aa086918..0000000000 --- a/modules/metadata/mod_mime_magic.c +++ /dev/null @@ -1,2501 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_mime_magic: MIME type lookup via file magic numbers - * Copyright (c) 1996-1997 Cisco Systems, Inc. - * - * This software was submitted by Cisco Systems to the Apache Software Foundation in July - * 1997. Future revisions and derivatives of this source code must - * acknowledge Cisco Systems as the original contributor of this module. - * All other licensing and usage conditions are those of the Apache Software Foundation. - * - * Some of this code is derived from the free version of the file command - * originally posted to comp.sources.unix. Copyright info for that program - * is included below as required. - * --------------------------------------------------------------------------- - * - Copyright (c) Ian F. Darwin, 1987. Written by Ian F. Darwin. - * - * This software is not subject to any license of the American Telephone and - * Telegraph Company or of the Regents of the University of California. - * - * Permission is granted to anyone to use this software for any purpose on any - * computer system, and to alter it and redistribute it freely, subject to - * the following restrictions: - * - * 1. The author is not responsible for the consequences of use of this - * software, no matter how awful, even if they arise from flaws in it. - * - * 2. The origin of this software must not be misrepresented, either by - * explicit claim or by omission. Since few users ever read sources, credits - * must appear in the documentation. - * - * 3. Altered versions must be plainly marked as such, and must not be - * misrepresented as being the original software. Since few users ever read - * sources, credits must appear in the documentation. - * - * 4. This notice may not be removed or altered. - * ------------------------------------------------------------------------- - * - * For compliance with Mr Darwin's terms: this has been very significantly - * modified from the free "file" command. - * - all-in-one file for compilation convenience when moving from one - * version of Apache to the next. - * - Memory allocation is done through the Apache API's apr_pool_t structure. - * - All functions have had necessary Apache API request or server - * structures passed to them where necessary to call other Apache API - * routines. (i.e. usually for logging, files, or memory allocation in - * itself or a called function.) - * - struct magic has been converted from an array to a single-ended linked - * list because it only grows one record at a time, it's only accessed - * sequentially, and the Apache API has no equivalent of realloc(). - * - Functions have been changed to get their parameters from the server - * configuration instead of globals. (It should be reentrant now but has - * not been tested in a threaded environment.) - * - Places where it used to print results to stdout now saves them in a - * list where they're used to set the MIME type in the Apache request - * record. - * - Command-line flags have been removed since they will never be used here. - * - * Ian Kluft <ikluft@cisco.com> - * Engineering Information Framework - * Central Engineering - * Cisco Systems, Inc. - * San Jose, CA, USA - * - * Initial installation July/August 1996 - * Misc bug fixes May 1997 - * Submission to Apache Software Foundation July 1997 - * - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_lib.h" -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_log.h" -#include "http_protocol.h" -#include "util_script.h" - -/* ### this isn't set by configure? does anybody set this? */ -#ifdef HAVE_UTIME_H -#include <utime.h> -#endif - -/* - * data structures and related constants - */ - -#define MODNAME "mod_mime_magic" -#define MIME_MAGIC_DEBUG 0 - -#define MIME_BINARY_UNKNOWN "application/octet-stream" -#define MIME_TEXT_UNKNOWN "text/plain" - -#define MAXMIMESTRING 256 - -/* HOWMANY must be at least 4096 to make gzip -dcq work */ -#define HOWMANY 4096 -/* SMALL_HOWMANY limits how much work we do to figure out text files */ -#define SMALL_HOWMANY 1024 -#define MAXDESC 50 /* max leng of text description */ -#define MAXstring 64 /* max leng of "string" types */ - -struct magic { - struct magic *next; /* link to next entry */ - int lineno; /* line number from magic file */ - - short flag; -#define INDIR 1 /* if '>(...)' appears, */ -#define UNSIGNED 2 /* comparison is unsigned */ - short cont_level; /* level of ">" */ - struct { - char type; /* byte short long */ - long offset; /* offset from indirection */ - } in; - long offset; /* offset to magic number */ - unsigned char reln; /* relation (0=eq, '>'=gt, etc) */ - char type; /* int, short, long or string. */ - char vallen; /* length of string value, if any */ -#define BYTE 1 -#define SHORT 2 -#define LONG 4 -#define STRING 5 -#define DATE 6 -#define BESHORT 7 -#define BELONG 8 -#define BEDATE 9 -#define LESHORT 10 -#define LELONG 11 -#define LEDATE 12 - union VALUETYPE { - unsigned char b; - unsigned short h; - unsigned long l; - char s[MAXstring]; - unsigned char hs[2]; /* 2 bytes of a fixed-endian "short" */ - unsigned char hl[4]; /* 2 bytes of a fixed-endian "long" */ - } value; /* either number or string */ - unsigned long mask; /* mask before comparison with value */ - char nospflag; /* supress space character */ - - /* NOTE: this string is suspected of overrunning - find it! */ - char desc[MAXDESC]; /* description */ -}; - -/* - * data structures for tar file recognition - * -------------------------------------------------------------------------- - * Header file for public domain tar (tape archive) program. - * - * @(#)tar.h 1.20 86/10/29 Public Domain. Created 25 August 1985 by John - * Gilmore, ihnp4!hoptoad!gnu. - * - * Header block on tape. - * - * I'm going to use traditional DP naming conventions here. A "block" is a big - * chunk of stuff that we do I/O on. A "record" is a piece of info that we - * care about. Typically many "record"s fit into a "block". - */ -#define RECORDSIZE 512 -#define NAMSIZ 100 -#define TUNMLEN 32 -#define TGNMLEN 32 - -union record { - char charptr[RECORDSIZE]; - struct header { - char name[NAMSIZ]; - char mode[8]; - char uid[8]; - char gid[8]; - char size[12]; - char mtime[12]; - char chksum[8]; - char linkflag; - char linkname[NAMSIZ]; - char magic[8]; - char uname[TUNMLEN]; - char gname[TGNMLEN]; - char devmajor[8]; - char devminor[8]; - } header; -}; - -/* The magic field is filled with this if uname and gname are valid. */ -#define TMAGIC "ustar " /* 7 chars and a null */ - -/* - * file-function prototypes - */ -static int ascmagic(request_rec *, unsigned char *, apr_size_t); -static int is_tar(unsigned char *, apr_size_t); -static int softmagic(request_rec *, unsigned char *, apr_size_t); -static void tryit(request_rec *, unsigned char *, apr_size_t, int); -static int zmagic(request_rec *, unsigned char *, apr_size_t); - -static int getvalue(server_rec *, struct magic *, char **); -static int hextoint(int); -static char *getstr(server_rec *, char *, char *, int, int *); -static int parse(server_rec *, apr_pool_t *p, char *, int); - -static int match(request_rec *, unsigned char *, apr_size_t); -static int mget(request_rec *, union VALUETYPE *, unsigned char *, - struct magic *, apr_size_t); -static int mcheck(request_rec *, union VALUETYPE *, struct magic *); -static void mprint(request_rec *, union VALUETYPE *, struct magic *); - -static int uncompress(request_rec *, int, - unsigned char **, apr_size_t); -static long from_oct(int, char *); -static int fsmagic(request_rec *r, const char *fn); - -/* - * includes for ASCII substring recognition formerly "names.h" in file - * command - * - * Original notes: names and types used by ascmagic in file(1). These tokens are - * here because they can appear anywhere in the first HOWMANY bytes, while - * tokens in /etc/magic must appear at fixed offsets into the file. Don't - * make HOWMANY too high unless you have a very fast CPU. - */ - -/* these types are used to index the apr_table_t 'types': keep em in sync! */ -/* HTML inserted in first because this is a web server module now */ -#define L_HTML 0 /* HTML */ -#define L_C 1 /* first and foremost on UNIX */ -#define L_FORT 2 /* the oldest one */ -#define L_MAKE 3 /* Makefiles */ -#define L_PLI 4 /* PL/1 */ -#define L_MACH 5 /* some kinda assembler */ -#define L_ENG 6 /* English */ -#define L_PAS 7 /* Pascal */ -#define L_MAIL 8 /* Electronic mail */ -#define L_NEWS 9 /* Usenet Netnews */ - -static char *types[] = -{ - "text/html", /* HTML */ - "text/plain", /* "c program text", */ - "text/plain", /* "fortran program text", */ - "text/plain", /* "make commands text", */ - "text/plain", /* "pl/1 program text", */ - "text/plain", /* "assembler program text", */ - "text/plain", /* "English text", */ - "text/plain", /* "pascal program text", */ - "message/rfc822", /* "mail text", */ - "message/news", /* "news text", */ - "application/binary", /* "can't happen error on names.h/types", */ - 0 -}; - -static struct names { - char *name; - short type; -} names[] = { - - /* These must be sorted by eye for optimal hit rate */ - /* Add to this list only after substantial meditation */ - { - "<html>", L_HTML - }, - { - "<HTML>", L_HTML - }, - { - "<head>", L_HTML - }, - { - "<HEAD>", L_HTML - }, - { - "<title>", L_HTML - }, - { - "<TITLE>", L_HTML - }, - { - "<h1>", L_HTML - }, - { - "<H1>", L_HTML - }, - { - "<!--", L_HTML - }, - { - "<!DOCTYPE HTML", L_HTML - }, - { - "/*", L_C - }, /* must precede "The", "the", etc. */ - { - "#include", L_C - }, - { - "char", L_C - }, - { - "The", L_ENG - }, - { - "the", L_ENG - }, - { - "double", L_C - }, - { - "extern", L_C - }, - { - "float", L_C - }, - { - "real", L_C - }, - { - "struct", L_C - }, - { - "union", L_C - }, - { - "CFLAGS", L_MAKE - }, - { - "LDFLAGS", L_MAKE - }, - { - "all:", L_MAKE - }, - { - ".PRECIOUS", L_MAKE - }, - /* - * Too many files of text have these words in them. Find another way to - * recognize Fortrash. - */ -#ifdef NOTDEF - { - "subroutine", L_FORT - }, - { - "function", L_FORT - }, - { - "block", L_FORT - }, - { - "common", L_FORT - }, - { - "dimension", L_FORT - }, - { - "integer", L_FORT - }, - { - "data", L_FORT - }, -#endif /* NOTDEF */ - { - ".ascii", L_MACH - }, - { - ".asciiz", L_MACH - }, - { - ".byte", L_MACH - }, - { - ".even", L_MACH - }, - { - ".globl", L_MACH - }, - { - "clr", L_MACH - }, - { - "(input,", L_PAS - }, - { - "dcl", L_PLI - }, - { - "Received:", L_MAIL - }, - { - ">From", L_MAIL - }, - { - "Return-Path:", L_MAIL - }, - { - "Cc:", L_MAIL - }, - { - "Newsgroups:", L_NEWS - }, - { - "Path:", L_NEWS - }, - { - "Organization:", L_NEWS - }, - { - NULL, 0 - } -}; - -#define NNAMES ((sizeof(names)/sizeof(struct names)) - 1) - -/* - * Result String List (RSL) - * - * The file(1) command prints its output. Instead, we store the various - * "printed" strings in a list (allocating memory as we go) and concatenate - * them at the end when we finally know how much space they'll need. - */ - -typedef struct magic_rsl_s { - char *str; /* string, possibly a fragment */ - struct magic_rsl_s *next; /* pointer to next fragment */ -} magic_rsl; - -/* - * Apache module configuration structures - */ - -/* per-server info */ -typedef struct { - const char *magicfile; /* where magic be found */ - struct magic *magic; /* head of magic config list */ - struct magic *last; -} magic_server_config_rec; - -/* per-request info */ -typedef struct { - magic_rsl *head; /* result string list */ - magic_rsl *tail; - unsigned suf_recursion; /* recursion depth in suffix check */ -} magic_req_rec; - -/* - * configuration functions - called by Apache API routines - */ - -module mime_magic_module; - -static void *create_magic_server_config(apr_pool_t *p, server_rec *d) -{ - /* allocate the config - use pcalloc because it needs to be zeroed */ - return apr_pcalloc(p, sizeof(magic_server_config_rec)); -} - -static void *merge_magic_server_config(apr_pool_t *p, void *basev, void *addv) -{ - magic_server_config_rec *base = (magic_server_config_rec *) basev; - magic_server_config_rec *add = (magic_server_config_rec *) addv; - magic_server_config_rec *new = (magic_server_config_rec *) - apr_palloc(p, sizeof(magic_server_config_rec)); - - new->magicfile = add->magicfile ? add->magicfile : base->magicfile; - new->magic = NULL; - new->last = NULL; - return new; -} - -static const char *set_magicfile(cmd_parms *cmd, void *dummy, const char *arg) -{ - magic_server_config_rec *conf = (magic_server_config_rec *) - ap_get_module_config(cmd->server->module_config, - &mime_magic_module); - - if (!conf) { - return MODNAME ": server structure not allocated"; - } - conf->magicfile = arg; - return NULL; -} - -/* - * configuration file commands - exported to Apache API - */ - -static const command_rec mime_magic_cmds[] = -{ - AP_INIT_TAKE1("MimeMagicFile", set_magicfile, NULL, RSRC_CONF, - "Path to MIME Magic file (in file(1) format)"), - {NULL} -}; - -/* - * RSL (result string list) processing routines - * - * These collect strings that would have been printed in fragments by file(1) - * into a list of magic_rsl structures with the strings. When complete, - * they're concatenated together to become the MIME content and encoding - * types. - * - * return value conventions for these functions: functions which return int: - * failure = -1, other = result functions which return pointers: failure = 0, - * other = result - */ - -/* allocate a per-request structure and put it in the request record */ -static magic_req_rec *magic_set_config(request_rec *r) -{ - magic_req_rec *req_dat = (magic_req_rec *) apr_palloc(r->pool, - sizeof(magic_req_rec)); - - req_dat->head = req_dat->tail = (magic_rsl *) NULL; - ap_set_module_config(r->request_config, &mime_magic_module, req_dat); - return req_dat; -} - -/* add a string to the result string list for this request */ -/* it is the responsibility of the caller to allocate "str" */ -static int magic_rsl_add(request_rec *r, char *str) -{ - magic_req_rec *req_dat = (magic_req_rec *) - ap_get_module_config(r->request_config, &mime_magic_module); - magic_rsl *rsl; - - /* make sure we have a list to put it in */ - if (!req_dat) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, APR_EINVAL, r, - MODNAME ": request config should not be NULL"); - if (!(req_dat = magic_set_config(r))) { - /* failure */ - return -1; - } - } - - /* allocate the list entry */ - rsl = (magic_rsl *) apr_palloc(r->pool, sizeof(magic_rsl)); - - /* fill it */ - rsl->str = str; - rsl->next = (magic_rsl *) NULL; - - /* append to the list */ - if (req_dat->head && req_dat->tail) { - req_dat->tail->next = rsl; - req_dat->tail = rsl; - } - else { - req_dat->head = req_dat->tail = rsl; - } - - /* success */ - return 0; -} - -/* RSL hook for puts-type functions */ -static int magic_rsl_puts(request_rec *r, char *str) -{ - return magic_rsl_add(r, str); -} - -/* RSL hook for printf-type functions */ -static int magic_rsl_printf(request_rec *r, char *str,...) -{ - va_list ap; - - char buf[MAXMIMESTRING]; - - /* assemble the string into the buffer */ - va_start(ap, str); - apr_vsnprintf(buf, sizeof(buf), str, ap); - va_end(ap); - - /* add the buffer to the list */ - return magic_rsl_add(r, strdup(buf)); -} - -/* RSL hook for putchar-type functions */ -static int magic_rsl_putchar(request_rec *r, char c) -{ - char str[2]; - - /* high overhead for 1 char - just hope they don't do this much */ - str[0] = c; - str[1] = '\0'; - return magic_rsl_add(r, str); -} - -/* allocate and copy a contiguous string from a result string list */ -static char *rsl_strdup(request_rec *r, int start_frag, int start_pos, int len) -{ - char *result; /* return value */ - int cur_frag, /* current fragment number/counter */ - cur_pos, /* current position within fragment */ - res_pos; /* position in result string */ - magic_rsl *frag; /* list-traversal pointer */ - magic_req_rec *req_dat = (magic_req_rec *) - ap_get_module_config(r->request_config, &mime_magic_module); - - /* allocate the result string */ - result = (char *) apr_palloc(r->pool, len + 1); - - /* loop through and collect the string */ - res_pos = 0; - for (frag = req_dat->head, cur_frag = 0; - frag->next; - frag = frag->next, cur_frag++) { - /* loop to the first fragment */ - if (cur_frag < start_frag) - continue; - - /* loop through and collect chars */ - for (cur_pos = (cur_frag == start_frag) ? start_pos : 0; - frag->str[cur_pos]; - cur_pos++) { - if (cur_frag >= start_frag - && cur_pos >= start_pos - && res_pos <= len) { - result[res_pos++] = frag->str[cur_pos]; - if (res_pos > len) { - break; - } - } - } - } - - /* clean up and return */ - result[res_pos] = 0; -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - MODNAME ": rsl_strdup() %d chars: %s", res_pos - 1, result); -#endif - return result; -} - -/* states for the state-machine algorithm in magic_rsl_to_request() */ -typedef enum { - rsl_leading_space, rsl_type, rsl_subtype, rsl_separator, rsl_encoding -} rsl_states; - -/* process the RSL and set the MIME info in the request record */ -static int magic_rsl_to_request(request_rec *r) -{ - int cur_frag, /* current fragment number/counter */ - cur_pos, /* current position within fragment */ - type_frag, /* content type starting point: fragment */ - type_pos, /* content type starting point: position */ - type_len, /* content type length */ - encoding_frag, /* content encoding starting point: fragment */ - encoding_pos, /* content encoding starting point: position */ - encoding_len; /* content encoding length */ - - magic_rsl *frag; /* list-traversal pointer */ - rsl_states state; - - magic_req_rec *req_dat = (magic_req_rec *) - ap_get_module_config(r->request_config, &mime_magic_module); - - /* check if we have a result */ - if (!req_dat || !req_dat->head) { - /* empty - no match, we defer to other Apache modules */ - return DECLINED; - } - - /* start searching for the type and encoding */ - state = rsl_leading_space; - type_frag = type_pos = type_len = 0; - encoding_frag = encoding_pos = encoding_len = 0; - for (frag = req_dat->head, cur_frag = 0; - frag && frag->next; - frag = frag->next, cur_frag++) { - /* loop through the characters in the fragment */ - for (cur_pos = 0; frag->str[cur_pos]; cur_pos++) { - if (apr_isspace(frag->str[cur_pos])) { - /* process whitespace actions for each state */ - if (state == rsl_leading_space) { - /* eat whitespace in this state */ - continue; - } - else if (state == rsl_type) { - /* whitespace: type has no slash! */ - return DECLINED; - } - else if (state == rsl_subtype) { - /* whitespace: end of MIME type */ - state++; - continue; - } - else if (state == rsl_separator) { - /* eat whitespace in this state */ - continue; - } - else if (state == rsl_encoding) { - /* whitespace: end of MIME encoding */ - /* we're done */ - frag = req_dat->tail; - break; - } - else { - /* should not be possible */ - /* abandon malfunctioning module */ - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, - MODNAME ": bad state %d (ws)", state); - return DECLINED; - } - /* NOTREACHED */ - } - else if (state == rsl_type && - frag->str[cur_pos] == '/') { - /* copy the char and go to rsl_subtype state */ - type_len++; - state++; - } - else { - /* process non-space actions for each state */ - if (state == rsl_leading_space) { - /* non-space: begin MIME type */ - state++; - type_frag = cur_frag; - type_pos = cur_pos; - type_len = 1; - continue; - } - else if (state == rsl_type || - state == rsl_subtype) { - /* non-space: adds to type */ - type_len++; - continue; - } - else if (state == rsl_separator) { - /* non-space: begin MIME encoding */ - state++; - encoding_frag = cur_frag; - encoding_pos = cur_pos; - encoding_len = 1; - continue; - } - else if (state == rsl_encoding) { - /* non-space: adds to encoding */ - encoding_len++; - continue; - } - else { - /* should not be possible */ - /* abandon malfunctioning module */ - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, - MODNAME ": bad state %d (ns)", state); - return DECLINED; - } - /* NOTREACHED */ - } - /* NOTREACHED */ - } - } - - /* if we ended prior to state rsl_subtype, we had incomplete info */ - if (state != rsl_subtype && state != rsl_separator && - state != rsl_encoding) { - /* defer to other modules */ - return DECLINED; - } - - /* save the info in the request record */ - if (state == rsl_subtype || state == rsl_encoding || - state == rsl_encoding) { - char *tmp; - tmp = rsl_strdup(r, type_frag, type_pos, type_len); - /* XXX: this could be done at config time I'm sure... but I'm - * confused by all this magic_rsl stuff. -djg */ - ap_content_type_tolower(tmp); - r->content_type = tmp; - } - if (state == rsl_encoding) { - char *tmp; - tmp = rsl_strdup(r, encoding_frag, - encoding_pos, encoding_len); - /* XXX: this could be done at config time I'm sure... but I'm - * confused by all this magic_rsl stuff. -djg */ - ap_str_tolower(tmp); - r->content_encoding = tmp; - } - - /* detect memory allocation errors */ - if (!r->content_type || - (state == rsl_encoding && !r->content_encoding)) { - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* success! */ - return OK; -} - -/* - * magic_process - process input file r Apache API request record - * (formerly called "process" in file command, prefix added for clarity) Opens - * the file and reads a fixed-size buffer to begin processing the contents. - */ -static int magic_process(request_rec *r) -{ - apr_file_t *fd = NULL; - unsigned char buf[HOWMANY + 1]; /* one extra for terminating '\0' */ - apr_size_t nbytes = 0; /* number of bytes read from a datafile */ - int result; - - /* - * first try judging the file based on its filesystem status - */ - switch ((result = fsmagic(r, r->filename))) { - case DONE: - magic_rsl_putchar(r, '\n'); - return OK; - case OK: - break; - default: - /* fatal error, bail out */ - return result; - } - - if (apr_file_open(&fd, r->filename, APR_READ, APR_OS_DEFAULT, r->pool) != APR_SUCCESS) { - /* We can't open it, but we were able to stat it. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - MODNAME ": can't read `%s'", r->filename); - /* let some other handler decide what the problem is */ - return DECLINED; - } - - /* - * try looking at the first HOWMANY bytes - */ - nbytes = sizeof(buf) - 1; - if ((result = apr_file_read(fd, (char *) buf, &nbytes)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, result, r, - MODNAME ": read failed: %s", r->filename); - return HTTP_INTERNAL_SERVER_ERROR; - } - - if (nbytes == 0) - magic_rsl_puts(r, MIME_TEXT_UNKNOWN); - else { - buf[nbytes++] = '\0'; /* null-terminate it */ - tryit(r, buf, nbytes, 1); - } - - (void) apr_file_close(fd); - (void) magic_rsl_putchar(r, '\n'); - - return OK; -} - - -static void tryit(request_rec *r, unsigned char *buf, apr_size_t nb, int checkzmagic) -{ - /* - * Try compression stuff - */ - if (checkzmagic == 1) { - if (zmagic(r, buf, nb) == 1) - return; - } - - /* - * try tests in /etc/magic (or surrogate magic file) - */ - if (softmagic(r, buf, nb) == 1) - return; - - /* - * try known keywords, check for ascii-ness too. - */ - if (ascmagic(r, buf, nb) == 1) - return; - - /* - * abandon hope, all ye who remain here - */ - magic_rsl_puts(r, MIME_BINARY_UNKNOWN); -} - -#define EATAB {while (apr_isspace((unsigned char) *l)) ++l;} - -/* - * apprentice - load configuration from the magic file r - * API request record - */ -static int apprentice(server_rec *s, apr_pool_t *p) -{ - apr_file_t *f = NULL; - apr_status_t result; - char line[BUFSIZ + 1]; - int errs = 0; - int lineno; -#if MIME_MAGIC_DEBUG - int rule = 0; - struct magic *m, *prevm; -#endif - magic_server_config_rec *conf = (magic_server_config_rec *) - ap_get_module_config(s->module_config, &mime_magic_module); - - const char *fname = ap_server_root_relative(p, conf->magicfile); - result = apr_file_open(&f, fname, APR_READ | APR_BUFFERED, APR_OS_DEFAULT, p); - if (result != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, result, s, - MODNAME ": can't read magic file %s", fname); - return -1; - } - - /* set up the magic list (empty) */ - conf->magic = conf->last = NULL; - - /* parse it */ - for (lineno = 1; apr_file_gets(line, BUFSIZ, f) == APR_SUCCESS; lineno++) { - int ws_offset; - - /* delete newline */ - if (line[0]) { - line[strlen(line) - 1] = '\0'; - } - - /* skip leading whitespace */ - ws_offset = 0; - while (line[ws_offset] && apr_isspace(line[ws_offset])) { - ws_offset++; - } - - /* skip blank lines */ - if (line[ws_offset] == 0) { - continue; - } - - /* comment, do not parse */ - if (line[ws_offset] == '#') - continue; - -#if MIME_MAGIC_DEBUG - /* if we get here, we're going to use it so count it */ - rule++; -#endif - - /* parse it */ - if (parse(s, p, line + ws_offset, lineno) != 0) - ++errs; - } - - (void) apr_file_close(f); - -#if MIME_MAGIC_DEBUG - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s, - MODNAME ": apprentice conf=%x file=%s m=%s m->next=%s last=%s", - conf, - conf->magicfile ? conf->magicfile : "NULL", - conf->magic ? "set" : "NULL", - (conf->magic && conf->magic->next) ? "set" : "NULL", - conf->last ? "set" : "NULL"); - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s, - MODNAME ": apprentice read %d lines, %d rules, %d errors", - lineno, rule, errs); -#endif - -#if MIME_MAGIC_DEBUG - prevm = 0; - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s, - MODNAME ": apprentice test"); - for (m = conf->magic; m; m = m->next) { - if (apr_isprint((((unsigned long) m) >> 24) & 255) && - apr_isprint((((unsigned long) m) >> 16) & 255) && - apr_isprint((((unsigned long) m) >> 8) & 255) && - apr_isprint(((unsigned long) m) & 255)) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s, - MODNAME ": apprentice: POINTER CLOBBERED! " - "m=\"%c%c%c%c\" line=%d", - (((unsigned long) m) >> 24) & 255, - (((unsigned long) m) >> 16) & 255, - (((unsigned long) m) >> 8) & 255, - ((unsigned long) m) & 255, - prevm ? prevm->lineno : -1); - break; - } - prevm = m; - } -#endif - - return (errs ? -1 : 0); -} - -/* - * extend the sign bit if the comparison is to be signed - */ -static unsigned long signextend(server_rec *s, struct magic *m, unsigned long v) -{ - if (!(m->flag & UNSIGNED)) - switch (m->type) { - /* - * Do not remove the casts below. They are vital. When later - * compared with the data, the sign extension must have happened. - */ - case BYTE: - v = (char) v; - break; - case SHORT: - case BESHORT: - case LESHORT: - v = (short) v; - break; - case DATE: - case BEDATE: - case LEDATE: - case LONG: - case BELONG: - case LELONG: - v = (long) v; - break; - case STRING: - break; - default: - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, s, - MODNAME ": can't happen: m->type=%d", m->type); - return -1; - } - return v; -} - -/* - * parse one line from magic file, put into magic[index++] if valid - */ -static int parse(server_rec *serv, apr_pool_t *p, char *l, int lineno) -{ - struct magic *m; - char *t, *s; - magic_server_config_rec *conf = (magic_server_config_rec *) - ap_get_module_config(serv->module_config, &mime_magic_module); - - /* allocate magic structure entry */ - m = (struct magic *) apr_pcalloc(p, sizeof(struct magic)); - - /* append to linked list */ - m->next = NULL; - if (!conf->magic || !conf->last) { - conf->magic = conf->last = m; - } - else { - conf->last->next = m; - conf->last = m; - } - - /* set values in magic structure */ - m->flag = 0; - m->cont_level = 0; - m->lineno = lineno; - - while (*l == '>') { - ++l; /* step over */ - m->cont_level++; - } - - if (m->cont_level != 0 && *l == '(') { - ++l; /* step over */ - m->flag |= INDIR; - } - - /* get offset, then skip over it */ - m->offset = (int) strtol(l, &t, 0); - if (l == t) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, serv, - MODNAME ": offset %s invalid", l); - } - l = t; - - if (m->flag & INDIR) { - m->in.type = LONG; - m->in.offset = 0; - /* - * read [.lbs][+-]nnnnn) - */ - if (*l == '.') { - switch (*++l) { - case 'l': - m->in.type = LONG; - break; - case 's': - m->in.type = SHORT; - break; - case 'b': - m->in.type = BYTE; - break; - default: - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, serv, - MODNAME ": indirect offset type %c invalid", *l); - break; - } - l++; - } - s = l; - if (*l == '+' || *l == '-') - l++; - if (apr_isdigit((unsigned char) *l)) { - m->in.offset = strtol(l, &t, 0); - if (*s == '-') - m->in.offset = -m->in.offset; - } - else - t = l; - if (*t++ != ')') { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, serv, - MODNAME ": missing ')' in indirect offset"); - } - l = t; - } - - - while (apr_isdigit((unsigned char) *l)) - ++l; - EATAB; - -#define NBYTE 4 -#define NSHORT 5 -#define NLONG 4 -#define NSTRING 6 -#define NDATE 4 -#define NBESHORT 7 -#define NBELONG 6 -#define NBEDATE 6 -#define NLESHORT 7 -#define NLELONG 6 -#define NLEDATE 6 - - if (*l == 'u') { - ++l; - m->flag |= UNSIGNED; - } - - /* get type, skip it */ - if (strncmp(l, "byte", NBYTE) == 0) { - m->type = BYTE; - l += NBYTE; - } - else if (strncmp(l, "short", NSHORT) == 0) { - m->type = SHORT; - l += NSHORT; - } - else if (strncmp(l, "long", NLONG) == 0) { - m->type = LONG; - l += NLONG; - } - else if (strncmp(l, "string", NSTRING) == 0) { - m->type = STRING; - l += NSTRING; - } - else if (strncmp(l, "date", NDATE) == 0) { - m->type = DATE; - l += NDATE; - } - else if (strncmp(l, "beshort", NBESHORT) == 0) { - m->type = BESHORT; - l += NBESHORT; - } - else if (strncmp(l, "belong", NBELONG) == 0) { - m->type = BELONG; - l += NBELONG; - } - else if (strncmp(l, "bedate", NBEDATE) == 0) { - m->type = BEDATE; - l += NBEDATE; - } - else if (strncmp(l, "leshort", NLESHORT) == 0) { - m->type = LESHORT; - l += NLESHORT; - } - else if (strncmp(l, "lelong", NLELONG) == 0) { - m->type = LELONG; - l += NLELONG; - } - else if (strncmp(l, "ledate", NLEDATE) == 0) { - m->type = LEDATE; - l += NLEDATE; - } - else { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, serv, - MODNAME ": type %s invalid", l); - return -1; - } - /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */ - if (*l == '&') { - ++l; - m->mask = signextend(serv, m, strtol(l, &l, 0)); - } - else - m->mask = ~0L; - EATAB; - - switch (*l) { - case '>': - case '<': - /* Old-style anding: "0 byte &0x80 dynamically linked" */ - case '&': - case '^': - case '=': - m->reln = *l; - ++l; - break; - case '!': - if (m->type != STRING) { - m->reln = *l; - ++l; - break; - } - /* FALL THROUGH */ - default: - if (*l == 'x' && apr_isspace((unsigned char) l[1])) { - m->reln = *l; - ++l; - goto GetDesc; /* Bill The Cat */ - } - m->reln = '='; - break; - } - EATAB; - - if (getvalue(serv, m, &l)) - return -1; - /* - * now get last part - the description - */ - GetDesc: - EATAB; - if (l[0] == '\b') { - ++l; - m->nospflag = 1; - } - else if ((l[0] == '\\') && (l[1] == 'b')) { - ++l; - ++l; - m->nospflag = 1; - } - else - m->nospflag = 0; - strncpy(m->desc, l, sizeof(m->desc) - 1); - m->desc[sizeof(m->desc) - 1] = '\0'; - -#if MIME_MAGIC_DEBUG - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, serv, - MODNAME ": parse line=%d m=%x next=%x cont=%d desc=%s", - lineno, m, m->next, m->cont_level, m->desc); -#endif /* MIME_MAGIC_DEBUG */ - - return 0; -} - -/* - * Read a numeric value from a pointer, into the value union of a magic - * pointer, according to the magic type. Update the string pointer to point - * just after the number read. Return 0 for success, non-zero for failure. - */ -static int getvalue(server_rec *s, struct magic *m, char **p) -{ - int slen; - - if (m->type == STRING) { - *p = getstr(s, *p, m->value.s, sizeof(m->value.s), &slen); - m->vallen = slen; - } - else if (m->reln != 'x') - m->value.l = signextend(s, m, strtol(*p, p, 0)); - return 0; -} - -/* - * Convert a string containing C character escapes. Stop at an unescaped - * space or tab. Copy the converted version to "p", returning its length in - * *slen. Return updated scan pointer as function result. - */ -static char *getstr(server_rec *serv, register char *s, register char *p, - int plen, int *slen) -{ - char *origs = s, *origp = p; - char *pmax = p + plen - 1; - register int c; - register int val; - - while ((c = *s++) != '\0') { - if (apr_isspace((unsigned char) c)) - break; - if (p >= pmax) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, serv, - MODNAME ": string too long: %s", origs); - break; - } - if (c == '\\') { - switch (c = *s++) { - - case '\0': - goto out; - - default: - *p++ = (char) c; - break; - - case 'n': - *p++ = '\n'; - break; - - case 'r': - *p++ = '\r'; - break; - - case 'b': - *p++ = '\b'; - break; - - case 't': - *p++ = '\t'; - break; - - case 'f': - *p++ = '\f'; - break; - - case 'v': - *p++ = '\v'; - break; - - /* \ and up to 3 octal digits */ - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - val = c - '0'; - c = *s++; /* try for 2 */ - if (c >= '0' && c <= '7') { - val = (val << 3) | (c - '0'); - c = *s++; /* try for 3 */ - if (c >= '0' && c <= '7') - val = (val << 3) | (c - '0'); - else - --s; - } - else - --s; - *p++ = (char) val; - break; - - /* \x and up to 3 hex digits */ - case 'x': - val = 'x'; /* Default if no digits */ - c = hextoint(*s++); /* Get next char */ - if (c >= 0) { - val = c; - c = hextoint(*s++); - if (c >= 0) { - val = (val << 4) + c; - c = hextoint(*s++); - if (c >= 0) { - val = (val << 4) + c; - } - else - --s; - } - else - --s; - } - else - --s; - *p++ = (char) val; - break; - } - } - else - *p++ = (char) c; - } - out: - *p = '\0'; - *slen = p - origp; - return s; -} - - -/* Single hex char to int; -1 if not a hex char. */ -static int hextoint(int c) -{ - if (apr_isdigit((unsigned char) c)) - return c - '0'; - if ((c >= 'a') && (c <= 'f')) - return c + 10 - 'a'; - if ((c >= 'A') && (c <= 'F')) - return c + 10 - 'A'; - return -1; -} - - -/* - * return DONE to indicate it's been handled - * return OK to indicate it's a regular file still needing handling - * other returns indicate a failure of some sort - */ -static int fsmagic(request_rec *r, const char *fn) -{ - switch (r->finfo.filetype) { - case APR_DIR: - magic_rsl_puts(r, DIR_MAGIC_TYPE); - return DONE; - case APR_CHR: - /* - * (void) magic_rsl_printf(r,"character special (%d/%d)", - * major(sb->st_rdev), minor(sb->st_rdev)); - */ - (void) magic_rsl_puts(r, MIME_BINARY_UNKNOWN); - return DONE; - case APR_BLK: - /* - * (void) magic_rsl_printf(r,"block special (%d/%d)", - * major(sb->st_rdev), minor(sb->st_rdev)); - */ - (void) magic_rsl_puts(r, MIME_BINARY_UNKNOWN); - return DONE; - /* TODO add code to handle V7 MUX and Blit MUX files */ - case APR_PIPE: - /* - * magic_rsl_puts(r,"fifo (named pipe)"); - */ - (void) magic_rsl_puts(r, MIME_BINARY_UNKNOWN); - return DONE; - case APR_LNK: - /* We used stat(), the only possible reason for this is that the - * symlink is broken. - */ - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, - MODNAME ": broken symlink (%s)", fn); - return HTTP_INTERNAL_SERVER_ERROR; - case APR_SOCK: - magic_rsl_puts(r, MIME_BINARY_UNKNOWN); - return DONE; - case APR_REG: - break; - default: - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, - MODNAME ": invalid file type %d.", r->finfo.filetype); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* - * regular file, check next possibility - */ - if (r->finfo.size == 0) { - magic_rsl_puts(r, MIME_TEXT_UNKNOWN); - return DONE; - } - return OK; -} - -/* - * softmagic - lookup one file in database (already read from /etc/magic by - * apprentice.c). Passed the name and FILE * of one file to be typed. - */ - /* ARGSUSED1 *//* nbytes passed for regularity, maybe need later */ -static int softmagic(request_rec *r, unsigned char *buf, apr_size_t nbytes) -{ - if (match(r, buf, nbytes)) - return 1; - - return 0; -} - -/* - * Go through the whole list, stopping if you find a match. Process all the - * continuations of that match before returning. - * - * We support multi-level continuations: - * - * At any time when processing a successful top-level match, there is a current - * continuation level; it represents the level of the last successfully - * matched continuation. - * - * Continuations above that level are skipped as, if we see one, it means that - * the continuation that controls them - i.e, the lower-level continuation - * preceding them - failed to match. - * - * Continuations below that level are processed as, if we see one, it means - * we've finished processing or skipping higher-level continuations under the - * control of a successful or unsuccessful lower-level continuation, and are - * now seeing the next lower-level continuation and should process it. The - * current continuation level reverts to the level of the one we're seeing. - * - * Continuations at the current level are processed as, if we see one, there's - * no lower-level continuation that may have failed. - * - * If a continuation matches, we bump the current continuation level so that - * higher-level continuations are processed. - */ -static int match(request_rec *r, unsigned char *s, apr_size_t nbytes) -{ -#if MIME_MAGIC_DEBUG - int rule_counter = 0; -#endif - int cont_level = 0; - int need_separator = 0; - union VALUETYPE p; - magic_server_config_rec *conf = (magic_server_config_rec *) - ap_get_module_config(r->server->module_config, &mime_magic_module); - struct magic *m; - -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - MODNAME ": match conf=%x file=%s m=%s m->next=%s last=%s", - conf, - conf->magicfile ? conf->magicfile : "NULL", - conf->magic ? "set" : "NULL", - (conf->magic && conf->magic->next) ? "set" : "NULL", - conf->last ? "set" : "NULL"); -#endif - -#if MIME_MAGIC_DEBUG - for (m = conf->magic; m; m = m->next) { - if (apr_isprint((((unsigned long) m) >> 24) & 255) && - apr_isprint((((unsigned long) m) >> 16) & 255) && - apr_isprint((((unsigned long) m) >> 8) & 255) && - apr_isprint(((unsigned long) m) & 255)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - MODNAME ": match: POINTER CLOBBERED! " - "m=\"%c%c%c%c\"", - (((unsigned long) m) >> 24) & 255, - (((unsigned long) m) >> 16) & 255, - (((unsigned long) m) >> 8) & 255, - ((unsigned long) m) & 255); - break; - } - } -#endif - - for (m = conf->magic; m; m = m->next) { -#if MIME_MAGIC_DEBUG - rule_counter++; - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - MODNAME ": line=%d desc=%s", m->lineno, m->desc); -#endif - - /* check if main entry matches */ - if (!mget(r, &p, s, m, nbytes) || - !mcheck(r, &p, m)) { - struct magic *m_cont; - - /* - * main entry didn't match, flush its continuations - */ - if (!m->next || (m->next->cont_level == 0)) { - continue; - } - - m_cont = m->next; - while (m_cont && (m_cont->cont_level != 0)) { -#if MIME_MAGIC_DEBUG - rule_counter++; - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - MODNAME ": line=%d mc=%x mc->next=%x cont=%d desc=%s", - m_cont->lineno, m_cont, - m_cont->next, m_cont->cont_level, - m_cont->desc); -#endif - /* - * this trick allows us to keep *m in sync when the continue - * advances the pointer - */ - m = m_cont; - m_cont = m_cont->next; - } - continue; - } - - /* if we get here, the main entry rule was a match */ - /* this will be the last run through the loop */ -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - MODNAME ": rule matched, line=%d type=%d %s", - m->lineno, m->type, - (m->type == STRING) ? m->value.s : ""); -#endif - - /* print the match */ - mprint(r, &p, m); - - /* - * If we printed something, we'll need to print a blank before we - * print something else. - */ - if (m->desc[0]) - need_separator = 1; - /* and any continuations that match */ - cont_level++; - /* - * while (m && m->next && m->next->cont_level != 0 && ( m = m->next - * )) - */ - m = m->next; - while (m && (m->cont_level != 0)) { -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - MODNAME ": match line=%d cont=%d type=%d %s", - m->lineno, m->cont_level, m->type, - (m->type == STRING) ? m->value.s : ""); -#endif - if (cont_level >= m->cont_level) { - if (cont_level > m->cont_level) { - /* - * We're at the end of the level "cont_level" - * continuations. - */ - cont_level = m->cont_level; - } - if (mget(r, &p, s, m, nbytes) && - mcheck(r, &p, m)) { - /* - * This continuation matched. Print its message, with a - * blank before it if the previous item printed and this - * item isn't empty. - */ - /* space if previous printed */ - if (need_separator - && (m->nospflag == 0) - && (m->desc[0] != '\0') - ) { - (void) magic_rsl_putchar(r, ' '); - need_separator = 0; - } - mprint(r, &p, m); - if (m->desc[0]) - need_separator = 1; - - /* - * If we see any continuations at a higher level, process - * them. - */ - cont_level++; - } - } - - /* move to next continuation record */ - m = m->next; - } -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - MODNAME ": matched after %d rules", rule_counter); -#endif - return 1; /* all through */ - } -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - MODNAME ": failed after %d rules", rule_counter); -#endif - return 0; /* no match at all */ -} - -static void mprint(request_rec *r, union VALUETYPE *p, struct magic *m) -{ - char *pp, *rt; - unsigned long v; - - switch (m->type) { - case BYTE: - v = p->b; - break; - - case SHORT: - case BESHORT: - case LESHORT: - v = p->h; - break; - - case LONG: - case BELONG: - case LELONG: - v = p->l; - break; - - case STRING: - if (m->reln == '=') { - (void) magic_rsl_printf(r, m->desc, m->value.s); - } - else { - (void) magic_rsl_printf(r, m->desc, p->s); - } - return; - - case DATE: - case BEDATE: - case LEDATE: - /* XXX: not multithread safe */ - pp = ctime((time_t *) & p->l); - if ((rt = strchr(pp, '\n')) != NULL) - *rt = '\0'; - (void) magic_rsl_printf(r, m->desc, pp); - return; - default: - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, - MODNAME ": invalid m->type (%d) in mprint().", - m->type); - return; - } - - v = signextend(r->server, m, v) & m->mask; - (void) magic_rsl_printf(r, m->desc, (unsigned long) v); -} - -/* - * Convert the byte order of the data we are looking at - */ -static int mconvert(request_rec *r, union VALUETYPE *p, struct magic *m) -{ - char *rt; - - switch (m->type) { - case BYTE: - case SHORT: - case LONG: - case DATE: - return 1; - case STRING: - /* Null terminate and eat the return */ - p->s[sizeof(p->s) - 1] = '\0'; - if ((rt = strchr(p->s, '\n')) != NULL) - *rt = '\0'; - return 1; - case BESHORT: - p->h = (short) ((p->hs[0] << 8) | (p->hs[1])); - return 1; - case BELONG: - case BEDATE: - p->l = (long) - ((p->hl[0] << 24) | (p->hl[1] << 16) | (p->hl[2] << 8) | (p->hl[3])); - return 1; - case LESHORT: - p->h = (short) ((p->hs[1] << 8) | (p->hs[0])); - return 1; - case LELONG: - case LEDATE: - p->l = (long) - ((p->hl[3] << 24) | (p->hl[2] << 16) | (p->hl[1] << 8) | (p->hl[0])); - return 1; - default: - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, - MODNAME ": invalid type %d in mconvert().", m->type); - return 0; - } -} - - -static int mget(request_rec *r, union VALUETYPE *p, unsigned char *s, - struct magic *m, apr_size_t nbytes) -{ - long offset = m->offset; - - if (offset + sizeof(union VALUETYPE) > nbytes) - return 0; - - memcpy(p, s + offset, sizeof(union VALUETYPE)); - - if (!mconvert(r, p, m)) - return 0; - - if (m->flag & INDIR) { - - switch (m->in.type) { - case BYTE: - offset = p->b + m->in.offset; - break; - case SHORT: - offset = p->h + m->in.offset; - break; - case LONG: - offset = p->l + m->in.offset; - break; - } - - if (offset + sizeof(union VALUETYPE) > nbytes) - return 0; - - memcpy(p, s + offset, sizeof(union VALUETYPE)); - - if (!mconvert(r, p, m)) - return 0; - } - return 1; -} - -static int mcheck(request_rec *r, union VALUETYPE *p, struct magic *m) -{ - register unsigned long l = m->value.l; - register unsigned long v; - int matched; - - if ((m->value.s[0] == 'x') && (m->value.s[1] == '\0')) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, - MODNAME ": BOINK"); - return 1; - } - - switch (m->type) { - case BYTE: - v = p->b; - break; - - case SHORT: - case BESHORT: - case LESHORT: - v = p->h; - break; - - case LONG: - case BELONG: - case LELONG: - case DATE: - case BEDATE: - case LEDATE: - v = p->l; - break; - - case STRING: - l = 0; - /* - * What we want here is: v = strncmp(m->value.s, p->s, m->vallen); - * but ignoring any nulls. bcmp doesn't give -/+/0 and isn't - * universally available anyway. - */ - v = 0; - { - register unsigned char *a = (unsigned char *) m->value.s; - register unsigned char *b = (unsigned char *) p->s; - register int len = m->vallen; - - while (--len >= 0) - if ((v = *b++ - *a++) != 0) - break; - } - break; - default: - /* bogosity, pretend that it just wasn't a match */ - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, - MODNAME ": invalid type %d in mcheck().", m->type); - return 0; - } - - v = signextend(r->server, m, v) & m->mask; - - switch (m->reln) { - case 'x': -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - "%lu == *any* = 1", v); -#endif - matched = 1; - break; - - case '!': - matched = v != l; -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - "%lu != %lu = %d", v, l, matched); -#endif - break; - - case '=': - matched = v == l; -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - "%lu == %lu = %d", v, l, matched); -#endif - break; - - case '>': - if (m->flag & UNSIGNED) { - matched = v > l; -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - "%lu > %lu = %d", v, l, matched); -#endif - } - else { - matched = (long) v > (long) l; -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - "%ld > %ld = %d", v, l, matched); -#endif - } - break; - - case '<': - if (m->flag & UNSIGNED) { - matched = v < l; -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - "%lu < %lu = %d", v, l, matched); -#endif - } - else { - matched = (long) v < (long) l; -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - "%ld < %ld = %d", v, l, matched); -#endif - } - break; - - case '&': - matched = (v & l) == l; -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - "((%lx & %lx) == %lx) = %d", v, l, l, matched); -#endif - break; - - case '^': - matched = (v & l) != l; -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - "((%lx & %lx) != %lx) = %d", v, l, l, matched); -#endif - break; - - default: - /* bogosity, pretend it didn't match */ - matched = 0; - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, - MODNAME ": mcheck: can't happen: invalid relation %d.", - m->reln); - break; - } - - return matched; -} - -/* an optimization over plain strcmp() */ -#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) - -static int ascmagic(request_rec *r, unsigned char *buf, apr_size_t nbytes) -{ - int has_escapes = 0; - unsigned char *s; - char nbuf[HOWMANY + 1]; /* one extra for terminating '\0' */ - char *token; - register struct names *p; - int small_nbytes; - - /* these are easy, do them first */ - - /* - * for troff, look for . + letter + letter or .\"; this must be done to - * disambiguate tar archives' ./file and other trash from real troff - * input. - */ - if (*buf == '.') { - unsigned char *tp = buf + 1; - - while (apr_isspace(*tp)) - ++tp; /* skip leading whitespace */ - if ((apr_isalnum(*tp) || *tp == '\\') && - (apr_isalnum(*(tp + 1)) || *tp == '"')) { - magic_rsl_puts(r, "application/x-troff"); - return 1; - } - } - if ((*buf == 'c' || *buf == 'C') && apr_isspace(*(buf + 1))) { - /* Fortran */ - magic_rsl_puts(r, "text/plain"); - return 1; - } - - /* look for tokens from names.h - this is expensive!, so we'll limit - * ourselves to only SMALL_HOWMANY bytes */ - small_nbytes = (nbytes > SMALL_HOWMANY) ? SMALL_HOWMANY : nbytes; - /* make a copy of the buffer here because strtok() will destroy it */ - s = (unsigned char *) memcpy(nbuf, buf, small_nbytes); - s[small_nbytes] = '\0'; - has_escapes = (memchr(s, '\033', small_nbytes) != NULL); - /* XXX: not multithread safe */ - while ((token = strtok((char *) s, " \t\n\r\f")) != NULL) { - s = NULL; /* make strtok() keep on tokin' */ - for (p = names; p < names + NNAMES; p++) { - if (STREQ(p->name, token)) { - magic_rsl_puts(r, types[p->type]); - if (has_escapes) - magic_rsl_puts(r, " (with escape sequences)"); - return 1; - } - } - } - - switch (is_tar(buf, nbytes)) { - case 1: - /* V7 tar archive */ - magic_rsl_puts(r, "application/x-tar"); - return 1; - case 2: - /* POSIX tar archive */ - magic_rsl_puts(r, "application/x-tar"); - return 1; - } - - /* all else fails, but it is ascii... */ - if (has_escapes) { - /* text with escape sequences */ - /* we leave this open for further differentiation later */ - magic_rsl_puts(r, "text/plain"); - } - else { - /* plain text */ - magic_rsl_puts(r, "text/plain"); - } - return 1; -} - - -/* - * compress routines: zmagic() - returns 0 if not recognized, uncompresses - * and prints information if recognized uncompress(s, method, old, n, newch) - * - uncompress old into new, using method, return sizeof new - */ - -static struct { - char *magic; - int maglen; - char *argv[3]; - int silent; - char *encoding; /* MUST be lowercase */ -} compr[] = { - - /* we use gzip here rather than uncompress because we have to pass - * it a full filename -- and uncompress only considers filenames - * ending with .Z - */ - { - "\037\235", 2, { - "gzip", "-dcq", NULL - }, 0, "x-compress" - }, - { - "\037\213", 2, { - "gzip", "-dcq", NULL - }, 1, "x-gzip" - }, - /* - * XXX pcat does not work, cause I don't know how to make it read stdin, - * so we use gzip - */ - { - "\037\036", 2, { - "gzip", "-dcq", NULL - }, 0, "x-gzip" - }, -}; - -static int ncompr = sizeof(compr) / sizeof(compr[0]); - -static int zmagic(request_rec *r, unsigned char *buf, apr_size_t nbytes) -{ - unsigned char *newbuf; - int newsize; - int i; - - for (i = 0; i < ncompr; i++) { - if (nbytes < compr[i].maglen) - continue; - if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0) - break; - } - - if (i == ncompr) - return 0; - - if ((newsize = uncompress(r, i, &newbuf, nbytes)) > 0) { - tryit(r, newbuf, newsize, 0); - - /* set encoding type in the request record */ - r->content_encoding = compr[i].encoding; - } - return 1; -} - - -struct uncompress_parms { - request_rec *r; - int method; -}; - -static int create_uncompress_child(struct uncompress_parms *parm, apr_pool_t *cntxt, - apr_file_t **pipe_in) -{ - int rc = 1; - const char *new_argv[4]; - const char *const *env; - request_rec *r = parm->r; - apr_pool_t *child_context = cntxt; - apr_procattr_t *procattr; - apr_proc_t *procnew; - - /* XXX missing 1.3 logic: - * - * what happens when !compr[parm->method].silent? - * Should we create the err pipe, read it, and copy to the log? - */ - - env = (const char *const *)ap_create_environment(child_context, r->subprocess_env); - - if ((apr_procattr_create(&procattr, child_context) != APR_SUCCESS) || - (apr_procattr_io_set(procattr, APR_FULL_BLOCK, - APR_FULL_BLOCK, APR_NO_PIPE) != APR_SUCCESS) || - (apr_procattr_dir_set(procattr, r->filename) != APR_SUCCESS) || - (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)) { - /* Something bad happened, tell the world. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_ENOPROC, r, - "couldn't setup child process: %s", r->filename); - } - else { - new_argv[0] = compr[parm->method].argv[0]; - new_argv[1] = compr[parm->method].argv[1]; - new_argv[2] = r->filename; - new_argv[3] = NULL; - - procnew = apr_pcalloc(child_context, sizeof(*procnew)); - rc = apr_proc_create(procnew, compr[parm->method].argv[0], - new_argv, env, procattr, child_context); - - if (rc != APR_SUCCESS) { - /* Bad things happened. Everyone should have cleaned up. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_ENOPROC, r, - MODNAME ": could not execute `%s'.", - compr[parm->method].argv[0]); - } - else { - apr_pool_note_subprocess(child_context, procnew, kill_after_timeout); - *pipe_in = procnew->out; - } - } - - return (rc); -} - -static int uncompress(request_rec *r, int method, - unsigned char **newch, apr_size_t n) -{ - struct uncompress_parms parm; - apr_file_t *pipe_out = NULL; - apr_pool_t *sub_context; - apr_status_t rv; - - parm.r = r; - parm.method = method; - - /* We make a sub_pool so that we can collect our child early, otherwise - * there are cases (i.e. generating directory indicies with mod_autoindex) - * where we would end up with LOTS of zombies. - */ - if (apr_pool_create(&sub_context, r->pool) != APR_SUCCESS) - return -1; - - if ((rv = create_uncompress_child(&parm, sub_context, &pipe_out)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - MODNAME ": couldn't spawn uncompress process: %s", r->uri); - return -1; - } - - *newch = (unsigned char *) apr_palloc(r->pool, n); - rv = apr_file_read(pipe_out, *newch, &n); - if (n == 0) { - apr_pool_destroy(sub_context); - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - MODNAME ": read failed %s", r->filename); - return -1; - } - apr_pool_destroy(sub_context); - return n; -} - -/* - * is_tar() -- figure out whether file is a tar archive. - * - * Stolen (by author of file utility) from the public domain tar program: Public - * Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu). - * - * @(#)list.c 1.18 9/23/86 Public Domain - gnu $Id: mod_mime_magic.c,v 1.7 - * 1997/06/24 00:41:02 ikluft Exp ikluft $ - * - * Comments changed and some code/comments reformatted for file command by Ian - * Darwin. - */ - -#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') ) - -/* - * Return 0 if the checksum is bad (i.e., probably not a tar archive), 1 for - * old UNIX tar file, 2 for Unix Std (POSIX) tar file. - */ - -static int is_tar(unsigned char *buf, apr_size_t nbytes) -{ - register union record *header = (union record *) buf; - register int i; - register long sum, recsum; - register char *p; - - if (nbytes < sizeof(union record)) - return 0; - - recsum = from_oct(8, header->header.chksum); - - sum = 0; - p = header->charptr; - for (i = sizeof(union record); --i >= 0;) { - /* - * We can't use unsigned char here because of old compilers, e.g. V7. - */ - sum += 0xFF & *p++; - } - - /* Adjust checksum to count the "chksum" field as blanks. */ - for (i = sizeof(header->header.chksum); --i >= 0;) - sum -= 0xFF & header->header.chksum[i]; - sum += ' ' * sizeof header->header.chksum; - - if (sum != recsum) - return 0; /* Not a tar archive */ - - if (0 == strcmp(header->header.magic, TMAGIC)) - return 2; /* Unix Standard tar archive */ - - return 1; /* Old fashioned tar archive */ -} - - -/* - * Quick and dirty octal conversion. - * - * Result is -1 if the field is invalid (all blank, or nonoctal). - */ -static long from_oct(int digs, char *where) -{ - register long value; - - while (apr_isspace(*where)) { /* Skip spaces */ - where++; - if (--digs <= 0) - return -1; /* All blank field */ - } - value = 0; - while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */ - value = (value << 3) | (*where++ - '0'); - --digs; - } - - if (digs > 0 && *where && !apr_isspace(*where)) - return -1; /* Ended on non-space/nul */ - - return value; -} - -/* - * Check for file-revision suffix - * - * This is for an obscure document control system used on an intranet. - * The web representation of each file's revision has an @1, @2, etc - * appended with the revision number. This needs to be stripped off to - * find the file suffix, which can be recognized by sending the name back - * through a sub-request. The base file name (without the @num suffix) - * must exist because its type will be used as the result. - */ -static int revision_suffix(request_rec *r) -{ - int suffix_pos, result; - char *sub_filename; - request_rec *sub; - -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - MODNAME ": revision_suffix checking %s", r->filename); -#endif /* MIME_MAGIC_DEBUG */ - - /* check for recognized revision suffix */ - suffix_pos = strlen(r->filename) - 1; - if (!apr_isdigit(r->filename[suffix_pos])) { - return 0; - } - while (suffix_pos >= 0 && apr_isdigit(r->filename[suffix_pos])) - suffix_pos--; - if (suffix_pos < 0 || r->filename[suffix_pos] != '@') { - return 0; - } - - /* perform sub-request for the file name without the suffix */ - result = 0; - sub_filename = apr_pstrndup(r->pool, r->filename, suffix_pos); -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - MODNAME ": subrequest lookup for %s", sub_filename); -#endif /* MIME_MAGIC_DEBUG */ - sub = ap_sub_req_lookup_file(sub_filename, r, NULL); - - /* extract content type/encoding/language from sub-request */ - if (sub->content_type) { - r->content_type = apr_pstrdup(r->pool, sub->content_type); -#if MIME_MAGIC_DEBUG - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r, - MODNAME ": subrequest %s got %s", - sub_filename, r->content_type); -#endif /* MIME_MAGIC_DEBUG */ - if (sub->content_encoding) - r->content_encoding = - apr_pstrdup(r->pool, sub->content_encoding); - if (sub->content_language) - r->content_language = - apr_pstrdup(r->pool, sub->content_language); - result = 1; - } - - /* clean up */ - ap_destroy_sub_req(sub); - - return result; -} - -/* - * initialize the module - */ -static void magic_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server) -{ - int result; - magic_server_config_rec *conf; - magic_server_config_rec *main_conf; - server_rec *s; -#if MIME_MAGIC_DEBUG - struct magic *m, *prevm; -#endif /* MIME_MAGIC_DEBUG */ - - main_conf = ap_get_module_config(main_server->module_config, &mime_magic_module); - for (s = main_server; s; s = s->next) { - conf = ap_get_module_config(s->module_config, &mime_magic_module); - if (conf->magicfile == NULL && s != main_server) { - /* inherits from the parent */ - *conf = *main_conf; - } - else if (conf->magicfile) { - result = apprentice(s, p); - if (result == -1) - return; -#if MIME_MAGIC_DEBUG - prevm = 0; - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s, - MODNAME ": magic_init 1 test"); - for (m = conf->magic; m; m = m->next) { - if (apr_isprint((((unsigned long) m) >> 24) & 255) && - apr_isprint((((unsigned long) m) >> 16) & 255) && - apr_isprint((((unsigned long) m) >> 8) & 255) && - apr_isprint(((unsigned long) m) & 255)) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s, - MODNAME ": magic_init 1: POINTER CLOBBERED! " - "m=\"%c%c%c%c\" line=%d", - (((unsigned long) m) >> 24) & 255, - (((unsigned long) m) >> 16) & 255, - (((unsigned long) m) >> 8) & 255, - ((unsigned long) m) & 255, - prevm ? prevm->lineno : -1); - break; - } - prevm = m; - } -#endif - } - } -} - -/* - * Find the Content-Type from any resource this module has available - */ - -static int magic_find_ct(request_rec *r) -{ - int result; - magic_server_config_rec *conf; - - /* the file has to exist */ - if (r->finfo.filetype == 0 || !r->filename) { - return DECLINED; - } - - /* was someone else already here? */ - if (r->content_type) { - return DECLINED; - } - - conf = ap_get_module_config(r->server->module_config, &mime_magic_module); - if (!conf || !conf->magic) { - return DECLINED; - } - - /* initialize per-request info */ - if (!magic_set_config(r)) { - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* try excluding file-revision suffixes */ - if (revision_suffix(r) != 1) { - /* process it based on the file contents */ - if ((result = magic_process(r)) != OK) { - return result; - } - } - - /* if we have any results, put them in the request structure */ - return magic_rsl_to_request(r); -} - -static void register_hooks(apr_pool_t *p) -{ - static const char * const aszPre[]={ "mod_mime.c", NULL }; - - /* mod_mime_magic should be run after mod_mime, if at all. */ - - ap_hook_type_checker(magic_find_ct, aszPre, NULL, APR_HOOK_MIDDLE); - ap_hook_post_config(magic_init, NULL, NULL, APR_HOOK_FIRST); -} - -/* - * Apache API module interface - */ - -module mime_magic_module = -{ - STANDARD20_MODULE_STUFF, - NULL, /* dir config creator */ - NULL, /* dir merger --- default is to override */ - create_magic_server_config, /* server config */ - merge_magic_server_config, /* merge server config */ - mime_magic_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; - - diff --git a/modules/metadata/mod_mime_magic.exp b/modules/metadata/mod_mime_magic.exp deleted file mode 100644 index 42068a4342..0000000000 --- a/modules/metadata/mod_mime_magic.exp +++ /dev/null @@ -1 +0,0 @@ -mime_magic_module diff --git a/modules/metadata/mod_setenvif.c b/modules/metadata/mod_setenvif.c deleted file mode 100644 index 386f3c8d74..0000000000 --- a/modules/metadata/mod_setenvif.c +++ /dev/null @@ -1,471 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_setenvif.c - * Set environment variables based on matching request headers or - * attributes against regex strings - * - * Paul Sutton <paul@ukweb.com> 27 Oct 1996 - * Based on mod_browser by Alexei Kosut <akosut@organic.com> - */ - -/* - * Used to set environment variables based on the incoming request headers, - * or some selected other attributes of the request (e.g., the remote host - * name). - * - * Usage: - * - * SetEnvIf name regex var ... - * - * where name is either a HTTP request header name, or one of the - * special values (see below). The 'value' of the header (or the - * value of the special value from below) are compared against the - * regex argument. If this is a simple string, a simple sub-string - * match is performed. Otherwise, a request expression match is - * done. If the value matches the string or regular expression, the - * environment variables listed as var ... are set. Each var can - * be in one of three formats: var, which sets the named variable - * (the value value "1"); var=value, which sets the variable to - * the given value; or !var, which unsets the variable is it has - * been previously set. - * - * Normally the strings are compared with regard to case. To ignore - * case, use the directive SetEnvIfNoCase instead. - * - * Special values for 'name' are: - * - * remote_host Remote host name (if available) - * remote_addr Remote IP address - * remote_user Remote authenticated user (if any) - * request_method Request method (GET, POST, etc) - * request_uri Requested URI - * - * Examples: - * - * To set the enviroment variable LOCALHOST if the client is the local - * machine: - * - * SetEnvIf remote_addr 127.0.0.1 LOCALHOST - * - * To set LOCAL if the client is the local host, or within our company's - * domain (192.168.10): - * - * SetEnvIf remote_addr 192.168.10. LOCAL - * SetEnvIf remote_addr 127.0.0.1 LOCALHOST - * - * This could be written as: - * - * SetEnvIf remote_addr (127.0.0.1|192.168.10.) LOCAL - */ - -#include "apr.h" -#include "apr_strings.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_protocol.h" - - -enum special { - SPECIAL_NOT, - SPECIAL_REMOTE_ADDR, - SPECIAL_REMOTE_HOST, - SPECIAL_REMOTE_USER, - SPECIAL_REQUEST_URI, - SPECIAL_REQUEST_METHOD, - SPECIAL_REQUEST_PROTOCOL -}; -typedef struct { - char *name; /* header name */ - char *regex; /* regex to match against */ - regex_t *preg; /* compiled regex */ - apr_table_t *features; /* env vars to set (or unset) */ - enum special special_type; /* is it a "special" header ? */ - int icase; /* ignoring case? */ -} sei_entry; - -typedef struct { - apr_array_header_t *conditionals; -} sei_cfg_rec; - -module AP_MODULE_DECLARE_DATA setenvif_module; - -/* - * These routines, the create- and merge-config functions, are called - * for both the server-wide and the per-directory contexts. This is - * because the different definitions are used at different times; the - * server-wide ones are used in the post-read-request phase, and the - * per-directory ones are used during the header-parse phase (after - * the URI has been mapped to a file and we have anything from the - * .htaccess file and <Directory> and <Files> containers). - */ -static void *create_setenvif_config(apr_pool_t *p) -{ - sei_cfg_rec *new = (sei_cfg_rec *) apr_palloc(p, sizeof(sei_cfg_rec)); - - new->conditionals = apr_array_make(p, 20, sizeof(sei_entry)); - return (void *) new; -} - -static void *create_setenvif_config_svr(apr_pool_t *p, server_rec *dummy) -{ - return create_setenvif_config(p); -} - -static void *create_setenvif_config_dir(apr_pool_t *p, char *dummy) -{ - return create_setenvif_config(p); -} - -static void *merge_setenvif_config(apr_pool_t *p, void *basev, void *overridesv) -{ - sei_cfg_rec *a = apr_pcalloc(p, sizeof(sei_cfg_rec)); - sei_cfg_rec *base = basev, *overrides = overridesv; - - a->conditionals = apr_array_append(p, base->conditionals, - overrides->conditionals); - return a; -} - -/* - * any non-NULL magic constant will do... used to indicate if REG_ICASE should - * be used - */ -#define ICASE_MAGIC ((void *)(&setenvif_module)) -#define SEI_MAGIC_HEIRLOOM "setenvif-phase-flag" - -static const char *add_setenvif_core(cmd_parms *cmd, void *mconfig, - char *fname, const char *args) -{ - char *regex; - const char *feature; - sei_cfg_rec *sconf; - sei_entry *new; - sei_entry *entries; - char *var; - int i; - int beenhere = 0; - int icase; - - /* - * Determine from our context into which record to put the entry. - * cmd->path == NULL means we're in server-wide context; otherwise, - * we're dealing with a per-directory setting. - */ - sconf = (cmd->path != NULL) - ? (sei_cfg_rec *) mconfig - : (sei_cfg_rec *) ap_get_module_config(cmd->server->module_config, - &setenvif_module); - entries = (sei_entry *) sconf->conditionals->elts; - /* get regex */ - regex = ap_getword_conf(cmd->pool, &args); - if (!*regex) { - return apr_pstrcat(cmd->pool, "Missing regular expression for ", - cmd->cmd->name, NULL); - } - - /* - * If we've already got a sei_entry with the same name we want to - * just copy the name pointer... so that later on we can compare - * two header names just by comparing the pointers. - */ - - for (i = 0; i < sconf->conditionals->nelts; ++i) { - new = &entries[i]; - if (!strcasecmp(new->name, fname)) { - fname = new->name; - break; - } - } - - /* if the last entry has an identical headername and regex then - * merge with it - */ - i = sconf->conditionals->nelts - 1; - icase = cmd->info == ICASE_MAGIC; - if (i < 0 - || entries[i].name != fname - || entries[i].icase != icase - || strcmp(entries[i].regex, regex)) { - - /* no match, create a new entry */ - - new = apr_array_push(sconf->conditionals); - new->name = fname; - new->regex = regex; - new->icase = icase; - new->preg = ap_pregcomp(cmd->pool, regex, - (REG_EXTENDED | REG_NOSUB - | (icase ? REG_ICASE : 0))); - if (new->preg == NULL) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - " regex could not be compiled.", NULL); - } - new->features = apr_table_make(cmd->pool, 2); - - if (!strcasecmp(fname, "remote_addr")) { - new->special_type = SPECIAL_REMOTE_ADDR; - } - else if (!strcasecmp(fname, "remote_host")) { - new->special_type = SPECIAL_REMOTE_HOST; - } - else if (!strcasecmp(fname, "remote_user")) { - new->special_type = SPECIAL_REMOTE_USER; - } - else if (!strcasecmp(fname, "request_uri")) { - new->special_type = SPECIAL_REQUEST_URI; - } - else if (!strcasecmp(fname, "request_method")) { - new->special_type = SPECIAL_REQUEST_METHOD; - } - else if (!strcasecmp(fname, "request_protocol")) { - new->special_type = SPECIAL_REQUEST_PROTOCOL; - } - else { - new->special_type = SPECIAL_NOT; - } - } - else { - new = &entries[i]; - } - - for ( ; ; ) { - feature = ap_getword_conf(cmd->pool, &args); - if (!*feature) { - break; - } - beenhere++; - - var = ap_getword(cmd->pool, &feature, '='); - if (*feature) { - apr_table_setn(new->features, var, feature); - } - else if (*var == '!') { - apr_table_setn(new->features, var + 1, "!"); - } - else { - apr_table_setn(new->features, var, "1"); - } - } - - if (!beenhere) { - return apr_pstrcat(cmd->pool, "Missing envariable expression for ", - cmd->cmd->name, NULL); - } - - return NULL; -} - -static const char *add_setenvif(cmd_parms *cmd, void *mconfig, - const char *args) -{ - char *fname; - - /* get header name */ - fname = ap_getword_conf(cmd->pool, &args); - if (!*fname) { - return apr_pstrcat(cmd->pool, "Missing header-field name for ", - cmd->cmd->name, NULL); - } - return add_setenvif_core(cmd, mconfig, fname, args); -} - -/* - * This routine handles the BrowserMatch* directives. It simply turns around - * and feeds them, with the appropriate embellishments, to the general-purpose - * command handler. - */ -static const char *add_browser(cmd_parms *cmd, void *mconfig, const char *args) -{ - return add_setenvif_core(cmd, mconfig, "User-Agent", args); -} - -static const command_rec setenvif_module_cmds[] = -{ - AP_INIT_RAW_ARGS("SetEnvIf", add_setenvif, NULL, - OR_FILEINFO, "A header-name, regex and a list of variables."), - AP_INIT_RAW_ARGS("SetEnvIfNoCase", add_setenvif, ICASE_MAGIC, - OR_FILEINFO, "a header-name, regex and a list of variables."), - AP_INIT_RAW_ARGS("BrowserMatch", add_browser, NULL, - OR_FILEINFO, "A browser regex and a list of variables."), - AP_INIT_RAW_ARGS("BrowserMatchNoCase", add_browser, ICASE_MAGIC, - OR_FILEINFO, "A browser regex and a list of variables."), - { NULL }, -}; - -/* - * This routine gets called at two different points in request processing: - * once before the URI has been translated (during the post-read-request - * phase) and once after (during the header-parse phase). We use different - * config records for the two different calls to reduce overhead (by not - * re-doing the server-wide settings during directory processing), and - * signal which call it is by having the earlier one pass a flag to the - * later one. - */ -static int match_headers(request_rec *r) -{ - sei_cfg_rec *sconf; - sei_entry *entries; - apr_table_entry_t *elts; - const char *val; - int i, j; - char *last_name; - - if (apr_table_get(r->notes, SEI_MAGIC_HEIRLOOM) == NULL) { - apr_table_set(r->notes, SEI_MAGIC_HEIRLOOM, "post-read done"); - sconf = (sei_cfg_rec *) ap_get_module_config(r->server->module_config, - &setenvif_module); - } - else { - sconf = (sei_cfg_rec *) ap_get_module_config(r->per_dir_config, - &setenvif_module); - } - entries = (sei_entry *) sconf->conditionals->elts; - last_name = NULL; - val = NULL; - for (i = 0; i < sconf->conditionals->nelts; ++i) { - sei_entry *b = &entries[i]; - - /* Optimize the case where a bunch of directives in a row use the - * same header. Remember we don't need to strcmp the two header - * names because we made sure the pointers were equal during - * configuration. - */ - if (b->name != last_name) { - last_name = b->name; - switch (b->special_type) { - case SPECIAL_REMOTE_ADDR: - val = r->connection->remote_ip; - break; - case SPECIAL_REMOTE_HOST: - val = ap_get_remote_host(r->connection, r->per_dir_config, - REMOTE_NAME, NULL); - break; - case SPECIAL_REMOTE_USER: - val = r->user; - break; - case SPECIAL_REQUEST_URI: - val = r->uri; - break; - case SPECIAL_REQUEST_METHOD: - val = r->method; - break; - case SPECIAL_REQUEST_PROTOCOL: - val = r->protocol; - break; - case SPECIAL_NOT: - val = apr_table_get(r->headers_in, b->name); - if (val == NULL) { - val = apr_table_get(r->subprocess_env, b->name); - } - break; - } - } - - /* - * A NULL value indicates that the header field or special entity - * wasn't present or is undefined. Represent that as an empty string - * so that REs like "^$" will work and allow envariable setting - * based on missing or empty field. - */ - if (val == NULL) { - val = ""; - } - - if (!ap_regexec(b->preg, val, 0, NULL, 0)) { - apr_array_header_t *arr = apr_table_elts(b->features); - elts = (apr_table_entry_t *) arr->elts; - - for (j = 0; j < arr->nelts; ++j) { - if (!strcmp(elts[j].val, "!")) { - apr_table_unset(r->subprocess_env, elts[j].key); - } - else { - apr_table_setn(r->subprocess_env, elts[j].key, elts[j].val); - } - } - } - } - - return DECLINED; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_header_parser(match_headers, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_read_request(match_headers, NULL, NULL, APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA setenvif_module = -{ - STANDARD20_MODULE_STUFF, - create_setenvif_config_dir, /* dir config creater */ - merge_setenvif_config, /* dir merger --- default is to override */ - create_setenvif_config_svr, /* server config */ - merge_setenvif_config, /* merge server configs */ - setenvif_module_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/metadata/mod_setenvif.exp b/modules/metadata/mod_setenvif.exp deleted file mode 100644 index 4f3800e3a8..0000000000 --- a/modules/metadata/mod_setenvif.exp +++ /dev/null @@ -1 +0,0 @@ -setenvif_module diff --git a/modules/metadata/mod_unique_id.c b/modules/metadata/mod_unique_id.c deleted file mode 100644 index 69a54174b4..0000000000 --- a/modules/metadata/mod_unique_id.c +++ /dev/null @@ -1,402 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_unique_id.c: generate a unique identifier for each request - * - * Original author: Dean Gaudet <dgaudet@arctic.org> - * UUencoding modified by: Alvaro Martinez Echevarria <alvaro@lander.es> - */ - -#include "apr_general.h" /* for XtOffsetOf */ - -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "http_protocol.h" /* for ap_hook_post_read_request */ - -#if APR_HAVE_NETDB_H -#include <netdb.h> -#endif -#if APR_HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif - -typedef struct { - unsigned int stamp; - unsigned int in_addr; - unsigned int pid; - unsigned short counter; - unsigned int thread_index; -} unique_id_rec; - -/* We are using thread_index (the index into the scoreboard), because we - * cannont garauntee the thread_id will be an integer. - * - * This code looks like it won't give a unique ID with the new thread logic. - * It will. The reason is, we don't increment the counter in a thread_safe - * manner. Because the thread_index is also in the unique ID now, this does - * not matter. In order for the id to not be unique, the same thread would - * have to get the same counter twice in the same second. - */ - -/* Comments: - * - * We want an identifier which is unique across all hits, everywhere. - * "everywhere" includes multiple httpd instances on the same machine, or on - * multiple machines. Essentially "everywhere" should include all possible - * httpds across all servers at a particular "site". We make some assumptions - * that if the site has a cluster of machines then their time is relatively - * synchronized. We also assume that the first address returned by a - * gethostbyname (gethostname()) is unique across all the machines at the - * "site". - * - * We also further assume that pids fit in 32-bits. If something uses more - * than 32-bits, the fix is trivial, but it requires the unrolled uuencoding - * loop to be extended. * A similar fix is needed to support multithreaded - * servers, using a pid/tid combo. - * - * Together, the in_addr and pid are assumed to absolutely uniquely identify - * this one child from all other currently running children on all servers - * (including this physical server if it is running multiple httpds) from each - * other. - * - * The stamp and counter are used to distinguish all hits for a particular - * (in_addr,pid) pair. The stamp is updated using r->request_time, - * saving cpu cycles. The counter is never reset, and is used to permit up to - * 64k requests in a single second by a single child. - * - * The 112-bits of unique_id_rec are encoded using the alphabet - * [A-Za-z0-9@-], resulting in 19 bytes of printable characters. That is then - * stuffed into the environment variable UNIQUE_ID so that it is available to - * other modules. The alphabet choice differs from normal base64 encoding - * [A-Za-z0-9+/] because + and / are special characters in URLs and we want to - * make it easy to use UNIQUE_ID in URLs. - * - * Note that UNIQUE_ID should be considered an opaque token by other - * applications. No attempt should be made to dissect its internal components. - * It is an abstraction that may change in the future as the needs of this - * module change. - * - * It is highly desirable that identifiers exist for "eternity". But future - * needs (such as much faster webservers, moving to 64-bit pids, or moving to a - * multithreaded server) may dictate a need to change the contents of - * unique_id_rec. Such a future implementation should ensure that the first - * field is still a time_t stamp. By doing that, it is possible for a site to - * have a "flag second" in which they stop all of their old-format servers, - * wait one entire second, and then start all of their new-servers. This - * procedure will ensure that the new space of identifiers is completely unique - * from the old space. (Since the first four unencoded bytes always differ.) - */ -/* - * Sun Jun 7 05:43:49 CEST 1998 -- Alvaro - * More comments: - * 1) The UUencoding prodecure is now done in a general way, avoiding the problems - * with sizes and paddings that can arise depending on the architecture. Now the - * offsets and sizes of the elements of the unique_id_rec structure are calculated - * in unique_id_global_init; and then used to duplicate the structure without the - * paddings that might exist. The multithreaded server fix should be now very easy: - * just add a new "tid" field to the unique_id_rec structure, and increase by one - * UNIQUE_ID_REC_MAX. - * 2) unique_id_rec.stamp has been changed from "time_t" to "unsigned int", because - * its size is 64bits on some platforms (linux/alpha), and this caused problems with - * htonl/ntohl. Well, this shouldn't be a problem till year 2106. - */ - -static unsigned global_in_addr; - -static unique_id_rec cur_unique_id; - -/* - * Number of elements in the structure unique_id_rec. - */ -#define UNIQUE_ID_REC_MAX 5 - -static unsigned short unique_id_rec_offset[UNIQUE_ID_REC_MAX], - unique_id_rec_size[UNIQUE_ID_REC_MAX], - unique_id_rec_total_size, - unique_id_rec_size_uu; - -static void unique_id_global_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server) -{ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 256 -#endif - char str[MAXHOSTNAMELEN + 1]; - struct hostent *hent; - apr_short_interval_time_t pause; - - /* - * Calculate the sizes and offsets in cur_unique_id. - */ - unique_id_rec_offset[0] = XtOffsetOf(unique_id_rec, stamp); - unique_id_rec_size[0] = sizeof(cur_unique_id.stamp); - unique_id_rec_offset[1] = XtOffsetOf(unique_id_rec, in_addr); - unique_id_rec_size[1] = sizeof(cur_unique_id.in_addr); - unique_id_rec_offset[2] = XtOffsetOf(unique_id_rec, pid); - unique_id_rec_size[2] = sizeof(cur_unique_id.pid); - unique_id_rec_offset[3] = XtOffsetOf(unique_id_rec, counter); - unique_id_rec_size[3] = sizeof(cur_unique_id.counter); - unique_id_rec_offset[4] = XtOffsetOf(unique_id_rec, thread_index); - unique_id_rec_size[4] = sizeof(cur_unique_id.thread_index); - unique_id_rec_total_size = unique_id_rec_size[0] + unique_id_rec_size[1] + - unique_id_rec_size[2] + unique_id_rec_size[3] + - unique_id_rec_size[4]; - - /* - * Calculate the size of the structure when encoded. - */ - unique_id_rec_size_uu = (unique_id_rec_total_size*8+5)/6; - - /* - * Now get the global in_addr. Note that it is not sufficient to use one - * of the addresses from the main_server, since those aren't as likely to - * be unique as the physical address of the machine - */ - if (gethostname(str, sizeof(str) - 1) != 0) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, errno, main_server, - "gethostname: mod_unique_id requires the hostname of the server"); - exit(1); - } - str[sizeof(str) - 1] = '\0'; - - if ((hent = gethostbyname(str)) == NULL) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, h_errno, main_server, - "mod_unique_id: unable to gethostbyname(\"%s\")", str); - exit(1); - } - - global_in_addr = ((struct in_addr *) hent->h_addr_list[0])->s_addr; - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, main_server, - "mod_unique_id: using ip addr %s", - inet_ntoa(*(struct in_addr *) hent->h_addr_list[0])); - - /* - * If the server is pummelled with restart requests we could possibly end - * up in a situation where we're starting again during the same second - * that has been used in previous identifiers. Avoid that situation. - * - * In truth, for this to actually happen not only would it have to restart - * in the same second, but it would have to somehow get the same pids as - * one of the other servers that was running in that second. Which would - * mean a 64k wraparound on pids ... not very likely at all. - * - * But protecting against it is relatively cheap. We just sleep into the - * next second. - */ - pause = (apr_short_interval_time_t)(1000000 - (apr_time_now() % APR_USEC_PER_SEC)); - apr_sleep(pause); -} - -static void unique_id_child_init(apr_pool_t *p, server_rec *s) -{ - pid_t pid; - apr_time_t tv; - - /* - * Note that we use the pid because it's possible that on the same - * physical machine there are multiple servers (i.e. using Listen). But - * it's guaranteed that none of them will share the same pids between - * children. - * - * XXX: for multithread this needs to use a pid/tid combo and probably - * needs to be expanded to 32 bits - */ - pid = getpid(); - cur_unique_id.pid = pid; - - /* - * Test our assumption that the pid is 32-bits. It's possible that - * 64-bit machines will declare pid_t to be 64 bits but only use 32 - * of them. It would have been really nice to test this during - * global_init ... but oh well. - */ - if (cur_unique_id.pid != pid) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, 0, s, - "oh no! pids are greater than 32-bits! I'm broken!"); - } - - cur_unique_id.in_addr = global_in_addr; - - /* - * If we use 0 as the initial counter we have a little less protection - * against restart problems, and a little less protection against a clock - * going backwards in time. - */ - tv = apr_time_now(); - /* Some systems have very low variance on the low end of their system - * counter, defend against that. - */ - cur_unique_id.counter = tv % APR_USEC_PER_SEC / 10; - - /* - * We must always use network ordering for these bytes, so that - * identifiers are comparable between machines of different byte - * orderings. Note in_addr is already in network order. - */ - cur_unique_id.pid = htonl(cur_unique_id.pid); - cur_unique_id.counter = htons(cur_unique_id.counter); -} - -/* NOTE: This is *NOT* the same encoding used by base64encode ... the last two - * characters should be + and /. But those two characters have very special - * meanings in URLs, and we want to make it easy to use identifiers in - * URLs. So we replace them with @ and -. - */ -static const char uuencoder[64] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '@', '-', -}; - -static int gen_unique_id(request_rec *r) -{ - char *str; - /* - * Buffer padded with two final bytes, used to copy the unique_id_red - * structure without the internal paddings that it could have. - */ - unique_id_rec new_unique_id; - struct { - unique_id_rec foo; - unsigned char pad[2]; - } paddedbuf; - unsigned char *x,*y; - unsigned short counter; - const char *e; - int i,j,k; - - /* copy the unique_id if this is an internal redirect (we're never - * actually called for sub requests, so we don't need to test for - * them) */ - if (r->prev && (e = apr_table_get(r->subprocess_env, "REDIRECT_UNIQUE_ID"))) { - apr_table_setn(r->subprocess_env, "UNIQUE_ID", e); - return DECLINED; - } - - new_unique_id.in_addr = cur_unique_id.in_addr; - new_unique_id.pid = cur_unique_id.pid; - new_unique_id.counter = cur_unique_id.counter; - - new_unique_id.stamp = htonl((unsigned int)r->request_time); - new_unique_id.thread_index = htonl((unsigned int)r->connection->id); - - /* we'll use a temporal buffer to avoid uuencoding the possible internal - * paddings of the original structure */ - x = (unsigned char *) &paddedbuf; - y = (unsigned char *) &new_unique_id; - k = 0; - for (i = 0; i < UNIQUE_ID_REC_MAX; i++) { - y = ((unsigned char *) &new_unique_id) + unique_id_rec_offset[i]; - for (j = 0; j < unique_id_rec_size[i]; j++, k++) { - x[k] = y[j]; - } - } - /* - * We reset two more bytes just in case padding is needed for the uuencoding. - */ - x[k++] = '\0'; - x[k++] = '\0'; - - /* alloc str and do the uuencoding */ - str = (char *)apr_palloc(r->pool, unique_id_rec_size_uu + 1); - k = 0; - for (i = 0; i < unique_id_rec_total_size; i += 3) { - y = x + i; - str[k++] = uuencoder[y[0] >> 2]; - str[k++] = uuencoder[((y[0] & 0x03) << 4) | ((y[1] & 0xf0) >> 4)]; - if (k == unique_id_rec_size_uu) break; - str[k++] = uuencoder[((y[1] & 0x0f) << 2) | ((y[2] & 0xc0) >> 6)]; - if (k == unique_id_rec_size_uu) break; - str[k++] = uuencoder[y[2] & 0x3f]; - } - str[k++] = '\0'; - - /* set the environment variable */ - apr_table_setn(r->subprocess_env, "UNIQUE_ID", str); - - /* and increment the identifier for the next call */ - - counter = ntohs(new_unique_id.counter) + 1; - cur_unique_id.counter = htons(counter); - - return DECLINED; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_post_config(unique_id_global_init, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_child_init(unique_id_child_init, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_read_request(gen_unique_id, NULL, NULL, APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA unique_id_module = { - STANDARD20_MODULE_STUFF, - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server configs */ - NULL, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/metadata/mod_unique_id.exp b/modules/metadata/mod_unique_id.exp deleted file mode 100644 index 93000f1ee6..0000000000 --- a/modules/metadata/mod_unique_id.exp +++ /dev/null @@ -1 +0,0 @@ -unique_id_module diff --git a/modules/metadata/mod_usertrack.c b/modules/metadata/mod_usertrack.c deleted file mode 100644 index dfe39f0875..0000000000 --- a/modules/metadata/mod_usertrack.c +++ /dev/null @@ -1,328 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* User Tracking Module (Was mod_cookies.c) - * - * This Apache module is designed to track users paths through a site. - * It uses the client-side state ("Cookie") protocol developed by Netscape. - * It is known to work on Netscape browsers, Microsoft Internet - * Explorer and others currently being developed. - * - * Each time a page is requested we look to see if the browser is sending - * us a Cookie: header that we previously generated. - * - * If we don't find one then the user hasn't been to this site since - * starting their browser or their browser doesn't support cookies. So - * we generate a unique Cookie for the transaction and send it back to - * the browser (via a "Set-Cookie" header) - * Future requests from the same browser should keep the same Cookie line. - * - * By matching up all the requests with the same cookie you can - * work out exactly what path a user took through your site. To log - * the cookie use the " %{Cookie}n " directive in a custom access log; - * - * Example 1 : If you currently use the standard Log file format (CLF) - * and use the command "TransferLog somefilename", add the line - * LogFormat "%h %l %u %t \"%r\" %s %b %{Cookie}n" - * to your config file. - * - * Example 2 : If you used to use the old "CookieLog" directive, you - * can emulate it by adding the following command to your config file - * CustomLog filename "%{Cookie}n \"%r\" %t" - * - * Notes: - * 1. This code now logs the initial transaction (the one that created - * the cookie to start with). - * 2. This module has been designed to not interfere with other Cookies - * your site may be using; just avoid sending out cookies with - * the name "Apache=" or things will get confused. - * 3. If you want you can modify the Set-Cookie line so that the Cookie - * never expires. You would then get the same Cookie each time the - * user revisits your site. - * - * Mark Cox, mark@ukweb.com, 6 July 95 - * - * This file replaces mod_cookies.c - */ - -#include "apr.h" -#include "apr_lib.h" -#include "apr_strings.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_request.h" - - -module AP_MODULE_DECLARE_DATA usertrack_module; - -typedef struct { - int always; - int expires; -} cookie_log_state; - -typedef struct { - int enabled; - char *cookie_name; -} cookie_dir_rec; - -/* Make Cookie: Now we have to generate something that is going to be - * pretty unique. We can base it on the pid, time, hostip */ - -#define COOKIE_NAME "Apache" - -static void make_cookie(request_rec *r) -{ - cookie_log_state *cls = ap_get_module_config(r->server->module_config, - &usertrack_module); - /* 1024 == hardcoded constant */ - char cookiebuf[1024]; - char *new_cookie; - const char *rname = ap_get_remote_host(r->connection, r->per_dir_config, - REMOTE_NAME, NULL); - cookie_dir_rec *dcfg; - - dcfg = ap_get_module_config(r->per_dir_config, &usertrack_module); - - /* XXX: hmm, this should really tie in with mod_unique_id */ - apr_snprintf(cookiebuf, sizeof(cookiebuf), "%s.%qd", rname, apr_time_now()); - - if (cls->expires) { - apr_exploded_time_t tms; - - apr_explode_gmt(&tms, r->request_time + cls->expires * APR_USEC_PER_SEC); - - /* Cookie with date; as strftime '%a, %d-%h-%y %H:%M:%S GMT' */ - new_cookie = apr_psprintf(r->pool, - "%s=%s; path=/; expires=%s, %.2d-%s-%.2d %.2d:%.2d:%.2d GMT", - dcfg->cookie_name, cookiebuf, apr_day_snames[tms.tm_wday], - tms.tm_mday, apr_month_snames[tms.tm_mon], - tms.tm_year % 100, - tms.tm_hour, tms.tm_min, tms.tm_sec); - } - else { - new_cookie = apr_psprintf(r->pool, "%s=%s; path=/", - dcfg->cookie_name, cookiebuf); - } - - apr_table_setn(r->headers_out, "Set-Cookie", new_cookie); - apr_table_setn(r->notes, "cookie", apr_pstrdup(r->pool, cookiebuf)); /* log first time */ - return; -} - -static int spot_cookie(request_rec *r) -{ - cookie_dir_rec *dcfg = ap_get_module_config(r->per_dir_config, - &usertrack_module); - const char *cookie; - const char *value; - - if (!dcfg->enabled) { - return DECLINED; - } - - if ((cookie = apr_table_get(r->headers_in, "Cookie"))) - if ((value = ap_strstr_c(cookie, dcfg->cookie_name))) { - char *cookiebuf, *cookieend; - - value += strlen(dcfg->cookie_name) + 1; /* Skip over the '=' */ - cookiebuf = apr_pstrdup(r->pool, value); - cookieend = strchr(cookiebuf, ';'); - if (cookieend) - *cookieend = '\0'; /* Ignore anything after a ; */ - - /* Set the cookie in a note, for logging */ - apr_table_setn(r->notes, "cookie", cookiebuf); - - return DECLINED; /* There's already a cookie, no new one */ - } - make_cookie(r); - return OK; /* We set our cookie */ -} - -static void *make_cookie_log_state(apr_pool_t *p, server_rec *s) -{ - cookie_log_state *cls = - (cookie_log_state *) apr_palloc(p, sizeof(cookie_log_state)); - - cls->expires = 0; - - return (void *) cls; -} - -static void *make_cookie_dir(apr_pool_t *p, char *d) -{ - cookie_dir_rec *dcfg; - - dcfg = (cookie_dir_rec *) apr_pcalloc(p, sizeof(cookie_dir_rec)); - dcfg->cookie_name = COOKIE_NAME; - dcfg->enabled = 0; - return dcfg; -} - -static const char *set_cookie_enable(cmd_parms *cmd, void *mconfig, int arg) -{ - cookie_dir_rec *dcfg = mconfig; - - dcfg->enabled = arg; - return NULL; -} - -static const char *set_cookie_exp(cmd_parms *parms, void *dummy, const char *arg) -{ - cookie_log_state *cls = ap_get_module_config(parms->server->module_config, - &usertrack_module); - time_t factor, modifier = 0; - time_t num = 0; - char *word; - - /* The simple case first - all numbers (we assume) */ - if (apr_isdigit(arg[0]) && apr_isdigit(arg[strlen(arg) - 1])) { - cls->expires = atol(arg); - return NULL; - } - - /* - * The harder case - stolen from mod_expires - * - * CookieExpires "[plus] {<num> <type>}*" - */ - - word = ap_getword_conf(parms->pool, &arg); - if (!strncasecmp(word, "plus", 1)) { - word = ap_getword_conf(parms->pool, &arg); - }; - - /* {<num> <type>}* */ - while (word[0]) { - /* <num> */ - if (apr_isdigit(word[0])) - num = atoi(word); - else - return "bad expires code, numeric value expected."; - - /* <type> */ - word = ap_getword_conf(parms->pool, &arg); - if (!word[0]) - return "bad expires code, missing <type>"; - - factor = 0; - if (!strncasecmp(word, "years", 1)) - factor = 60 * 60 * 24 * 365; - else if (!strncasecmp(word, "months", 2)) - factor = 60 * 60 * 24 * 30; - else if (!strncasecmp(word, "weeks", 1)) - factor = 60 * 60 * 24 * 7; - else if (!strncasecmp(word, "days", 1)) - factor = 60 * 60 * 24; - else if (!strncasecmp(word, "hours", 1)) - factor = 60 * 60; - else if (!strncasecmp(word, "minutes", 2)) - factor = 60; - else if (!strncasecmp(word, "seconds", 1)) - factor = 1; - else - return "bad expires code, unrecognized type"; - - modifier = modifier + factor * num; - - /* next <num> */ - word = ap_getword_conf(parms->pool, &arg); - } - - cls->expires = modifier; - - return NULL; -} - -static const char *set_cookie_name(cmd_parms *cmd, void *mconfig, const char *name) -{ - cookie_dir_rec *dcfg = (cookie_dir_rec *) mconfig; - - dcfg->cookie_name = apr_pstrdup(cmd->pool, name); - return NULL; -} - -static const command_rec cookie_log_cmds[] = { - AP_INIT_TAKE1("CookieExpires", set_cookie_exp, NULL, RSRC_CONF, - "an expiry date code"), - AP_INIT_FLAG("CookieTracking", set_cookie_enable, NULL, OR_FILEINFO, - "whether or not to enable cookies"), - AP_INIT_TAKE1("CookieName", set_cookie_name, NULL, OR_FILEINFO, - "name of the tracking cookie"), - {NULL} -}; - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_fixups(spot_cookie,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA usertrack_module = { - STANDARD20_MODULE_STUFF, - make_cookie_dir, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - make_cookie_log_state, /* server config */ - NULL, /* merge server configs */ - cookie_log_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/metadata/mod_usertrack.dsp b/modules/metadata/mod_usertrack.dsp deleted file mode 100644 index 47a70f1645..0000000000 --- a/modules/metadata/mod_usertrack.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_usertrack" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_usertrack - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_usertrack.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_usertrack.mak" CFG="mod_usertrack - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_usertrack - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_usertrack - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_usertrack - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_usertrack" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_usertrack.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_usertrack -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_usertrack.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_usertrack - -!ELSEIF "$(CFG)" == "mod_usertrack - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_usertrack" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_usertrack.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_usertrack -# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_usertrack.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_usertrack - -!ENDIF - -# Begin Target - -# Name "mod_usertrack - Win32 Release" -# Name "mod_usertrack - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_usertrack.c -# End Source File -# End Target -# End Project diff --git a/modules/metadata/mod_usertrack.exp b/modules/metadata/mod_usertrack.exp deleted file mode 100644 index 234a5f759d..0000000000 --- a/modules/metadata/mod_usertrack.exp +++ /dev/null @@ -1 +0,0 @@ -usertrack_module diff --git a/modules/metadata/mod_usertrack.mak b/modules/metadata/mod_usertrack.mak deleted file mode 100644 index 342ea22ce1..0000000000 --- a/modules/metadata/mod_usertrack.mak +++ /dev/null @@ -1,325 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_usertrack.dsp -!IF "$(CFG)" == "" -CFG=mod_usertrack - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_usertrack - Win32\ - Release. -!ENDIF - -!IF "$(CFG)" != "mod_usertrack - Win32 Release" && "$(CFG)" !=\ - "mod_usertrack - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_usertrack.mak" CFG="mod_usertrack - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_usertrack - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_usertrack - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_usertrack - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_usertrack.so" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libapr - Win32 Release"\ - "$(OUTDIR)\mod_usertrack.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_usertrack.idb" - -@erase "$(INTDIR)\mod_usertrack.obj" - -@erase "$(OUTDIR)\mod_usertrack.exp" - -@erase "$(OUTDIR)\mod_usertrack.lib" - -@erase "$(OUTDIR)\mod_usertrack.map" - -@erase "$(OUTDIR)\mod_usertrack.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_usertrack" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_usertrack.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_usertrack.pdb" /map:"$(INTDIR)\mod_usertrack.map"\ - /machine:I386 /out:"$(OUTDIR)\mod_usertrack.so"\ - /implib:"$(OUTDIR)\mod_usertrack.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_usertrack -LINK32_OBJS= \ - "$(INTDIR)\mod_usertrack.obj" \ - "..\..\Release\libhttpd.lib" \ - "..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_usertrack.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_usertrack - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_usertrack.so" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libapr - Win32 Debug"\ - "$(OUTDIR)\mod_usertrack.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_usertrack.idb" - -@erase "$(INTDIR)\mod_usertrack.obj" - -@erase "$(OUTDIR)\mod_usertrack.exp" - -@erase "$(OUTDIR)\mod_usertrack.lib" - -@erase "$(OUTDIR)\mod_usertrack.map" - -@erase "$(OUTDIR)\mod_usertrack.pdb" - -@erase "$(OUTDIR)\mod_usertrack.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I "..\..\os\win32" /I\ - "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D\ - "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_usertrack" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_usertrack.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"$(OUTDIR)\mod_usertrack.pdb" /map:"$(INTDIR)\mod_usertrack.map" /debug\ - /machine:I386 /out:"$(OUTDIR)\mod_usertrack.so"\ - /implib:"$(OUTDIR)\mod_usertrack.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_usertrack -LINK32_OBJS= \ - "$(INTDIR)\mod_usertrack.obj" \ - "..\..\Debug\libhttpd.lib" \ - "..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_usertrack.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_usertrack - Win32 Release" || "$(CFG)" ==\ - "mod_usertrack - Win32 Debug" - -!IF "$(CFG)" == "mod_usertrack - Win32 Release" - -"libapr - Win32 Release" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Release" - cd "..\..\modules\metadata" - -"libapr - Win32 ReleaseCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\metadata" - -!ELSEIF "$(CFG)" == "mod_usertrack - Win32 Debug" - -"libapr - Win32 Debug" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\libapr.mak CFG="libapr - Win32 Debug" - cd "..\..\modules\metadata" - -"libapr - Win32 DebugCLEAN" : - cd "..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libapr.mak CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\metadata" - -!ENDIF - -!IF "$(CFG)" == "mod_usertrack - Win32 Release" - -"libhttpd - Win32 Release" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Release" - cd ".\modules\metadata" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Release"\ - RECURSE=1 - cd ".\modules\metadata" - -!ELSEIF "$(CFG)" == "mod_usertrack - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) /F .\libhttpd.mak CFG="libhttpd - Win32 Debug" - cd ".\modules\metadata" - -"libhttpd - Win32 DebugCLEAN" : - cd "..\.." - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\libhttpd.mak CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\metadata" - -!ENDIF - -SOURCE=.\mod_usertrack.c -DEP_CPP_MOD_U=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_request.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\apr_buckets.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_ring.h"\ - "..\..\srclib\apr-util\include\apu.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_info.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\include\apr_user.h"\ - "..\..\srclib\apr\include\apr_want.h"\ - -NODEP_CPP_MOD_U=\ - "..\..\include\ap_config_auto.h"\ - - -"$(INTDIR)\mod_usertrack.obj" : $(SOURCE) $(DEP_CPP_MOD_U) "$(INTDIR)" - - - -!ENDIF - diff --git a/modules/proxy/.cvsignore b/modules/proxy/.cvsignore deleted file mode 100644 index efec0263f6..0000000000 --- a/modules/proxy/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -Debug -Release -Makefile -*.lo -*.slo -*.la -*.so -modules.mk -.deps -.libs diff --git a/modules/proxy/.indent.pro b/modules/proxy/.indent.pro deleted file mode 100644 index 20c2d83371..0000000000 --- a/modules/proxy/.indent.pro +++ /dev/null @@ -1,55 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 --TBUFF --TFILE --TTRANS --TUINT4 --T_trans --Tallow_options_t --Tapache_sfio --Tarray_header --Tbool_int --Tbuf_area --Tbuff_struct --Tbuffy --Tcmd_how --Tcmd_parms --Tcommand_rec --Tcommand_struct --Tconn_rec --Tcore_dir_config --Tcore_server_config --Tdir_maker_func --Tevent --Tglobals_s --Thandler_func --Thandler_rec --Tjoblist_s --Tlisten_rec --Tmerger_func --Tmode_t --Tmodule --Tmodule_struct --Tmutex --Tn_long --Tother_child_rec --Toverrides_t --Tparent_score --Tpid_t --Tpiped_log --Tpool --Trequest_rec --Trequire_line --Trlim_t --Tscoreboard --Tsemaphore --Tserver_addr_rec --Tserver_rec --Tserver_rec_chain --Tshort_score --Ttable --Ttable_entry --Tthread --Tu_wide_int --Tvtime_t --Twide_int --Tproxy_server_conf diff --git a/modules/proxy/Makefile.in b/modules/proxy/Makefile.in deleted file mode 100644 index 7c5c149d85..0000000000 --- a/modules/proxy/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ -# a modules Makefile has no explicit targets -- they will be defined by -# whatever modules are enabled. just grab special.mk to deal with this. -include $(top_srcdir)/build/special.mk diff --git a/modules/proxy/config.m4 b/modules/proxy/config.m4 deleted file mode 100644 index 325fca910f..0000000000 --- a/modules/proxy/config.m4 +++ /dev/null @@ -1,24 +0,0 @@ -dnl modules enabled in this directory by default - -APACHE_MODPATH_INIT(proxy) - -if test "$enable_proxy" = "shared"; then - proxy_mods_enable=shared -elif test "$enable_proxy" = "yes"; then - proxy_mods_enable=yes -else - proxy_mods_enable=no -fi - -proxy_objs="mod_proxy.lo proxy_util.lo" -APACHE_MODULE(proxy, Apache proxy module, $proxy_objs, , $proxy_mods_enable) - -proxy_connect_objs="proxy_connect.lo proxy_util.lo" -APACHE_MODULE(proxy_connect, Apache proxy CONNECT module, $proxy_connect_objs, , $proxy_mods_enable) -proxy_ftp_objs="proxy_ftp.lo proxy_util.lo" -APACHE_MODULE(proxy_ftp, Apache proxy FTP module, $proxy_ftp_objs, , $proxy_mods_enable) -proxy_http_objs="proxy_http.lo proxy_util.lo" -APACHE_MODULE(proxy_http, Apache proxy HTTP module, $proxy_http_objs, , $proxy_mods_enable) - - -APACHE_MODPATH_FINISH diff --git a/modules/proxy/libproxy.exp b/modules/proxy/libproxy.exp deleted file mode 100644 index a20f2378f5..0000000000 --- a/modules/proxy/libproxy.exp +++ /dev/null @@ -1 +0,0 @@ -proxy_module diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c deleted file mode 100644 index 0d6b28977f..0000000000 --- a/modules/proxy/mod_proxy.c +++ /dev/null @@ -1,768 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#define CORE_PRIVATE - -#include "mod_proxy.h" - -extern module AP_MODULE_DECLARE_DATA proxy_module; - - -/* - * A Web proxy module. Stages: - * - * translate_name: set filename to proxy:<URL> - * type_checker: set type to PROXY_MAGIC_TYPE if filename begins proxy: - * fix_ups: convert the URL stored in the filename to the - * canonical form. - * handler: handle proxy requests - */ - -/* -------------------------------------------------------------- */ -/* Translate the URL into a 'filename' */ - -static int alias_match(const char *uri, const char *alias_fakename) -{ - const char *end_fakename = alias_fakename + strlen(alias_fakename); - const char *aliasp = alias_fakename, *urip = uri; - - while (aliasp < end_fakename) { - if (*aliasp == '/') { - /* any number of '/' in the alias matches any number in - * the supplied URI, but there must be at least one... - */ - if (*urip != '/') - return 0; - - while (*aliasp == '/') - ++aliasp; - while (*urip == '/') - ++urip; - } - else { - /* Other characters are compared literally */ - if (*urip++ != *aliasp++) - return 0; - } - } - - /* Check last alias path component matched all the way */ - - if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/') - return 0; - - /* Return number of characters from URI which matched (may be - * greater than length of alias, since we may have matched - * doubled slashes) - */ - - return urip - uri; -} - -/* Detect if an absoluteURI should be proxied or not. Note that we - * have to do this during this phase because later phases are - * "short-circuiting"... i.e. translate_names will end when the first - * module returns OK. So for example, if the request is something like: - * - * GET http://othervhost/cgi-bin/printenv HTTP/1.0 - * - * mod_alias will notice the /cgi-bin part and ScriptAlias it and - * short-circuit the proxy... just because of the ordering in the - * configuration file. - */ -static int proxy_detect(request_rec *r) -{ - void *sconf = r->server->module_config; - proxy_server_conf *conf; - - conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); - - if (conf->req && r->parsed_uri.scheme) { - /* but it might be something vhosted */ - if (!(r->parsed_uri.hostname - && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r)) - && ap_matches_request_vhost(r, r->parsed_uri.hostname, - r->parsed_uri.port_str ? r->parsed_uri.port : ap_default_port(r)))) { - r->proxyreq = PROXYREQ_PROXY; - r->uri = r->unparsed_uri; - r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL); - r->handler = "proxy-server"; - } - } - /* We need special treatment for CONNECT proxying: it has no scheme part */ - else if (conf->req && r->method_number == M_CONNECT - && r->parsed_uri.hostname - && r->parsed_uri.port_str) { - r->proxyreq = PROXYREQ_PROXY; - r->uri = r->unparsed_uri; - r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL); - r->handler = "proxy-server"; - } - return DECLINED; -} - -static int proxy_trans(request_rec *r) -{ - void *sconf = r->server->module_config; - proxy_server_conf *conf = - (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); - int i, len; - struct proxy_alias *ent = (struct proxy_alias *) conf->aliases->elts; - - if (r->proxyreq) { - /* someone has already set up the proxy, it was possibly ourselves - * in proxy_detect - */ - return OK; - } - - /* XXX: since r->uri has been manipulated already we're not really - * compliant with RFC1945 at this point. But this probably isn't - * an issue because this is a hybrid proxy/origin server. - */ - - for (i = 0; i < conf->aliases->nelts; i++) { - len = alias_match(r->uri, ent[i].fake); - - if (len > 0) { - r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real, - r->uri + len, NULL); - r->handler = "proxy-server"; - r->proxyreq = PROXYREQ_REVERSE; - return OK; - } - } - return DECLINED; -} - -/* -------------------------------------------------------------- */ -/* Fixup the filename */ - -/* - * Canonicalise the URL - */ -static int proxy_fixup(request_rec *r) -{ - char *url, *p; - int access_status; - - if (!r->proxyreq || strncmp(r->filename, "proxy:", 6) != 0) - return DECLINED; - - url = &r->filename[6]; - - /* canonicalise each specific scheme */ - if ((access_status = proxy_run_canon_handler(r, url))) { - return access_status; - } - - p = strchr(url, ':'); - if (p == NULL || p == url) - return HTTP_BAD_REQUEST; - - return OK; /* otherwise; we've done the best we can */ -} - -/* Send a redirection if the request contains a hostname which is not */ -/* fully qualified, i.e. doesn't have a domain name appended. Some proxy */ -/* servers like Netscape's allow this and access hosts from the local */ -/* domain in this case. I think it is better to redirect to a FQDN, since */ -/* these will later be found in the bookmarks files. */ -/* The "ProxyDomain" directive determines what domain will be appended */ -static int proxy_needsdomain(request_rec *r, const char *url, const char *domain) -{ - char *nuri; - const char *ref; - - /* We only want to worry about GETs */ - if (!r->proxyreq || r->method_number != M_GET || !r->parsed_uri.hostname) - return DECLINED; - - /* If host does contain a dot already, or it is "localhost", decline */ - if (strchr(r->parsed_uri.hostname, '.') != NULL - || strcasecmp(r->parsed_uri.hostname, "localhost") == 0) - return DECLINED; /* host name has a dot already */ - - ref = apr_table_get(r->headers_in, "Referer"); - - /* Reassemble the request, but insert the domain after the host name */ - /* Note that the domain name always starts with a dot */ - r->parsed_uri.hostname = apr_pstrcat(r->pool, r->parsed_uri.hostname, - domain, NULL); - nuri = ap_unparse_uri_components(r->pool, - &r->parsed_uri, - UNP_REVEALPASSWORD); - - apr_table_set(r->headers_out, "Location", nuri); - ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r, - "Domain missing: %s sent to %s%s%s", r->uri, - ap_unparse_uri_components(r->pool, &r->parsed_uri, - UNP_OMITUSERINFO), - ref ? " from " : "", ref ? ref : ""); - - return HTTP_MOVED_PERMANENTLY; -} - -/* -------------------------------------------------------------- */ -/* Invoke handler */ - -static int proxy_handler(request_rec *r) -{ - char *url, *scheme, *p; - const char *p2; - void *sconf = r->server->module_config; - proxy_server_conf *conf = (proxy_server_conf *) - ap_get_module_config(sconf, &proxy_module); - apr_array_header_t *proxies = conf->proxies; - struct proxy_remote *ents = (struct proxy_remote *) proxies->elts; - int i, rc, access_status; - int direct_connect = 0; - const char *str; - long maxfwd; - - /* is this for us? */ - if (!r->proxyreq || strncmp(r->filename, "proxy:", 6) != 0) - return DECLINED; - - /* handle max-forwards / OPTIONS / TRACE */ - if ((str = apr_table_get(r->headers_in, "Max-Forwards"))) { - maxfwd = strtol(str, NULL, 10); - if (maxfwd < 1) { - switch (r->method_number) { - case M_TRACE: { - int access_status; - r->proxyreq = PROXYREQ_NONE; - if ((access_status = ap_send_http_trace(r))) - ap_die(access_status, r); - else - ap_finalize_request_protocol(r); - return OK; - } - case M_OPTIONS: { - int access_status; - r->proxyreq = PROXYREQ_NONE; - if ((access_status = ap_send_http_options(r))) - ap_die(access_status, r); - else - ap_finalize_request_protocol(r); - return OK; - } - default: { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Max-Forwards has reached zero - proxy loop?"); - } - } - } - maxfwd = (maxfwd > 0) ? maxfwd - 1 : 0; - } - else { - /* set configured max-forwards */ - maxfwd = conf->maxfwd; - } - apr_table_setn(r->headers_in, "Max-Forwards", - apr_psprintf(r->pool, "%ld", (maxfwd > 0) ? maxfwd : 0)); - - if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) - return rc; - - url = r->filename + 6; - p = strchr(url, ':'); - if (p == NULL) - return HTTP_BAD_REQUEST; - - /* If the host doesn't have a domain name, add one and redirect. */ - if (conf->domain != NULL) { - rc = proxy_needsdomain(r, url, conf->domain); - if (ap_is_HTTP_REDIRECT(rc)) - return HTTP_MOVED_PERMANENTLY; - } - - *p = '\0'; - scheme = apr_pstrdup(r->pool, url); - *p = ':'; - - /* Check URI's destination host against NoProxy hosts */ - /* Bypass ProxyRemote server lookup if configured as NoProxy */ - /* we only know how to handle communication to a proxy via http */ - /*if (strcasecmp(scheme, "http") == 0) */ - { - int ii; - struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts; - - for (direct_connect = ii = 0; ii < conf->dirconn->nelts && !direct_connect; ii++) { - direct_connect = list[ii].matcher(&list[ii], r); - } -#if DEBUGGING - ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r, - (direct_connect) ? "NoProxy for %s" : "UseProxy for %s", - r->uri); -#endif - } - - /* firstly, try a proxy, unless a NoProxy directive is active */ - if (!direct_connect) { - for (i = 0; i < proxies->nelts; i++) { - p2 = ap_strchr_c(ents[i].scheme, ':'); /* is it a partial URL? */ - if (strcmp(ents[i].scheme, "*") == 0 || - (p2 == NULL && strcasecmp(scheme, ents[i].scheme) == 0) || - (p2 != NULL && - strncasecmp(url, ents[i].scheme, strlen(ents[i].scheme)) == 0)) { - - /* handle the scheme */ - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, - "Trying to run scheme_handler against proxy"); - access_status = proxy_run_scheme_handler(r, conf, url, ents[i].hostname, ents[i].port); - - /* an error or success */ - if (access_status != DECLINED && access_status != HTTP_BAD_GATEWAY) { - return access_status; - } - /* we failed to talk to the upstream proxy */ - } - } - } - - /* otherwise, try it direct */ - /* N.B. what if we're behind a firewall, where we must use a proxy or - * give up?? - */ - - /* handle the scheme */ - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, - "Trying to run scheme_handler"); - access_status = proxy_run_scheme_handler(r, conf, url, NULL, 0); - if (DECLINED == access_status) { - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, - "Neither CONNECT, HTTP or FTP for %s", - r->uri); - return HTTP_FORBIDDEN; - } - return access_status; -} - -/* -------------------------------------------------------------- */ -/* Setup configurable data */ - -static void * create_proxy_config(apr_pool_t *p, server_rec *s) -{ - proxy_server_conf *ps = ap_pcalloc(p, sizeof(proxy_server_conf)); - - ps->proxies = ap_make_array(p, 10, sizeof(struct proxy_remote)); - ps->aliases = ap_make_array(p, 10, sizeof(struct proxy_alias)); - ps->raliases = ap_make_array(p, 10, sizeof(struct proxy_alias)); - ps->noproxies = ap_make_array(p, 10, sizeof(struct noproxy_entry)); - ps->dirconn = ap_make_array(p, 10, sizeof(struct dirconn_entry)); - ps->allowed_connect_ports = ap_make_array(p, 10, sizeof(int)); - ps->domain = NULL; - ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */ - ps->viaopt_set = 0; /* 0 means default */ - ps->req = 0; - ps->req_set = 0; - ps->recv_buffer_size = 0; /* this default was left unset for some reason */ - ps->recv_buffer_size_set = 0; - ps->maxfwd = DEFAULT_MAX_FORWARDS; - ps->maxfwd_set = 0; - - return ps; -} - -static void * merge_proxy_config(apr_pool_t *p, void *basev, void *overridesv) -{ - proxy_server_conf *ps = ap_pcalloc(p, sizeof(proxy_server_conf)); - proxy_server_conf *base = (proxy_server_conf *) basev; - proxy_server_conf *overrides = (proxy_server_conf *) overridesv; - - ps->proxies = ap_append_arrays(p, base->proxies, overrides->proxies); - ps->aliases = ap_append_arrays(p, base->aliases, overrides->aliases); - ps->raliases = ap_append_arrays(p, base->raliases, overrides->raliases); - ps->noproxies = ap_append_arrays(p, base->noproxies, overrides->noproxies); - ps->dirconn = ap_append_arrays(p, base->dirconn, overrides->dirconn); - ps->allowed_connect_ports = ap_append_arrays(p, base->allowed_connect_ports, overrides->allowed_connect_ports); - - ps->domain = (overrides->domain == NULL) ? base->domain : overrides->domain; - ps->viaopt = (overrides->viaopt_set == 0) ? base->viaopt : overrides->viaopt; - ps->req = (overrides->req_set == 0) ? base->req : overrides->req; - ps->recv_buffer_size = (overrides->recv_buffer_size_set == 0) ? base->recv_buffer_size : overrides->recv_buffer_size; - ps->maxfwd = (overrides->maxfwd_set == 0) ? base->maxfwd : overrides->maxfwd; - - return ps; -} - -static const char * - add_proxy(cmd_parms *cmd, void *dummy, const char *f1, const char *r1) -{ - server_rec *s = cmd->server; - proxy_server_conf *conf = - (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module); - struct proxy_remote *new; - char *p, *q; - char *r, *f, *scheme; - int port; - - r = apr_pstrdup(cmd->pool, r1); - scheme = apr_pstrdup(cmd->pool, r1); - f = apr_pstrdup(cmd->pool, f1); - p = strchr(r, ':'); - if (p == NULL || p[1] != '/' || p[2] != '/' || p[3] == '\0') { - return "ProxyRemote: Bad syntax for a remote proxy server"; - } - else { - scheme[p-r] = 0; - } - q = strchr(p + 3, ':'); - if (q != NULL) { - if (sscanf(q + 1, "%u", &port) != 1 || port > 65535) - return "ProxyRemote: Bad syntax for a remote proxy server (bad port number)"; - *q = '\0'; - } - else - port = -1; - *p = '\0'; - if (strchr(f, ':') == NULL) - ap_str_tolower(f); /* lowercase scheme */ - ap_str_tolower(p + 3); /* lowercase hostname */ - - if (port == -1) { - port = ap_default_port_for_scheme(scheme); - } - - new = apr_array_push(conf->proxies); - new->scheme = f; - new->protocol = r; - new->hostname = p + 3; - new->port = port; - return NULL; -} - -static const char * - add_pass(cmd_parms *cmd, void *dummy, const char *f, const char *r) -{ - server_rec *s = cmd->server; - proxy_server_conf *conf = - (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module); - struct proxy_alias *new; - - new = apr_array_push(conf->aliases); - new->fake = f; - new->real = r; - return NULL; -} - -static const char * - add_pass_reverse(cmd_parms *cmd, void *dummy, const char *f, const char *r) -{ - server_rec *s = cmd->server; - proxy_server_conf *conf; - struct proxy_alias *new; - - conf = (proxy_server_conf *)ap_get_module_config(s->module_config, - &proxy_module); - new = apr_array_push(conf->raliases); - new->fake = f; - new->real = r; - return NULL; -} - -static const char * - set_proxy_exclude(cmd_parms *parms, void *dummy, const char *arg) -{ - server_rec *s = parms->server; - proxy_server_conf *conf = - ap_get_module_config(s->module_config, &proxy_module); - struct noproxy_entry *new; - struct noproxy_entry *list = (struct noproxy_entry *) conf->noproxies->elts; - struct apr_sockaddr_t *addr; - int found = 0; - int i; - - /* Don't duplicate entries */ - for (i = 0; i < conf->noproxies->nelts; i++) { - if (apr_strnatcasecmp(arg, list[i].name) == 0) { /* ignore case for host names */ - found = 1; - } - } - - if (!found) { - new = apr_array_push(conf->noproxies); - new->name = arg; - if (APR_SUCCESS == apr_sockaddr_info_get(&addr, new->name, APR_UNSPEC, 0, 0, parms->pool)) { - new->addr = addr; - } - else { - new->addr = NULL; - } - } - return NULL; -} - -/* - * Set the ports CONNECT can use - */ -static const char * - set_allowed_ports(cmd_parms *parms, void *dummy, const char *arg) -{ - server_rec *s = parms->server; - proxy_server_conf *conf = - ap_get_module_config(s->module_config, &proxy_module); - int *New; - - if (!apr_isdigit(arg[0])) - return "AllowCONNECT: port number must be numeric"; - - New = apr_array_push(conf->allowed_connect_ports); - *New = atoi(arg); - return NULL; -} - -/* Similar to set_proxy_exclude(), but defining directly connected hosts, - * which should never be accessed via the configured ProxyRemote servers - */ -static const char * - set_proxy_dirconn(cmd_parms *parms, void *dummy, const char *arg) -{ - server_rec *s = parms->server; - proxy_server_conf *conf = - ap_get_module_config(s->module_config, &proxy_module); - struct dirconn_entry *New; - struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts; - int found = 0; - int i; - - /* Don't duplicate entries */ - for (i = 0; i < conf->dirconn->nelts; i++) { - if (strcasecmp(arg, list[i].name) == 0) - found = 1; - } - - if (!found) { - New = apr_array_push(conf->dirconn); - New->name = apr_pstrdup(parms->pool, arg); - New->hostentry = NULL; - - if (ap_proxy_is_ipaddr(New, parms->pool)) { -#if DEBUGGING - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Parsed addr %s", inet_ntoa(New->addr)); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Parsed mask %s", inet_ntoa(New->mask)); -#endif - } - else if (ap_proxy_is_domainname(New, parms->pool)) { - ap_str_tolower(New->name); -#if DEBUGGING - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Parsed domain %s", New->name); -#endif - } - else if (ap_proxy_is_hostname(New, parms->pool)) { - ap_str_tolower(New->name); -#if DEBUGGING - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Parsed host %s", New->name); -#endif - } - else { - ap_proxy_is_word(New, parms->pool); -#if DEBUGGING - fprintf(stderr, "Parsed word %s\n", New->name); -#endif - } - } - return NULL; -} - -static const char * - set_proxy_domain(cmd_parms *parms, void *dummy, const char *arg) -{ - proxy_server_conf *psf = - ap_get_module_config(parms->server->module_config, &proxy_module); - - if (arg[0] != '.') - return "ProxyDomain: domain name must start with a dot."; - - psf->domain = arg; - return NULL; -} - -static const char * - set_proxy_req(cmd_parms *parms, void *dummy, int flag) -{ - proxy_server_conf *psf = - ap_get_module_config(parms->server->module_config, &proxy_module); - - psf->req = flag; - psf->req_set = 1; - return NULL; -} - -static const char * - set_recv_buffer_size(cmd_parms *parms, void *dummy, const char *arg) -{ - proxy_server_conf *psf = - ap_get_module_config(parms->server->module_config, &proxy_module); - int s = atoi(arg); - if (s < 512 && s != 0) { - return "ProxyReceiveBufferSize must be >= 512 bytes, or 0 for system default."; - } - - psf->recv_buffer_size = s; - psf->recv_buffer_size_set = 1; - return NULL; -} - -static const char * - set_max_forwards(cmd_parms *parms, void *dummy, const char *arg) -{ - proxy_server_conf *psf = - ap_get_module_config(parms->server->module_config, &proxy_module); - long s = atol(arg); - if (s < 0) { - return "ProxyMaxForwards must be greater or equal to zero.."; - } - - psf->maxfwd = s; - psf->maxfwd_set = 1; - return NULL; -} - -static const char* - set_via_opt(cmd_parms *parms, void *dummy, const char *arg) -{ - proxy_server_conf *psf = - ap_get_module_config(parms->server->module_config, &proxy_module); - - if (strcasecmp(arg, "Off") == 0) - psf->viaopt = via_off; - else if (strcasecmp(arg, "On") == 0) - psf->viaopt = via_on; - else if (strcasecmp(arg, "Block") == 0) - psf->viaopt = via_block; - else if (strcasecmp(arg, "Full") == 0) - psf->viaopt = via_full; - else { - return "ProxyVia must be one of: " - "off | on | full | block"; - } - - psf->viaopt_set = 1; - return NULL; -} - -static const command_rec proxy_cmds[] = -{ - AP_INIT_FLAG("ProxyRequests", set_proxy_req, NULL, RSRC_CONF, - "on if the true proxy requests should be accepted"), - AP_INIT_TAKE2("ProxyRemote", add_proxy, NULL, RSRC_CONF, - "a scheme, partial URL or '*' and a proxy server"), - AP_INIT_TAKE2("ProxyPass", add_pass, NULL, RSRC_CONF, - "a virtual path and a URL"), - AP_INIT_TAKE2("ProxyPassReverse", add_pass_reverse, NULL, RSRC_CONF, - "a virtual path and a URL for reverse proxy behaviour"), - AP_INIT_ITERATE("ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF, - "A list of names, hosts or domains to which the proxy will not connect"), - AP_INIT_TAKE1("ProxyReceiveBufferSize", set_recv_buffer_size, NULL, RSRC_CONF, - "Receive buffer size for outgoing HTTP and FTP connections in bytes"), - AP_INIT_TAKE1("ProxyMaxForwards", set_max_forwards, NULL, RSRC_CONF, - "The maximum number of proxies a request may be forwarded through."), - AP_INIT_ITERATE("NoProxy", set_proxy_dirconn, NULL, RSRC_CONF, - "A list of domains, hosts, or subnets to which the proxy will connect directly"), - AP_INIT_TAKE1("ProxyDomain", set_proxy_domain, NULL, RSRC_CONF, - "The default intranet domain name (in absence of a domain in the URL)"), - AP_INIT_ITERATE("AllowCONNECT", set_allowed_ports, NULL, RSRC_CONF, - "A list of ports which CONNECT may connect to"), - AP_INIT_TAKE1("ProxyVia", set_via_opt, NULL, RSRC_CONF, - "Configure Via: proxy header header to one of: on | off | block | full"), - {NULL} -}; - -static void register_hooks(apr_pool_t *p) -{ - /* handler */ - ap_hook_handler(proxy_handler, NULL, NULL, APR_HOOK_FIRST); - /* filename-to-URI translation */ - ap_hook_translate_name(proxy_trans, NULL, NULL, APR_HOOK_FIRST); - /* fixups */ - ap_hook_fixups(proxy_fixup, NULL, NULL, APR_HOOK_FIRST); - /* post read_request handling */ - ap_hook_post_read_request(proxy_detect, NULL, NULL, APR_HOOK_FIRST); -} - -module AP_MODULE_DECLARE_DATA proxy_module = -{ - STANDARD20_MODULE_STUFF, - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - create_proxy_config, /* create per-server config structure */ - merge_proxy_config, /* merge per-server config structures */ - proxy_cmds, /* command table */ - register_hooks -}; - -APR_HOOK_STRUCT( - APR_HOOK_LINK(scheme_handler) - APR_HOOK_LINK(canon_handler) -) - -APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, scheme_handler, - (request_rec *r, proxy_server_conf *conf, - char *url, const char *proxyhost, - apr_port_t proxyport),(r,conf,url, - proxyhost,proxyport),DECLINED) -APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, canon_handler, - (request_rec *r, char *url),(r, - url),DECLINED) diff --git a/modules/proxy/mod_proxy.dsp b/modules/proxy/mod_proxy.dsp deleted file mode 100644 index d57baaa0e5..0000000000 --- a/modules/proxy/mod_proxy.dsp +++ /dev/null @@ -1,123 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_proxy" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_proxy - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_proxy.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_proxy.mak" CFG="mod_proxy - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_proxy - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_proxy - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_proxy - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /I "..\..\include" /I "..\..\os\win32" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_proxy" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_proxy.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_proxy -# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_proxy.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_proxy - -!ELSEIF "$(CFG)" == "mod_proxy - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /I "..\..\include" /I "..\..\os\win32" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_proxy" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_proxy.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_proxy -# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_proxy.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_proxy - -!ENDIF - -# Begin Target - -# Name "mod_proxy - Win32 Release" -# Name "mod_proxy - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" -# Begin Source File - -SOURCE=.\mod_proxy.c -# End Source File -# Begin Source File - -SOURCE=.\proxy_connect.c -# End Source File -# Begin Source File - -SOURCE=.\proxy_ftp.c -# End Source File -# Begin Source File - -SOURCE=.\proxy_http.c -# End Source File -# Begin Source File - -SOURCE=.\proxy_util.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" -# Begin Source File - -SOURCE=.\mod_proxy.h -# End Source File -# End Group -# End Target -# End Project diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h deleted file mode 100644 index c614605a36..0000000000 --- a/modules/proxy/mod_proxy.h +++ /dev/null @@ -1,259 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef MOD_PROXY_H -#define MOD_PROXY_H - -/* - * Main include file for the Apache proxy - */ - -/* - - Also note numerous FIXMEs and CHECKMEs which should be eliminated. - - This code is once again experimental! - - Things to do: - - 1. Make it completely work (for FTP too) - - 2. HTTP/1.1 - - Chuck Murcko <chuck@topsail.org> 02-06-01 - - */ - -#define CORE_PRIVATE - -#include "apr_hooks.h" -#include "apr.h" -#include "apr_compat.h" -#include "apr_lib.h" -#include "apr_strings.h" -#include "apr_buckets.h" -#include "apr_md5.h" -#include "apr_pools.h" -#include "apr_strings.h" - -#include "httpd.h" -#include "http_config.h" -#include "ap_config.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_request.h" -#include "http_vhost.h" -#include "http_main.h" -#include "http_log.h" -#include "http_connection.h" -#include "util_filter.h" -#include "util_date.h" -#include "util_uri.h" -#include "mod_core.h" - - -#if APR_HAVE_NETDB_H -#include <netdb.h> -#endif -#if APR_HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#if APR_HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif -#if APR_HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif - -/* for proxy_canonenc() */ -enum enctype { - enc_path, enc_search, enc_user, enc_fpath, enc_parm -}; - -#if APR_CHARSET_EBCDIC -#define CRLF "\r\n" -#else /*APR_CHARSET_EBCDIC*/ -#define CRLF "\015\012" -#endif /*APR_CHARSET_EBCDIC*/ - -/* default Max-Forwards header setting */ -#define DEFAULT_MAX_FORWARDS 10 - -/* static information about a remote proxy */ -struct proxy_remote { - const char *scheme; /* the schemes handled by this proxy, or '*' */ - const char *protocol; /* the scheme used to talk to this proxy */ - const char *hostname; /* the hostname of this proxy */ - int port; /* the port for this proxy */ -}; - -struct proxy_alias { - const char *real; - const char *fake; -}; - -struct dirconn_entry { - char *name; - struct in_addr addr, mask; - struct hostent *hostentry; - int (*matcher) (struct dirconn_entry * This, request_rec *r); -}; - -struct noproxy_entry { - const char *name; - struct apr_sockaddr_t *addr; -}; - -typedef struct { - apr_array_header_t *proxies; - apr_array_header_t *aliases; - apr_array_header_t *raliases; - apr_array_header_t *noproxies; - apr_array_header_t *dirconn; - apr_array_header_t *allowed_connect_ports; - const char *domain; /* domain name to use in absence of a domain name in the request */ - int req; /* true if proxy requests are enabled */ - char req_set; - enum { - via_off, - via_on, - via_block, - via_full - } viaopt; /* how to deal with proxy Via: headers */ - char viaopt_set; - size_t recv_buffer_size; - char recv_buffer_size_set; - long maxfwd; - char maxfwd_set; -} proxy_server_conf; - -struct per_thread_data { - struct hostent hpbuf; - u_long ipaddr; - char *charpbuf[2]; -}; - -typedef struct { - conn_rec *connection; - char *hostname; - apr_port_t port; -} proxy_conn_rec; - -typedef struct { - float cache_completion; /* completion percentage */ - int content_length; /* length of the content */ -} proxy_completion; - - -/* hooks */ - -/* Create a set of PROXY_DECLARE(type), PROXY_DECLARE_NONSTD(type) and - * PROXY_DECLARE_DATA with appropriate export and import tags for the platform - */ -#if !defined(WIN32) -#define PROXY_DECLARE(type) type -#define PROXY_DECLARE_NONSTD(type) type -#define PROXY_DECLARE_DATA -#elif defined(PROXY_DECLARE_STATIC) -#define PROXY_DECLARE(type) type __stdcall -#define PROXY_DECLARE_NONSTD(type) type -#define PROXY_DECLARE_DATA -#elif defined(PROXY_DECLARE_EXPORT) -#define PROXY_DECLARE(type) __declspec(dllexport) type __stdcall -#define PROXY_DECLARE_NONSTD(type) __declspec(dllexport) type -#define PROXY_DECLARE_DATA __declspec(dllexport) -#else -#define PROXY_DECLARE(type) __declspec(dllimport) type __stdcall -#define PROXY_DECLARE_NONSTD(type) __declspec(dllimport) type -#define PROXY_DECLARE_DATA __declspec(dllimport) -#endif - -APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, scheme_handler, (request_rec *r, - proxy_server_conf *conf, char *url, - const char *proxyhost, apr_port_t proxyport)) -APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, canon_handler, (request_rec *r, - char *url)) - -/* proxy_util.c */ - -request_rec *make_fake_req(conn_rec *c, request_rec *r); -int ap_proxy_hex2c(const char *x); -void ap_proxy_c2hex(int ch, char *x); -char *ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t, - int isenc); -char *ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp, - char **passwordp, char **hostp, apr_port_t *port); -const char *ap_proxy_date_canon(apr_pool_t *p, const char *x); -apr_table_t *ap_proxy_read_headers(request_rec *r, request_rec *rp, char *buffer, int size, conn_rec *c); -int ap_proxy_liststr(const char *list, const char *val); -char *ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val); -int ap_proxy_hex2sec(const char *x); -void ap_proxy_sec2hex(int t, char *y); -const char *ap_proxy_host2addr(const char *host, struct hostent *reqhp); -int ap_proxyerror(request_rec *r, int statuscode, const char *message); -int ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p); -int ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p); -int ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p); -int ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p); -int ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, apr_sockaddr_t *uri_addr); -int ap_proxy_pre_http_connection(conn_rec *c, request_rec *r); -apr_status_t ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb, char *buff, size_t bufflen, int *eos); -void ap_proxy_reset_output_filters(conn_rec *c); - - -#endif /*MOD_PROXY_H*/ diff --git a/modules/proxy/mod_proxy.mak b/modules/proxy/mod_proxy.mak deleted file mode 100644 index 3d13f3d1ac..0000000000 --- a/modules/proxy/mod_proxy.mak +++ /dev/null @@ -1,573 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_proxy.dsp -!IF "$(CFG)" == "" -CFG=mod_proxy - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_proxy - Win32 Release. -!ENDIF - -!IF "$(CFG)" != "mod_proxy - Win32 Release" && "$(CFG)" !=\ - "mod_proxy - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_proxy.mak" CFG="mod_proxy - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_proxy - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_proxy - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_proxy - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_proxy.so" - -!ELSE - -ALL : "libaprutil - Win32 Release" "libhttpd - Win32 Release"\ - "libapr - Win32 Release" "$(OUTDIR)\mod_proxy.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"\ - "libaprutil - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_proxy.idb" - -@erase "$(INTDIR)\mod_proxy.obj" - -@erase "$(INTDIR)\proxy_connect.obj" - -@erase "$(INTDIR)\proxy_ftp.obj" - -@erase "$(INTDIR)\proxy_http.obj" - -@erase "$(INTDIR)\proxy_util.obj" - -@erase "$(OUTDIR)\mod_proxy.exp" - -@erase "$(OUTDIR)\mod_proxy.lib" - -@erase "$(OUTDIR)\mod_proxy.map" - -@erase "$(OUTDIR)\mod_proxy.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\..\srclib\apr\include" /I\ - "../../srclib/apr-util/include" /I "..\..\include" /I "..\..\os\win32" /D\ - "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_proxy" /FD\ - /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_proxy.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows\ - /dll /incremental:no /pdb:"$(OUTDIR)\mod_proxy.pdb"\ - /map:"$(INTDIR)\mod_proxy.map" /machine:I386 /out:"$(OUTDIR)\mod_proxy.so"\ - /implib:"$(OUTDIR)\mod_proxy.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy -LINK32_OBJS= \ - "$(INTDIR)\mod_proxy.obj" \ - "$(INTDIR)\proxy_connect.obj" \ - "$(INTDIR)\proxy_ftp.obj" \ - "$(INTDIR)\proxy_http.obj" \ - "$(INTDIR)\proxy_util.obj" \ - "..\..\Release\libhttpd.lib" \ - "..\..\srclib\apr-util\Release\libaprutil.lib" \ - "..\..\srclib\apr\Release\libapr.lib" - -"$(OUTDIR)\mod_proxy.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "mod_proxy - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_proxy.so" - -!ELSE - -ALL : "libaprutil - Win32 Debug" "libhttpd - Win32 Debug"\ - "libapr - Win32 Debug" "$(OUTDIR)\mod_proxy.so" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"\ - "libaprutil - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_proxy.idb" - -@erase "$(INTDIR)\mod_proxy.obj" - -@erase "$(INTDIR)\proxy_connect.obj" - -@erase "$(INTDIR)\proxy_ftp.obj" - -@erase "$(INTDIR)\proxy_http.obj" - -@erase "$(INTDIR)\proxy_util.obj" - -@erase "$(OUTDIR)\mod_proxy.exp" - -@erase "$(OUTDIR)\mod_proxy.lib" - -@erase "$(OUTDIR)\mod_proxy.map" - -@erase "$(OUTDIR)\mod_proxy.pdb" - -@erase "$(OUTDIR)\mod_proxy.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\..\srclib\apr\include" /I\ - "../../srclib/apr-util/include" /I "..\..\include" /I "..\..\os\win32" /D\ - "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_proxy" /FD\ - /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_proxy.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows\ - /dll /incremental:no /pdb:"$(OUTDIR)\mod_proxy.pdb"\ - /map:"$(INTDIR)\mod_proxy.map" /debug /machine:I386\ - /out:"$(OUTDIR)\mod_proxy.so" /implib:"$(OUTDIR)\mod_proxy.lib"\ - /base:@..\..\os\win32\BaseAddr.ref,mod_proxy -LINK32_OBJS= \ - "$(INTDIR)\mod_proxy.obj" \ - "$(INTDIR)\proxy_connect.obj" \ - "$(INTDIR)\proxy_ftp.obj" \ - "$(INTDIR)\proxy_http.obj" \ - "$(INTDIR)\proxy_util.obj" \ - "..\..\Debug\libhttpd.lib" \ - "..\..\srclib\apr-util\Debug\libaprutil.lib" \ - "..\..\srclib\apr\Debug\libapr.lib" - -"$(OUTDIR)\mod_proxy.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "mod_proxy - Win32 Release" || "$(CFG)" ==\ - "mod_proxy - Win32 Debug" -SOURCE=.\mod_proxy.c -DEP_CPP_MOD_P=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\http_request.h"\ - "..\..\include\http_vhost.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_date.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\ap_buckets.h"\ - "..\..\srclib\apr-util\include\ap_hooks.h"\ - "..\..\srclib\apr-util\include\ap_ring.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_compat.h"\ - "..\..\srclib\apr\include\apr_dso.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_lock.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\network_io\os2\os2nerrno.h"\ - ".\mod_proxy.h"\ - -NODEP_CPP_MOD_P=\ - "..\..\include\ap_config_auto.h"\ - "..\..\include\ap_config_path.h"\ - ".\ap_cache.h"\ - ".\buff.h"\ - - -"$(INTDIR)\mod_proxy.obj" : $(SOURCE) $(DEP_CPP_MOD_P) "$(INTDIR)" - - -SOURCE=.\proxy_connect.c -DEP_CPP_PROXY=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_main.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\ap_buckets.h"\ - "..\..\srclib\apr-util\include\ap_hooks.h"\ - "..\..\srclib\apr-util\include\ap_ring.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_compat.h"\ - "..\..\srclib\apr\include\apr_dso.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_lock.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\network_io\os2\os2nerrno.h"\ - ".\mod_proxy.h"\ - -NODEP_CPP_PROXY=\ - "..\..\include\ap_config_auto.h"\ - "..\..\include\ap_config_path.h"\ - ".\ap_cache.h"\ - ".\buff.h"\ - - -"$(INTDIR)\proxy_connect.obj" : $(SOURCE) $(DEP_CPP_PROXY) "$(INTDIR)" - - -SOURCE=.\proxy_ftp.c -DEP_CPP_PROXY_=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_main.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\ap_buckets.h"\ - "..\..\srclib\apr-util\include\ap_hooks.h"\ - "..\..\srclib\apr-util\include\ap_ring.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_compat.h"\ - "..\..\srclib\apr\include\apr_dso.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_lock.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\network_io\os2\os2nerrno.h"\ - ".\mod_proxy.h"\ - -NODEP_CPP_PROXY_=\ - "..\..\include\ap_config_auto.h"\ - "..\..\include\ap_config_path.h"\ - ".\ap_cache.h"\ - ".\buff.h"\ - - -"$(INTDIR)\proxy_ftp.obj" : $(SOURCE) $(DEP_CPP_PROXY_) "$(INTDIR)" - - -SOURCE=.\proxy_http.c -DEP_CPP_PROXY_H=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_connection.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_main.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_date.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\ap_buckets.h"\ - "..\..\srclib\apr-util\include\ap_hooks.h"\ - "..\..\srclib\apr-util\include\ap_ring.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_compat.h"\ - "..\..\srclib\apr\include\apr_dso.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_lock.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\network_io\os2\os2nerrno.h"\ - ".\mod_proxy.h"\ - -NODEP_CPP_PROXY_H=\ - "..\..\include\ap_config_auto.h"\ - "..\..\include\ap_config_path.h"\ - ".\ap_cache.h"\ - ".\buff.h"\ - - -"$(INTDIR)\proxy_http.obj" : $(SOURCE) $(DEP_CPP_PROXY_H) "$(INTDIR)" - - -SOURCE=.\proxy_util.c -DEP_CPP_PROXY_U=\ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_main.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\httpd.h"\ - "..\..\include\pcreposix.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_date.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_uri.h"\ - "..\..\os\win32\os.h"\ - "..\..\srclib\apr-util\include\ap_buckets.h"\ - "..\..\srclib\apr-util\include\ap_hooks.h"\ - "..\..\srclib\apr-util\include\ap_ring.h"\ - "..\..\srclib\apr\include\apr.h"\ - "..\..\srclib\apr\include\apr_compat.h"\ - "..\..\srclib\apr\include\apr_dso.h"\ - "..\..\srclib\apr\include\apr_errno.h"\ - "..\..\srclib\apr\include\apr_file_io.h"\ - "..\..\srclib\apr\include\apr_general.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_lock.h"\ - "..\..\srclib\apr\include\apr_md5.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_network_io.h"\ - "..\..\srclib\apr\include\apr_pools.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_tables.h"\ - "..\..\srclib\apr\include\apr_thread_proc.h"\ - "..\..\srclib\apr\include\apr_time.h"\ - "..\..\srclib\apr\include\apr_xlate.h"\ - "..\..\srclib\apr\network_io\os2\os2nerrno.h"\ - ".\mod_proxy.h"\ - -NODEP_CPP_PROXY_U=\ - "..\..\include\ap_config_auto.h"\ - "..\..\include\ap_config_path.h"\ - ".\ap_cache.h"\ - ".\buff.h"\ - - -"$(INTDIR)\proxy_util.obj" : $(SOURCE) $(DEP_CPP_PROXY_U) "$(INTDIR)" - - -!IF "$(CFG)" == "mod_proxy - Win32 Release" - -"libapr - Win32 Release" : - cd "\test\httpd-2.0\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" - cd "..\..\modules\proxy" - -"libapr - Win32 ReleaseCLEAN" : - cd "\test\httpd-2.0\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libapr.mak" CFG="libapr - Win32 Release"\ - RECURSE=1 - cd "..\..\modules\proxy" - -!ELSEIF "$(CFG)" == "mod_proxy - Win32 Debug" - -"libapr - Win32 Debug" : - cd "\test\httpd-2.0\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" - cd "..\..\modules\proxy" - -"libapr - Win32 DebugCLEAN" : - cd "\test\httpd-2.0\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libapr.mak" CFG="libapr - Win32 Debug"\ - RECURSE=1 - cd "..\..\modules\proxy" - -!ENDIF - -!IF "$(CFG)" == "mod_proxy - Win32 Release" - -"libhttpd - Win32 Release" : - cd "\test\httpd-2.0" - $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" - cd ".\modules\proxy" - -"libhttpd - Win32 ReleaseCLEAN" : - cd "\test\httpd-2.0" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libhttpd.mak"\ - CFG="libhttpd - Win32 Release" RECURSE=1 - cd ".\modules\proxy" - -!ELSEIF "$(CFG)" == "mod_proxy - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd "\test\httpd-2.0" - $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" - cd ".\modules\proxy" - -"libhttpd - Win32 DebugCLEAN" : - cd "\test\httpd-2.0" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"\ - RECURSE=1 - cd ".\modules\proxy" - -!ENDIF - -!IF "$(CFG)" == "mod_proxy - Win32 Release" - -"libaprutil - Win32 Release" : - cd "\test\httpd-2.0\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"\ - - cd "..\..\modules\proxy" - -"libaprutil - Win32 ReleaseCLEAN" : - cd "\test\httpd-2.0\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libaprutil.mak"\ - CFG="libaprutil - Win32 Release" RECURSE=1 - cd "..\..\modules\proxy" - -!ELSEIF "$(CFG)" == "mod_proxy - Win32 Debug" - -"libaprutil - Win32 Debug" : - cd "\test\httpd-2.0\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" - cd "..\..\modules\proxy" - -"libaprutil - Win32 DebugCLEAN" : - cd "\test\httpd-2.0\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\libaprutil.mak"\ - CFG="libaprutil - Win32 Debug" RECURSE=1 - cd "..\..\modules\proxy" - -!ENDIF - - -!ENDIF - diff --git a/modules/proxy/proxy_connect.c b/modules/proxy/proxy_connect.c deleted file mode 100644 index c83e2accf6..0000000000 --- a/modules/proxy/proxy_connect.c +++ /dev/null @@ -1,427 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* CONNECT method for Apache proxy */ - -#define CORE_PRIVATE - -#include "mod_proxy.h" - -module AP_MODULE_DECLARE_DATA proxy_connect_module; - -PROXY_DECLARE (int) ap_proxy_connect_canon(request_rec *r, char *url); -PROXY_DECLARE (int) ap_proxy_connect_handler(request_rec *r, proxy_server_conf *conf, - char *url, const char *proxyname, - apr_port_t proxyport); - -/* - * This handles Netscape CONNECT method secure proxy requests. - * A connection is opened to the specified host and data is - * passed through between the WWW site and the browser. - * - * This code is based on the INTERNET-DRAFT document - * "Tunneling SSL Through a WWW Proxy" currently at - * http://www.mcom.com/newsref/std/tunneling_ssl.html. - * - * If proxyhost and proxyport are set, we send a CONNECT to - * the specified proxy.. - * - * FIXME: this doesn't log the number of bytes sent, but - * that may be okay, since the data is supposed to - * be transparent. In fact, this doesn't log at all - * yet. 8^) - * FIXME: doesn't check any headers initally sent from the - * client. - * FIXME: should allow authentication, but hopefully the - * generic proxy authentication is good enough. - * FIXME: no check for r->assbackwards, whatever that is. - */ - -static int -allowed_port(proxy_server_conf *conf, int port) -{ - int i; - int *list = (int *) conf->allowed_connect_ports->elts; - - for(i = 0; i < conf->allowed_connect_ports->nelts; i++) { - if(port == list[i]) - return 1; - } - return 0; -} - -/* canonicalise CONNECT URLs. */ -PROXY_DECLARE (int) ap_proxy_connect_canon(request_rec *r, char *url) -{ - - if (r->method_number != M_CONNECT) { - return DECLINED; - } - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: CONNECT: canonicalising URL %s", url); - - return OK; -} - -/* CONNECT handler */ -PROXY_DECLARE (int) ap_proxy_connect_handler(request_rec *r, proxy_server_conf *conf, - char *url, const char *proxyname, - apr_port_t proxyport) -{ - apr_pool_t *p = r->pool; - apr_socket_t *sock; - apr_status_t err, rv; - apr_size_t i, o, nbytes; - char buffer[HUGE_STRING_LEN]; - - apr_pollfd_t *pollfd; - apr_int32_t pollcnt; - apr_int16_t pollevent; - apr_sockaddr_t *uri_addr, *connect_addr; - - uri_components uri; - const char *connectname; - int connectport = 0; - - /* is this for us? */ - if (r->method_number != M_CONNECT) { - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: CONNECT: rejecting URL %s", url); - return DECLINED; - } - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: CONNECT: serving URL %s", url); - - - /* - * Step One: Determine Who To Connect To - * - * Break up the URL to determine the host to connect to - */ - - /* we break the URL into host, port, uri */ - if (HTTP_OK != ap_parse_hostinfo_components(p, url, &uri)) { - return ap_proxyerror(r, HTTP_BAD_REQUEST, - apr_pstrcat(p, "URI cannot be parsed: ", url, NULL)); - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: CONNECT: connecting %s to %s:%d", url, uri.hostname, uri.port); - - /* do a DNS lookup for the destination host */ - err = apr_sockaddr_info_get(&uri_addr, uri.hostname, APR_UNSPEC, uri.port, 0, p); - - /* are we connecting directly, or via a proxy? */ - if (proxyname) { - connectname = proxyname; - connectport = proxyport; - err = apr_sockaddr_info_get(&connect_addr, proxyname, APR_UNSPEC, proxyport, 0, p); - } - else { - connectname = uri.hostname; - connectport = uri.port; - connect_addr = uri_addr; - } - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, - "proxy: CONNECT: connecting to remote proxy %s on port %d", connectname, connectport); - - /* check if ProxyBlock directive on this host */ - if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) { - return ap_proxyerror(r, HTTP_FORBIDDEN, - "Connect to remote machine blocked"); - } - - /* Check if it is an allowed port */ - if (conf->allowed_connect_ports->nelts == 0) { - /* Default setting if not overridden by AllowCONNECT */ - switch (uri.port) { - case DEFAULT_HTTPS_PORT: - case DEFAULT_SNEWS_PORT: - break; - default: - return HTTP_FORBIDDEN; - } - } else if(!allowed_port(conf, uri.port)) - return HTTP_FORBIDDEN; - - - /* - * Step Two: Make the Connection - * - * We have determined who to connect to. Now make the connection. - */ - - /* get all the possible IP addresses for the destname and loop through them - * until we get a successful connection - */ - if (APR_SUCCESS != err) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p, - "DNS lookup failure for: ", - connectname, NULL)); - } - - /* create a new socket */ - if ((rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, r->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: error creating socket"); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* - * At this point we have a list of one or more IP addresses of - * the machine to connect to. If configured, reorder this - * list so that the "best candidate" is first try. "best - * candidate" could mean the least loaded server, the fastest - * responding server, whatever. - * - * For now we do nothing, ie we get DNS round robin. - * XXX FIXME - */ - - - /* try each IP address until we connect successfully */ - { - int failed = 1; - while (connect_addr) { - - /* make the connection out of the socket */ - rv = apr_connect(sock, connect_addr); - - /* if an error occurred, loop round and try again */ - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: CONNECT: attempt to connect to %pI (%s) failed", connect_addr, connectname); - connect_addr = connect_addr->next; - continue; - } - - /* if we get here, all is well */ - failed = 0; - break; - } - - /* handle a permanent error from the above loop */ - if (failed) { - apr_socket_close(sock); - if (proxyname) { - return DECLINED; - } - else { - return HTTP_BAD_GATEWAY; - } - } - } - - - /* - * Step Three: Send the Request - * - * Send the HTTP/1.1 CONNECT request to the remote server - */ - - /* we are acting as a tunnel - the output filter stack should - * be completely empty, because when we are done here we are done completely. - * We add the NULL filter to the stack to do this... - */ - r->output_filters = NULL; - r->connection->output_filters = NULL; - - - /* If we are connecting through a remote proxy, we need to pass - * the CONNECT request on to it. - */ - if (proxyport) { - /* FIXME: Error checking ignored. - */ - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: CONNECT: sending the CONNECT request to the remote proxy"); - nbytes = apr_snprintf(buffer, sizeof(buffer), - "CONNECT %s HTTP/1.0" CRLF, r->uri); - apr_send(sock, buffer, &nbytes); - nbytes = apr_snprintf(buffer, sizeof(buffer), - "Proxy-agent: %s" CRLF CRLF, ap_get_server_version()); - apr_send(sock, buffer, &nbytes); - } - else { - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: CONNECT: Returning 200 OK Status"); - nbytes = apr_snprintf(buffer, sizeof(buffer), - "HTTP/1.0 200 Connection Established" CRLF); - apr_send(r->connection->client_socket, buffer, &nbytes); - nbytes = apr_snprintf(buffer, sizeof(buffer), - "Proxy-agent: %s" CRLF CRLF, ap_get_server_version()); - apr_send(r->connection->client_socket, buffer, &nbytes); - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: CONNECT: setting up poll()"); - - /* - * Step Four: Handle Data Transfer - * - * Handle two way transfer of data over the socket (this is a tunnel). - */ - -/* r->sent_bodyct = 1;*/ - - if((rv = apr_poll_setup(&pollfd, 2, r->pool)) != APR_SUCCESS) - { - apr_socket_close(sock); - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: CONNECT: error apr_poll_setup()"); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* Add client side to the poll */ - apr_poll_socket_add(pollfd, r->connection->client_socket, APR_POLLIN); - - /* Add the server side to the poll */ - apr_poll_socket_add(pollfd, sock, APR_POLLIN); - - while (1) { /* Infinite loop until error (one side closes the connection) */ -/* ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, "proxy: CONNECT: going to sleep (poll)");*/ - if ((rv = apr_poll(pollfd, &pollcnt, -1)) != APR_SUCCESS) - { - apr_socket_close(sock); - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "proxy: CONNECT: error apr_poll()"); - return HTTP_INTERNAL_SERVER_ERROR; - } -/* ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: CONNECT: woke from select(), i=%d", pollcnt);*/ - - if (pollcnt) { - apr_poll_revents_get(&pollevent, sock, pollfd); - if (pollevent & APR_POLLIN) { -/* ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: CONNECT: sock was set");*/ - nbytes = sizeof(buffer); - if (apr_recv(sock, buffer, &nbytes) == APR_SUCCESS) { - o = 0; - i = nbytes; - while(i > 0) - { - nbytes = i; - if (apr_send(r->connection->client_socket, buffer + o, &nbytes) != APR_SUCCESS) - break; - o += nbytes; - i -= nbytes; - } - } - else - break; - } - else if ((pollevent & APR_POLLERR) || (pollevent & APR_POLLHUP)) - break; - - - apr_poll_revents_get(&pollevent, r->connection->client_socket, pollfd); - if (pollevent & APR_POLLIN) { -/* ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: CONNECT: client was set");*/ - nbytes = sizeof(buffer); - if (apr_recv(r->connection->client_socket, buffer, &nbytes) == APR_SUCCESS) { - o = 0; - i = nbytes; - while(i > 0) - { - nbytes = i; - if (apr_send(sock, buffer + o, &nbytes) != APR_SUCCESS) - break; - o += nbytes; - i -= nbytes; - } - } - else - break; - } - else if ((pollevent & APR_POLLERR) || (pollevent & APR_POLLHUP)) - break; - } - else - break; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: CONNECT: finished with poll() - cleaning up"); - - /* - * Step Five: Clean Up - * - * Close the socket and clean up - */ - - apr_socket_close(sock); - - return OK; -} - -static void ap_proxy_connect_register_hook(apr_pool_t *p) -{ - proxy_hook_scheme_handler(ap_proxy_connect_handler, NULL, NULL, APR_HOOK_MIDDLE); - proxy_hook_canon_handler(ap_proxy_connect_canon, NULL, NULL, APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA proxy_connect_module = { - STANDARD20_MODULE_STUFF, - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - NULL, /* command apr_table_t */ - ap_proxy_connect_register_hook /* register hooks */ -}; diff --git a/modules/proxy/proxy_ftp.c b/modules/proxy/proxy_ftp.c deleted file mode 100644 index a6661db7a9..0000000000 --- a/modules/proxy/proxy_ftp.c +++ /dev/null @@ -1,1666 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* FTP routines for Apache proxy */ - -#include "mod_proxy.h" - -#define AUTODETECT_PWD - -module AP_MODULE_DECLARE_DATA proxy_ftp_module; - -PROXY_DECLARE (int) ap_proxy_ftp_canon(request_rec *r, char *url); -PROXY_DECLARE (int) ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf, - char *url, const char *proxyhost, - apr_port_t proxyport); -apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, - apr_bucket_brigade *bb); - - -/* - * Decodes a '%' escaped string, and returns the number of characters - */ -static int decodeenc(char *x) -{ - int i, j, ch; - - if (x[0] == '\0') - return 0; /* special case for no characters */ - for (i = 0, j = 0; x[i] != '\0'; i++, j++) { - /* decode it if not already done */ - ch = x[i]; - if (ch == '%' && ap_isxdigit(x[i + 1]) && ap_isxdigit(x[i + 2])) { - ch = ap_proxy_hex2c(&x[i + 1]); - i += 2; - } - x[j] = ch; - } - x[j] = '\0'; - return j; -} - -/* - * checks an encoded ftp string for bad characters, namely, CR, LF or - * non-ascii character - */ -static int ftp_check_string(const char *x) -{ - int i, ch = 0; - - for (i = 0; x[i] != '\0'; i++) { - ch = x[i]; - if (ch == '%' && ap_isxdigit(x[i + 1]) && ap_isxdigit(x[i + 2])) { - ch = ap_proxy_hex2c(&x[i + 1]); - i += 2; - } -#if !APR_CHARSET_EBCDIC - if (ch == '\015' || ch == '\012' || (ch & 0x80)) -#else /*APR_CHARSET_EBCDIC*/ - if (ch == '\r' || ch == '\n' || (os_toascii[ch] & 0x80)) -#endif /*APR_CHARSET_EBCDIC*/ - return 0; - } - return 1; -} - -/* - * Canonicalise ftp URLs. - */ -PROXY_DECLARE (int) ap_proxy_ftp_canon(request_rec *r, char *url) -{ - char *user, *password, *host, *path, *parms, *strp, sport[7]; - apr_pool_t *p = r->pool; - const char *err; - apr_port_t port, def_port; - - /* */ - if (strncasecmp(url, "ftp:", 4) == 0) { - url += 4; - } - else { - return DECLINED; - } - def_port = ap_default_port_for_scheme("ftp"); - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: canonicalising URL %s", url); - - port = def_port; - err = ap_proxy_canon_netloc(p, &url, &user, &password, &host, &port); - if (err) - return HTTP_BAD_REQUEST; - if (user != NULL && !ftp_check_string(user)) - return HTTP_BAD_REQUEST; - if (password != NULL && !ftp_check_string(password)) - return HTTP_BAD_REQUEST; - - /* now parse path/parameters args, according to rfc1738 */ - /* N.B. if this isn't a true proxy request, then the URL path - * (but not query args) has already been decoded. - * This gives rise to the problem of a ; being decoded into the - * path. - */ - strp = strchr(url, ';'); - if (strp != NULL) { - *(strp++) = '\0'; - parms = ap_proxy_canonenc(p, strp, strlen(strp), enc_parm, - r->proxyreq); - if (parms == NULL) - return HTTP_BAD_REQUEST; - } - else - parms = ""; - - path = ap_proxy_canonenc(p, url, strlen(url), enc_path, r->proxyreq); - if (path == NULL) - return HTTP_BAD_REQUEST; - if (!ftp_check_string(path)) - return HTTP_BAD_REQUEST; - - if (r->proxyreq && r->args != NULL) { - if (strp != NULL) { - strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_parm, 1); - if (strp == NULL) - return HTTP_BAD_REQUEST; - parms = apr_pstrcat(p, parms, "?", strp, NULL); - } - else { - strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_fpath, 1); - if (strp == NULL) - return HTTP_BAD_REQUEST; - path = apr_pstrcat(p, path, "?", strp, NULL); - } - r->args = NULL; - } - -/* now, rebuild URL */ - - if (port != def_port) - apr_snprintf(sport, sizeof(sport), ":%d", port); - else - sport[0] = '\0'; - - r->filename = apr_pstrcat(p, "proxy:ftp://", (user != NULL) ? user : "", - (password != NULL) ? ":" : "", - (password != NULL) ? password : "", - (user != NULL) ? "@" : "", host, sport, "/", path, - (parms[0] != '\0') ? ";" : "", parms, NULL); - - return OK; -} - -/* we chop lines longer than 80 characters */ -#define MAX_LINE_LEN 80 - -/* - * Reads response lines, returns both the ftp status code and - * remembers the response message in the supplied buffer - */ -static int ftp_getrc_msg(conn_rec *c, apr_bucket_brigade *bb, char *msgbuf, int msglen) -{ - int status; - char response[MAX_LINE_LEN]; - char buff[5]; - char *mb = msgbuf, - *me = &msgbuf[msglen]; - apr_status_t rv; - int eos; - - if (APR_SUCCESS != (rv = ap_proxy_string_read(c, bb, response, sizeof(response), &eos))) { - return -1; - } - if (!apr_isdigit(response[0]) || !apr_isdigit(response[1]) || - !apr_isdigit(response[2]) || (response[3] != ' ' && response[3] != '-')) - status = 0; - else - status = 100 * response[0] + 10 * response[1] + response[2] - 111 * '0'; - - mb = apr_cpystrn(mb, response+4, me - mb); - - if (response[3] == '-') { - memcpy(buff, response, 3); - buff[3] = ' '; - do { - if (APR_SUCCESS != (rv = ap_proxy_string_read(c, bb, response, sizeof(response), &eos))) { - return -1; - } - mb = apr_cpystrn(mb, response + (' ' == response[0] ? 1 : 4), me - mb); - } while (memcmp(response, buff, 4) != 0); - } - - return status; -} - -/* this is a filter that turns a raw ASCII directory listing into pretty HTML */ - -/* ideally, mod_proxy should simply send the raw directory list up the filter - * stack to mod_autoindex, which in theory should turn the raw ascii into - * pretty html along with all the bells and whistles it provides... - * - * all in good time...! :) - */ - -typedef struct { - apr_bucket_brigade *in; - char buffer[MAX_STRING_LEN]; - enum {HEADER, BODY, FOOTER} state; -} proxy_dir_ctx_t; - -apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *in) -{ - request_rec *r = f->r; - apr_pool_t *p = r->pool; - apr_bucket *e; - apr_bucket_brigade *out = apr_brigade_create(p); - apr_status_t rv; - - register int n; - char *dir, *path, *reldir, *site, *str; - - const char *pwd = apr_table_get(r->notes, "Directory-PWD"); - const char *readme = apr_table_get(r->notes, "Directory-README"); - - proxy_dir_ctx_t *ctx = f->ctx; - if (!ctx) { - f->ctx = ctx = apr_pcalloc(p, sizeof(*ctx)); - ctx->in = apr_brigade_create(p); - ctx->buffer[0] = 0; - ctx->state = HEADER; - } - - /* combine the stored and the new */ - APR_BRIGADE_CONCAT(ctx->in, in); - - if (HEADER == ctx->state) { - - /* Save "scheme://site" prefix without password */ - site = ap_unparse_uri_components(p, &f->r->parsed_uri, UNP_OMITPASSWORD|UNP_OMITPATHINFO); - /* ... and path without query args */ - path = ap_unparse_uri_components(p, &f->r->parsed_uri, UNP_OMITSITEPART|UNP_OMITQUERY); - (void)decodeenc(path); - - /* Copy path, strip (all except the last) trailing slashes */ - path = dir = apr_pstrcat(p, path, "/", NULL); - while ((n = strlen(path)) > 1 && path[n-1] == '/' && path[n-2] == '/') - path[n-1] = '\0'; - - /* print "ftp://host/" */ - str = apr_psprintf(p, DOCTYPE_HTML_3_2 - "\n\n<HTML>\n<HEAD>\n<TITLE>%s%s</TITLE>\n" - "<BASE HREF=\"%s%s\">\n</HEAD>\n\n" - "<BODY>\n\n<H2>Directory of " - "<A HREF=\"/\">%s</A>/", - site, path, site, path, site); - - e = apr_bucket_pool_create(str, strlen(str), p); - APR_BRIGADE_INSERT_TAIL(out, e); - - while ((dir = strchr(dir+1, '/')) != NULL) - { - *dir = '\0'; - if ((reldir = strrchr(path+1, '/'))==NULL) - reldir = path+1; - else - ++reldir; - /* print "path/" component */ - str = apr_psprintf(p, "<A HREF=\"/%s/\">%s</A>/", path+1, reldir); - e = apr_bucket_pool_create(str, strlen(str), p); - APR_BRIGADE_INSERT_TAIL(out, e); - *dir = '/'; - } - /* If the caller has determined the current directory, and it differs */ - /* from what the client requested, then show the real name */ - if (pwd == NULL || strncmp (pwd, path, strlen(pwd)) == 0) { - str = apr_psprintf(p, "</H2>\n\n<HR></HR>\n\n<PRE>"); - } else { - str = apr_psprintf(p, "</H2>\n\n(%s)\n\n<HR></HR>\n\n<PRE>", pwd); - } - e = apr_bucket_pool_create(str, strlen(str), p); - APR_BRIGADE_INSERT_TAIL(out, e); - - /* print README */ - if (readme) { - str = apr_psprintf(p, "%s\n</PRE>\n\n<HR></HR>\n\n<PRE>\n", - readme); - - e = apr_bucket_pool_create(str, strlen(str), p); - APR_BRIGADE_INSERT_TAIL(out, e); - } - - /* make sure page intro gets sent out */ - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(out, e); - if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) { - return rv; - } - apr_brigade_cleanup(out); - - ctx->state = BODY; - } - - /* loop through each line of directory */ - while (BODY == ctx->state) { - char *filename; - int found = 0; - int eos = 0; - - /* get a complete line */ - /* if the buffer overruns - throw data away */ - while (!found && !APR_BRIGADE_EMPTY(ctx->in)) { - char *pos, *response; - apr_size_t len, max; - e = APR_BRIGADE_FIRST(ctx->in); - if (APR_BUCKET_IS_EOS(e)) { - eos = 1; - break; - } - if (APR_SUCCESS != (rv = apr_bucket_read(e, (const char **)&response, &len, APR_BLOCK_READ))) { - return rv; - } - pos = memchr(response, APR_ASCII_LF, len); - if (pos != NULL) { - if ((pos - response + 1) != len) { - len = pos - response + 1; - apr_bucket_split(e, pos - response + 1); - - } - found = 1; - } - max = sizeof(ctx->buffer)-strlen(ctx->buffer)-1; - if (len > max) { - len = max; - } -/* strncat works here, but apr_cpystrn does not - the last char gets chopped, dunno why */ -/* apr_cpystrn(ctx->buffer+strlen(ctx->buffer), response, len);*/ - strncat(ctx->buffer, response, len); - APR_BUCKET_REMOVE(e); - apr_bucket_destroy(e); - } - - /* EOS? jump to footer */ - if (eos) { - ctx->state = FOOTER; - break; - } - - /* not complete? leave and try get some more */ - if (!found) { - return APR_SUCCESS; - } - - /* a symlink? */ - if (ctx->buffer[0] == 'l' && (filename=strstr(ctx->buffer, " -> ")) != NULL) { - char *link_ptr = filename; - - do { - filename--; - } while (filename[0] != ' '); - *(filename++) = '\0'; - *(link_ptr++) = '\0'; - if ((n = strlen(link_ptr)) > 1 && link_ptr[n - 1] == '\n') - link_ptr[n - 1] = '\0'; - str = apr_psprintf(p, "%s <A HREF=\"%s\">%s %s</A>\n", ctx->buffer, filename, filename, link_ptr); - } - - /* a directory/file? */ - else if (ctx->buffer[0] == 'd' || ctx->buffer[0] == '-' || ctx->buffer[0] == 'l' || apr_isdigit(ctx->buffer[0])) { - int searchidx = 0; - char *searchptr = NULL; - int firstfile = 1; - if (apr_isdigit(ctx->buffer[0])) { /* handle DOS dir */ - searchptr = strchr(ctx->buffer, '<'); - if (searchptr != NULL) - *searchptr = '['; - searchptr = strchr(ctx->buffer, '>'); - if (searchptr != NULL) - *searchptr = ']'; - } - - filename = strrchr(ctx->buffer, ' '); - *(filename++) = 0; - filename[strlen(filename) - 1] = 0; - - /* handle filenames with spaces in 'em */ - if (!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) { - firstfile = 0; - searchidx = filename - ctx->buffer; - } - else if (searchidx != 0 && ctx->buffer[searchidx] != 0) { - *(--filename) = ' '; - ctx->buffer[searchidx - 1] = 0; - filename = &ctx->buffer[searchidx]; - } - - /* Special handling for '.' and '..' */ - if (!strcmp(filename, ".") || !strcmp(filename, "..") || ctx->buffer[0] == 'd') { - str = apr_psprintf(p, "%s <A HREF=\"%s/\">%s</A>\n", - ctx->buffer, filename, filename); - } - else { - str = apr_psprintf(p, "%s <A HREF=\"%s\">%s</A>\n", - ctx->buffer, filename, filename); - } - } - else { - str = apr_pstrdup(p, ctx->buffer); - } - - /* erase buffer for next time around */ - ctx->buffer[0] = 0; - - e = apr_bucket_pool_create(str, strlen(str), p); - APR_BRIGADE_INSERT_TAIL(out, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(out, e); - if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) { - return rv; - } - apr_brigade_cleanup(out); - - } - - if (FOOTER == ctx->state) { - str = apr_psprintf(p, "</PRE>\n\n<HR></HR>\n\n%s\n\n</BODY>\n</HTML>\n", ap_psignature("", r)); - e = apr_bucket_pool_create(str, strlen(str), p); - APR_BRIGADE_INSERT_TAIL(out, e); - - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(out, e); - - e = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(out, e); - - if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) { - return rv; - } - apr_brigade_destroy(out); - } - - return APR_SUCCESS; -} - -/* Common routine for failed authorization (i.e., missing or wrong password) - * to an ftp service. This causes most browsers to retry the request - * with username and password (which was presumably queried from the user) - * supplied in the Authorization: header. - * Note that we "invent" a realm name which consists of the - * ftp://user@host part of the reqest (sans password -if supplied but invalid-) - */ -static int ftp_unauthorized (request_rec *r, int log_it) -{ - r->proxyreq = PROXYREQ_NONE; - /* Log failed requests if they supplied a password - * (log username/password guessing attempts) - */ - if (log_it) - ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r, - "proxy: missing or failed auth to %s", - ap_unparse_uri_components(r->pool, - &r->parsed_uri, UNP_OMITPATHINFO)); - - apr_table_setn(r->err_headers_out, "WWW-Authenticate", - apr_pstrcat(r->pool, "Basic realm=\"", - ap_unparse_uri_components(r->pool, &r->parsed_uri, - UNP_OMITPASSWORD|UNP_OMITPATHINFO), - "\"", NULL)); - - return HTTP_UNAUTHORIZED; -} - - -/* - * Handles direct access of ftp:// URLs - * Original (Non-PASV) version from - * Troy Morrison <spiffnet@zoom.com> - * PASV added by Chuck - * Filters by [Graham Leggett <minfrin@sharp.fm>] - */ -PROXY_DECLARE (int) ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf, - char *url, const char *proxyhost, - apr_port_t proxyport) -{ - apr_pool_t *p = r->pool; - conn_rec *c = r->connection; - proxy_conn_rec *backend; - apr_socket_t *sock, *local_sock, *remote_sock; - apr_sockaddr_t *connect_addr; - apr_status_t rv; - conn_rec *origin, *remote; - int err; - apr_bucket *e; - apr_bucket_brigade *bb = apr_brigade_create(p); - apr_bucket_brigade *cbb = apr_brigade_create(p); - char *buf, *connectname; - apr_port_t connectport; - char buffer[MAX_STRING_LEN]; - char *path, *strp, *parms; - char *user = NULL; -/* char *account = NULL; how to supply an account in a URL? */ - const char *password = NULL; - int i, j, len, rc; - int one = 1; - char *size = NULL; - apr_size_t readbytes = -1; - - /* stuff for PASV mode */ - int connect = 0, use_port = 0; - char dates[AP_RFC822_DATE_LEN]; - - /* is this for us? */ - if (proxyhost) { - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: rejecting URL %s - proxyhost %s specified:", url, proxyhost); - return DECLINED; /* proxy connections are via HTTP */ - } - if (strncasecmp(url, "ftp:", 4)) { - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: rejecting URL %s - not ftp:", url); - return DECLINED; /* only interested in FTP */ - } - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: serving URL %s", url); - - /* create space for state information */ - backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config, &proxy_ftp_module); - if (!backend) { - backend = ap_pcalloc(c->pool, sizeof(proxy_conn_rec)); - backend->connection = NULL; - backend->hostname = NULL; - backend->port = 0; - ap_set_module_config(c->conn_config, &proxy_ftp_module, backend); - } - - - /* - * I: Who Do I Connect To? - * ----------------------- - * - * Break up the URL to determine the host to connect to - */ - - /* we only support GET and HEAD */ - if (r->method_number != M_GET) - return HTTP_NOT_IMPLEMENTED; - - - /* We break the URL into host, port, path-search */ - connectname = r->parsed_uri.hostname; - connectport = (r->parsed_uri.port != 0) - ? r->parsed_uri.port - : ap_default_port_for_request(r); - path = apr_pstrdup(p, r->parsed_uri.path); - path = (path != NULL && path[0] != '\0') ? &path[1] : ""; - - parms = strchr(path, ';'); - if (parms != NULL) - *(parms++) = '\0'; - - /* The "Authorization:" header must be checked first. - * We allow the user to "override" the URL-coded user [ & password ] - * in the Browsers' User&Password Dialog. - * NOTE that this is only marginally more secure than having the - * password travel in plain as part of the URL, because Basic Auth - * simply uuencodes the plain text password. - * But chances are still smaller that the URL is logged regularly. - */ - if ((password = apr_table_get(r->headers_in, "Authorization")) != NULL - && strcasecmp(ap_getword(r->pool, &password, ' '), "Basic") == 0 - && (password = ap_pbase64decode(r->pool, password))[0] != ':') { - /* Note that this allocation has to be made from r->connection->pool - * because it has the lifetime of the connection. The other allocations - * are temporary and can be tossed away any time. - */ - user = ap_getword_nulls (r->connection->pool, &password, ':'); - r->ap_auth_type = "Basic"; - r->user = r->parsed_uri.user = user; - } - else if ((user = r->parsed_uri.user) != NULL) { - user = apr_pstrdup(p, user); - decodeenc(user); - if ((password = r->parsed_uri.password) != NULL) { - char *tmp = apr_pstrdup(p, password); - decodeenc(tmp); - password = tmp; - } - } - else { - user = "anonymous"; - password = "apache-proxy@"; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: connecting %s to %s:%d", url, connectname, connectport); - - /* do a DNS lookup for the destination host */ - err = apr_sockaddr_info_get(&connect_addr, connectname, APR_UNSPEC, connectport, 0, p); - - /* check if ProxyBlock directive on this host */ - if (OK != ap_proxy_checkproxyblock(r, conf, connect_addr)) { - return ap_proxyerror(r, HTTP_FORBIDDEN, - "Connect to remote machine blocked"); - } - - - /* - * II: Make the Connection - * ----------------------- - * - * We have determined who to connect to. Now make the connection. - */ - - /* get all the possible IP addresses for the destname and loop through them - * until we get a successful connection - */ - if (APR_SUCCESS != err) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p, - "DNS lookup failure for: ", - connectname, NULL)); - } - - - if ((rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, r->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: FTP: error creating socket"); - return HTTP_INTERNAL_SERVER_ERROR; - } - -#if !defined(TPF) && !defined(BEOS) - if (conf->recv_buffer_size > 0 - && (rv = apr_setsocketopt(sock, APR_SO_RCVBUF, - conf->recv_buffer_size))) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default"); - } -#endif - - if (APR_SUCCESS != (rv = apr_setsocketopt(sock, APR_SO_REUSEADDR, one))) { -#ifndef _OSD_POSIX /* BS2000 has this option "always on" */ - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: FTP: error setting reuseaddr option: setsockopt(SO_REUSEADDR)"); - return HTTP_INTERNAL_SERVER_ERROR; -#endif /*_OSD_POSIX*/ - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: socket has been created"); - - - /* - * At this point we have a list of one or more IP addresses of - * the machine to connect to. If configured, reorder this - * list so that the "best candidate" is first try. "best - * candidate" could mean the least loaded server, the fastest - * responding server, whatever. - * - * For now we do nothing, ie we get DNS round robin. - * XXX FIXME - */ - - - /* try each IP address until we connect successfully */ - { - int failed = 1; - while (connect_addr) { - - /* make the connection out of the socket */ - rv = apr_connect(sock, connect_addr); - - /* if an error occurred, loop round and try again */ - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: FTP: attempt to connect to %pI (%s) failed", connect_addr, connectname); - connect_addr = connect_addr->next; - continue; - } - - /* if we get here, all is well */ - failed = 0; - break; - } - - /* handle a permanent error from the above loop */ - if (failed) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_psprintf(r->pool, - "Could not connect to remote machine: %s port %d", - connectname, connectport)); - } - } - - /* the socket is now open, create a new connection */ - origin = ap_new_connection(p, r->server, sock, r->connection->id); - if (!origin) { - /* the peer reset the connection already; ap_new_connection() - * closed the socket */ - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: an error occurred creating a new connection to %pI (%s)", connect_addr, connectname); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* if a keepalive connection is floating around, close it first! */ - /* we might support ftp keepalives later, but not now... */ - if (backend->connection) { - apr_socket_close(backend->connection->client_socket); - backend->connection = NULL; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: control connection complete"); - - - /* - * III: Send Control Request - * ------------------------- - * - * Log into the ftp server, send the username & password, change to the correct - * directory... - */ - - /* set up the connection filters */ - ap_proxy_pre_http_connection(origin, NULL); - - /* possible results: */ - /* 120 Service ready in nnn minutes. */ - /* 220 Service ready for new user. */ - /* 421 Service not available, closing control connection. */ - i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", i, buffer); - if (i == -1) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server"); - } - if (i == 120) { - /* RFC2616 states: - * 14.37 Retry-After - * - * The Retry-After response-header field can be used with a 503 (Service - * Unavailable) response to indicate how long the service is expected to - * be unavailable to the requesting client. [...] The value of this field - * can be either an HTTP-date or an integer number of seconds (in decimal) - * after the time of the response. - * Retry-After = "Retry-After" ":" ( HTTP-date | delta-seconds ) - */ - for (i=0 ; buffer[i] && !isdigit(buffer[i]); i++); - if (buffer[i]) { - ap_table_add(r->headers_out, "Retry-After", apr_psprintf(p, "%lu", 60*atol(buffer+i))); - } - return ap_proxyerror(r, HTTP_SERVICE_UNAVAILABLE, buffer); - } - if (i != 220) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, buffer); - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: connected."); - - buf = apr_pstrcat(p, "USER ", user, CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: USER %s", user); - - /* possible results; 230, 331, 332, 421, 500, 501, 530 */ - /* states: 1 - error, 2 - success; 3 - send password, 4,5 fail */ - /* 230 User logged in, proceed. */ - /* 331 User name okay, need password. */ - /* 332 Need account for login. */ - /* 421 Service not available, closing control connection. */ - /* 500 Syntax error, command unrecognized. */ - /* (This may include errors such as command line too long.) */ - /* 501 Syntax error in parameters or arguments. */ - /* 530 Not logged in. */ - i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", i, buffer); - if (i == -1) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server"); - } - if (i == 530) { - return ftp_unauthorized (r, 1); /* log it: user name guessing attempt? */ - } - if (i != 230 && i != 331) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, buffer); - } - - if (i == 331) { /* send password */ - if (password == NULL) { - return ftp_unauthorized (r, 0); - } - buf = apr_pstrcat(p, "PASS ", password, CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: PASS %s", password); - - /* possible results 202, 230, 332, 421, 500, 501, 503, 530 */ - /* 230 User logged in, proceed. */ - /* 332 Need account for login. */ - /* 421 Service not available, closing control connection. */ - /* 500 Syntax error, command unrecognized. */ - /* 501 Syntax error in parameters or arguments. */ - /* 503 Bad sequence of commands. */ - /* 530 Not logged in. */ - i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", i, buffer); - if (i == -1) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Error reading from remote server"); - } - if (i == 332) { - return ap_proxyerror(r, HTTP_UNAUTHORIZED, - apr_pstrcat(p, "Need account for login: ", buffer, NULL)); - } - /* @@@ questionable -- we might as well return a 403 Forbidden here */ - if (i == 530) { - return ftp_unauthorized (r, 1); /* log it: passwd guessing attempt? */ - } - if (i != 230 && i != 202) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, buffer); - } - } - apr_table_set(r->notes, "Directory-README", buffer); - - /* set the directory (walk directory component by component): - * this is what we must do if we don't know the OS type of the remote - * machine - */ - for (;;) { - strp = strchr(path, '/'); - if (strp == NULL) - break; - *strp = '\0'; - - len = decodeenc(path); - buf = apr_pstrcat(p, "CWD ", path, CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: CWD %s", path); - *strp = '/'; - /* responses: 250, 421, 500, 501, 502, 530, 550 */ - /* 250 Requested file action okay, completed. */ - /* 421 Service not available, closing control connection. */ - /* 500 Syntax error, command unrecognized. */ - /* 501 Syntax error in parameters or arguments. */ - /* 502 Command not implemented. */ - /* 530 Not logged in. */ - /* 550 Requested action not taken. */ - i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", i, buffer); - if (i == -1) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Error reading from remote server"); - } - if (i == 550) { - return ap_proxyerror(r, HTTP_NOT_FOUND, buffer); - } - if (i != 250) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, buffer); - } - - path = strp + 1; - } - - if (parms != NULL && strncasecmp(parms, "type=a", 6) == 0) { - parms = "A"; - } - else { - parms = "I"; - } - - /* changed to make binary transfers the default */ - /* set type to binary */ - buf = apr_pstrcat(p, "TYPE ", parms, CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: TYPE I"); - /* responses: 200, 421, 500, 501, 504, 530 */ - /* 200 Command okay. */ - /* 421 Service not available, closing control connection. */ - /* 500 Syntax error, command unrecognized. */ - /* 501 Syntax error in parameters or arguments. */ - /* 504 Command not implemented for that parameter. */ - /* 530 Not logged in. */ - i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", i, buffer); - if (i == -1) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Error reading from remote server"); - } - if (i != 200 && i != 504) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, buffer); - } - /* Allow not implemented */ - if (i == 504) { - parms[0] = '\0'; - } - - - /* - * IV: Make Data Connection? - * ------------------------- - * - * Try EPSV, if that fails... - * try PASV, if that fails... - * try PORT. - */ -/* this temporarily switches off EPSV/PASV */ -/*goto bypass;*/ - - /* set up data connection - EPSV */ - { - apr_sockaddr_t *remote_addr; - char *remote_ip; - apr_port_t remote_port; - - /* The EPSV command replaces PASV where both IPV4 and IPV6 is supported. Only - * the port is returned, the IP address is always the same as that on the - * control connection. Example: - * Entering Extended Passive Mode (|||6446|) - */ - buf = apr_pstrcat(p, "EPSV", CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: EPSV"); - /* possible results: 227, 421, 500, 501, 502, 530 */ - /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */ - /* 421 Service not available, closing control connection. */ - /* 500 Syntax error, command unrecognized. */ - /* 501 Syntax error in parameters or arguments. */ - /* 502 Command not implemented. */ - /* 530 Not logged in. */ - i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", i, buffer); - if (i == -1) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Error reading from remote server"); - } - if (i != 229 && i != 500 && i != 501 && i != 502) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, buffer); - } - else if (i == 229) { - char *pstr; - - pstr = apr_pstrdup(p, buffer); - pstr = strtok(pstr, " "); /* separate result code */ - if (pstr != NULL) { - if (*(pstr + strlen(pstr) + 1) == '=') { - pstr += strlen(pstr) + 2; - } - else { - pstr = strtok(NULL, "("); /* separate address & port params */ - if (pstr != NULL) - pstr = strtok(NULL, ")"); - } - } - - if (pstr) { - apr_sockaddr_t *epsv_addr; - remote_port = atoi(pstr+3); - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: EPSV contacting remote host on port %d", - remote_port); - - if ((rv = apr_socket_create(&remote_sock, APR_INET, SOCK_STREAM, r->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: FTP: error creating EPSV socket"); - return HTTP_INTERNAL_SERVER_ERROR; - } - -#if !defined (TPF) && !defined(BEOS) - if (conf->recv_buffer_size > 0 && (rv = apr_setsocketopt(remote_sock, APR_SO_RCVBUF, - conf->recv_buffer_size))) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: FTP: setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default"); - } -#endif - - /* make the connection */ - apr_socket_addr_get(&remote_addr, APR_REMOTE, sock); - apr_sockaddr_ip_get(&remote_ip, remote_addr); - apr_sockaddr_info_get(&epsv_addr, remote_ip, APR_INET, remote_port, 0, p); - rv = apr_connect(remote_sock, epsv_addr); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: FTP: EPSV attempt to connect to %pI failed - Firewall/NAT?", epsv_addr); - return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_psprintf(r->pool, - "EPSV attempt to connect to %pI failed - firewall/NAT?", epsv_addr)); - } - else { - connect = 1; - } - } - else { - /* and try the regular way */ - apr_socket_close(remote_sock); - } - } - } - - /* set up data connection - PASV */ - if (!connect) { - buf = apr_pstrcat(p, "PASV", CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: PASV"); - /* possible results: 227, 421, 500, 501, 502, 530 */ - /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */ - /* 421 Service not available, closing control connection. */ - /* 500 Syntax error, command unrecognized. */ - /* 501 Syntax error in parameters or arguments. */ - /* 502 Command not implemented. */ - /* 530 Not logged in. */ - i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", i, buffer); - if (i == -1) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Error reading from remote server"); - } - if (i != 227 && i != 502) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, buffer); - } - else if (i == 227) { - unsigned int h0, h1, h2, h3, p0, p1; - char *pstr; - -/* FIXME: Check PASV against RFC1123 */ - - pstr = apr_pstrdup(p, buffer); - pstr = strtok(pstr, " "); /* separate result code */ - if (pstr != NULL) { - if (*(pstr + strlen(pstr) + 1) == '=') { - pstr += strlen(pstr) + 2; - } - else { - pstr = strtok(NULL, "("); /* separate address & port params */ - if (pstr != NULL) - pstr = strtok(NULL, ")"); - } - } - -/* FIXME: Only supports IPV4 - fix in RFC2428 */ - - if (pstr != NULL && (sscanf(pstr, - "%d,%d,%d,%d,%d,%d", &h3, &h2, &h1, &h0, &p1, &p0) == 6)) { - - apr_sockaddr_t *pasv_addr; - int pasvport = (p1 << 8) + p0; - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: PASV contacting host %d.%d.%d.%d:%d", - h3, h2, h1, h0, pasvport); - - if ((rv = apr_socket_create(&remote_sock, APR_INET, SOCK_STREAM, r->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: error creating PASV socket"); - return HTTP_INTERNAL_SERVER_ERROR; - } - -#if !defined (TPF) && !defined(BEOS) - if (conf->recv_buffer_size > 0 && (rv = apr_setsocketopt(remote_sock, APR_SO_RCVBUF, - conf->recv_buffer_size))) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: FTP: setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default"); - } -#endif - - /* make the connection */ - apr_sockaddr_info_get(&pasv_addr, apr_psprintf(p, "%d.%d.%d.%d", h3, h2, h1, h0), APR_INET, pasvport, 0, p); - rv = apr_connect(remote_sock, pasv_addr); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: FTP: PASV attempt to connect to %pI failed - Firewall/NAT?", pasv_addr); - return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_psprintf(r->pool, - "PASV attempt to connect to %pI failed - firewall/NAT?", pasv_addr)); - } - else { - connect = 1; - } - } - else { - /* and try the regular way */ - apr_socket_close(remote_sock); - } - } - } -/*bypass:*/ - - /* set up data connection - PORT */ - if (!connect) { - apr_sockaddr_t *local_addr; - char *local_ip; - apr_port_t local_port; - unsigned int h0, h1, h2, h3, p0, p1; - - if ((rv = apr_socket_create(&local_sock, APR_INET, SOCK_STREAM, r->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: FTP: error creating local socket"); - return HTTP_INTERNAL_SERVER_ERROR; - } - apr_socket_addr_get(&local_addr, APR_LOCAL, sock); - apr_sockaddr_port_get(&local_port, local_addr); - apr_sockaddr_ip_get(&local_ip, local_addr); - - if ((rv = apr_setsocketopt(local_sock, APR_SO_REUSEADDR, one)) != APR_SUCCESS) { -#ifndef _OSD_POSIX /* BS2000 has this option "always on" */ - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: FTP: error setting reuseaddr option"); - return HTTP_INTERNAL_SERVER_ERROR; -#endif /*_OSD_POSIX*/ - } - - apr_sockaddr_info_get(&local_addr, local_ip, APR_UNSPEC, local_port, 0, r->pool); - - if ((rv = apr_bind(local_sock, local_addr)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: FTP: error binding to ftp data socket %pI", local_addr); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* only need a short queue */ - if ((rv = apr_listen(local_sock, 2)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: FTP: error listening to ftp data socket %pI", local_addr); - return HTTP_INTERNAL_SERVER_ERROR; - } - -/* FIXME: Sent PORT here */ - - if (local_ip && (sscanf(local_ip, - "%d.%d.%d.%d", &h3, &h2, &h1, &h0) == 4)) { - p1 = (local_port >> 8); - p0 = (local_port & 0xFF); - - buf = apr_psprintf(p, "PORT %d,%d,%d,%d,%d,%d" CRLF, h3, h2, h1, h0, p1, p0); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: PORT %d,%d,%d,%d,%d,%d", h3, h2, h1, h0, p1, p0); - /* possible results: 200, 421, 500, 501, 502, 530 */ - /* 200 Command okay. */ - /* 421 Service not available, closing control connection. */ - /* 500 Syntax error, command unrecognized. */ - /* 501 Syntax error in parameters or arguments. */ - /* 502 Command not implemented. */ - /* 530 Not logged in. */ - rc = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", rc, buffer); - if (rc == -1) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Error reading from remote server"); - } - if (rc != 200) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, buffer); - } - - /* signal that we must use the EPRT/PORT loop */ - use_port = 1; - } - else { -/* IPV6 FIXME: - * The EPRT command replaces PORT where both IPV4 and IPV6 is supported. The first - * number (1,2) indicates the protocol type. Examples: - * EPRT |1|132.235.1.2|6275| - * EPRT |2|1080::8:800:200C:417A|5282| - */ - return ap_proxyerror(r, HTTP_NOT_IMPLEMENTED, "Connect to IPV6 ftp server using EPRT not supported. Enable EPSV."); - } - } - - - /* - * V: Set The Headers - * ------------------- - * - * Get the size of the request, set up the environment for HTTP. - */ - - /* set request; "path" holds last path component */ - len = decodeenc(path); - - /* TM - if len == 0 then it must be a directory (you can't RETR nothing) */ - - if (len == 0) { - parms = "d"; - } - else { - buf = apr_pstrcat(p, "SIZE ", path, CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: SIZE %s", path); - i = ftp_getrc_msg(origin, cbb, buffer, sizeof buffer); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: returned status %d with response %s", i, buffer); - if (i != 500) { /* Size command not recognized */ - if (i == 550) { /* Not a regular file */ - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: SIZE shows this is a directory"); - parms = "d"; - buf = apr_pstrcat(p, "CWD ", path, CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: CWD %s", path); - i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - /* possible results: 250, 421, 500, 501, 502, 530, 550 */ - /* 250 Requested file action okay, completed. */ - /* 421 Service not available, closing control connection. */ - /* 500 Syntax error, command unrecognized. */ - /* 501 Syntax error in parameters or arguments. */ - /* 502 Command not implemented. */ - /* 530 Not logged in. */ - /* 550 Requested action not taken. */ - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", i, buffer); - if (i == -1) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Error reading from remote server"); - } - if (i == 550) { - return ap_proxyerror(r, HTTP_NOT_FOUND, buffer); - } - if (i != 250) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, buffer); - } - path = ""; - len = 0; - } - else if (i == 213) { /* Size command ok */ - for (j = 0; j < sizeof(buffer) && apr_isdigit(buffer[j]); j++); - buffer[j] = '\0'; - if (buffer[0] != '\0') - size = apr_pstrdup(p, buffer); - } - } - } - - - -#ifdef AUTODETECT_PWD - buf = apr_pstrcat(p, "PWD", CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: PWD"); - /* responses: 257, 500, 501, 502, 421, 550 */ - /* 257 "<directory-name>" <commentary> */ - /* 421 Service not available, closing control connection. */ - /* 500 Syntax error, command unrecognized. */ - /* 501 Syntax error in parameters or arguments. */ - /* 502 Command not implemented. */ - /* 550 Requested action not taken. */ - i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", i, buffer); - if (i == -1 || i == 421) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Error reading from remote server"); - } - if (i == 550) { - return ap_proxyerror(r, HTTP_NOT_FOUND, buffer); - } - if (i == 257) { - const char *dirp = buffer; - apr_table_set(r->notes, "Directory-PWD", ap_getword_conf(r->pool, &dirp)); - } -#endif /*AUTODETECT_PWD*/ - - if (parms[0] == 'd') { - if (len != 0) - buf = apr_pstrcat(p, "LIST ", path, CRLF, NULL); - else - buf = apr_pstrcat(p, "LIST -lag", CRLF, NULL); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: LIST %s", (len == 0 ? "-lag" : path)); - } - else { -/* FIXME: Handle range requests - send REST */ - buf = apr_pstrcat(p, "RETR ", path, CRLF, NULL); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: RETR %s", path); - } - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - /* RETR: 110, 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 530, 550 - * NLST: 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 502, 530 */ - /* 110 Restart marker reply. */ - /* 125 Data connection already open; transfer starting. */ - /* 150 File status okay; about to open data connection. */ - /* 226 Closing data connection. */ - /* 250 Requested file action okay, completed. */ - /* 421 Service not available, closing control connection. */ - /* 425 Can't open data connection. */ - /* 426 Connection closed; transfer aborted. */ - /* 450 Requested file action not taken. */ - /* 451 Requested action aborted. Local error in processing. */ - /* 500 Syntax error, command unrecognized. */ - /* 501 Syntax error in parameters or arguments. */ - /* 530 Not logged in. */ - /* 550 Requested action not taken. */ - rc = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", rc, buffer); - if (rc == -1) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Error reading from remote server"); - } - if (rc == 550) { - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: RETR failed, trying LIST instead"); - parms = "d"; - buf = apr_pstrcat(p, "CWD ", path, CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: CWD %s", path); - /* possible results: 250, 421, 500, 501, 502, 530, 550 */ - /* 250 Requested file action okay, completed. */ - /* 421 Service not available, closing control connection. */ - /* 500 Syntax error, command unrecognized. */ - /* 501 Syntax error in parameters or arguments. */ - /* 502 Command not implemented. */ - /* 530 Not logged in. */ - /* 550 Requested action not taken. */ - rc = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", rc, buffer); - if (rc == -1) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Error reading from remote server"); - } - if (rc == 550) { - return ap_proxyerror(r, HTTP_NOT_FOUND, buffer); - } - if (rc != 250) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, buffer); - } - -#ifdef AUTODETECT_PWD - buf = apr_pstrcat(p, "PWD ", CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: PWD"); - /* responses: 257, 500, 501, 502, 421, 550 */ - /* 257 "<directory-name>" <commentary> */ - /* 421 Service not available, closing control connection. */ - /* 500 Syntax error, command unrecognized. */ - /* 501 Syntax error in parameters or arguments. */ - /* 502 Command not implemented. */ - /* 550 Requested action not taken. */ - i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", i, buffer); - if (i == -1 || i == 421) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Error reading from remote server"); - } - if (i == 550) { - return ap_proxyerror(r, HTTP_NOT_FOUND, buffer); - } - if (i == 257) { - const char *dirp = buffer; - apr_table_set(r->notes, "Directory-PWD", ap_getword_conf(r->pool, &dirp)); - } -#endif /*AUTODETECT_PWD*/ - - buf = apr_pstrcat(p, "LIST -lag", CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: LIST -lag"); - rc = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", rc, buffer); - if (rc == -1) - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Error reading from remote server"); - } - if (rc != 125 && rc != 150 && rc != 226 && rc != 250) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, buffer); - } - - r->status = HTTP_OK; - r->status_line = "200 OK"; - - apr_rfc822_date(dates, r->request_time); - apr_table_setn(r->headers_out, "Date", dates); - apr_table_setn(r->headers_out, "Server", ap_get_server_version()); - - /* set content-type */ - if (parms[0] == 'd') { - r->content_type = "text/html"; - } - else { - if (r->content_type) { - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: Content-Type set to %s", r->content_type); - } - else { - r->content_type = ap_default_type(r); - } - if (parms[0] != 'a' && size != NULL) { - /* We "trust" the ftp server to really serve (size) bytes... */ - apr_table_setn(r->headers_out, "Content-Length", size); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: Content-Length set to %s", size); - } - } - apr_table_setn(r->headers_out, "Content-Type", r->content_type); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: Content-Type set to %s", r->content_type); - - /* set content-encoding */ - if (r->content_encoding != NULL && r->content_encoding[0] != '\0') { - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: Content-Encoding set to %s", r->content_encoding); - apr_table_setn(r->headers_out, "Content-Encoding", r->content_encoding); - } - - /* wait for connection */ - if (use_port) { - for(;;) - { -/* FIXME: this does not return, despite the incoming connection being accepted */ - switch(rv = apr_accept(&remote_sock, local_sock, r->pool)) - { - case APR_EINTR: - continue; - case APR_SUCCESS: - break; - default: - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: FTP: failed to accept data connection"); - return HTTP_BAD_GATEWAY; - } - } - } - - /* the transfer socket is now open, create a new connection */ - remote = ap_new_connection(p, r->server, remote_sock, r->connection->id); - if (!remote) { - /* the peer reset the connection already; ap_new_connection() - * closed the socket */ - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: an error occurred creating the transfer connection"); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* set up the connection filters */ - ap_proxy_pre_http_connection(remote, NULL); - - - /* - * VI: Receive the Response - * ------------------------ - * - * Get response from the remote ftp socket, and pass it up the - * filter chain. - */ - - /* send response */ - r->sent_bodyct = 1; - - if (parms[0] == 'd') { - /* insert directory filter */ - ap_add_output_filter("PROXY_SEND_DIR", NULL, r, r->connection); - } - - /* send body */ - if (!r->header_only) { - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: start body send"); - - /* read the body, pass it to the output filters */ - while (ap_get_brigade(remote->input_filters, bb, AP_MODE_BLOCKING, &readbytes) == APR_SUCCESS) { - if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) { - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(r->output_filters, bb); - break; - } - ap_pass_brigade(r->output_filters, bb); - apr_brigade_cleanup(bb); - } - apr_brigade_cleanup(bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: end body send"); - - } - else { - - /* abort the transfer */ - buf = apr_pstrcat(p, "ABOR", CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: ABOR"); - /* responses: 225, 226, 421, 500, 501, 502 */ - /* 225 Data connection open; no transfer in progress. */ - /* 226 Closing data connection. */ - /* 421 Service not available, closing control connection. */ - /* 500 Syntax error, command unrecognized. */ - /* 501 Syntax error in parameters or arguments. */ - /* 502 Command not implemented. */ - i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", i, buffer); - } - - - /* - * VII: Clean Up - * ------------- - * - * If there are no KeepAlives, or if the connection has been signalled - * to close, close the socket and clean up - */ - - /* finish */ - buf = apr_pstrcat(p, "QUIT", CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: QUIT"); - /* responses: 221, 500 */ - /* 221 Service closing control connection. */ - /* 500 Syntax error, command unrecognized. */ - i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer)); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: FTP: %d %s", i, buffer); - - apr_brigade_destroy(bb); - return OK; -} - -static void ap_proxy_ftp_register_hook(apr_pool_t *p) -{ - /* hooks */ - proxy_hook_scheme_handler(ap_proxy_ftp_handler, NULL, NULL, APR_HOOK_MIDDLE); - proxy_hook_canon_handler(ap_proxy_ftp_canon, NULL, NULL, APR_HOOK_MIDDLE); - /* filters */ - ap_register_output_filter("PROXY_SEND_DIR", ap_proxy_send_dir_filter, AP_FTYPE_CONTENT); -} - -module AP_MODULE_DECLARE_DATA proxy_ftp_module = { - STANDARD20_MODULE_STUFF, - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - NULL, /* command apr_table_t */ - ap_proxy_ftp_register_hook /* register hooks */ -}; diff --git a/modules/proxy/proxy_http.c b/modules/proxy/proxy_http.c deleted file mode 100644 index f6d3213a28..0000000000 --- a/modules/proxy/proxy_http.c +++ /dev/null @@ -1,835 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* HTTP routines for Apache proxy */ - -#include "mod_proxy.h" - -module AP_MODULE_DECLARE_DATA proxy_http_module; - -PROXY_DECLARE (int) ap_proxy_http_canon(request_rec *r, char *url); -PROXY_DECLARE (int) ap_proxy_http_handler(request_rec *r, proxy_server_conf *conf, - char *url, const char *proxyname, - apr_port_t proxyport); - - -/* - * Canonicalise http-like URLs. - * scheme is the scheme for the URL - * url is the URL starting with the first '/' - * def_port is the default port for this scheme. - */ -PROXY_DECLARE (int) ap_proxy_http_canon(request_rec *r, char *url) -{ - char *host, *path, *search, sport[7]; - const char *err; - const char *scheme; - apr_port_t port, def_port; - - /* ap_default_port_for_scheme() */ - if (strncasecmp(url, "http:", 5) == 0) { - url += 5; - scheme = "http"; - } - else if (strncasecmp(url, "https:", 6) == 0) { - url += 6; - scheme = "https:"; - } - else { - return DECLINED; - } - def_port = ap_default_port_for_scheme(scheme); - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: HTTP: canonicalising URL %s", url); - - /* do syntatic check. - * We break the URL into host, port, path, search - */ - port = def_port; - err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port); - if (err) - return HTTP_BAD_REQUEST; - - /* now parse path/search args, according to rfc1738 */ - /* N.B. if this isn't a true proxy request, then the URL _path_ - * has already been decoded. True proxy requests have r->uri - * == r->unparsed_uri, and no others have that property. - */ - if (r->uri == r->unparsed_uri) { - search = strchr(url, '?'); - if (search != NULL) - *(search++) = '\0'; - } - else - search = r->args; - - /* process path */ - path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq); - if (path == NULL) - return HTTP_BAD_REQUEST; - - if (port != def_port) - apr_snprintf(sport, sizeof(sport), ":%d", port); - else - sport[0] = '\0'; - - r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport, "/", - path, (search) ? "?" : "", (search) ? search : "", NULL); - return OK; -} - -static const char *ap_proxy_location_reverse_map(request_rec *r, proxy_server_conf *conf, const char *url) -{ - struct proxy_alias *ent; - int i, l1, l2; - char *u; - - /* XXX FIXME: Make sure this handled the ambiguous case of the :80 - * after the hostname */ - - l1 = strlen(url); - ent = (struct proxy_alias *)conf->raliases->elts; - for (i = 0; i < conf->raliases->nelts; i++) { - l2 = strlen(ent[i].real); - if (l1 >= l2 && strncmp(ent[i].real, url, l2) == 0) { - u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL); - return ap_construct_url(r->pool, u, r); - } - } - return url; -} - -/* Clear all connection-based headers from the incoming headers table */ -static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers) -{ - const char *name; - char *next = apr_pstrdup(p, apr_table_get(headers, "Connection")); - - apr_table_unset(headers, "Proxy-Connection"); - if (!next) - return; - - while (*next) { - name = next; - while (*next && !apr_isspace(*next) && (*next != ',')) - ++next; - while (*next && (apr_isspace(*next) || (*next == ','))) { - *next = '\0'; - ++next; - } - apr_table_unset(headers, name); - } - apr_table_unset(headers, "Connection"); -} - -/* - * This handles http:// URLs, and other URLs using a remote proxy over http - * If proxyhost is NULL, then contact the server directly, otherwise - * go via the proxy. - * Note that if a proxy is used, then URLs other than http: can be accessed, - * also, if we have trouble which is clearly specific to the proxy, then - * we return DECLINED so that we can try another proxy. (Or the direct - * route.) - */ -PROXY_DECLARE (int) ap_proxy_http_handler(request_rec *r, proxy_server_conf *conf, - char *url, const char *proxyname, - apr_port_t proxyport) -{ - request_rec *rp; - const char *connectname; - int connectport = 0; - apr_sockaddr_t *uri_addr; - apr_sockaddr_t *connect_addr; - char server_portstr[32]; - apr_socket_t *sock; - int i, len, backasswards, eos, close=0, failed=0, new=0; - apr_status_t err, rv; - apr_array_header_t *headers_in_array; - apr_table_entry_t *headers_in; - char buffer[HUGE_STRING_LEN]; - char *buf; - conn_rec *origin; - uri_components uri; - proxy_conn_rec *backend; - - /* Note: Memory pool allocation. - * A downstream keepalive connection is always connected to the existence - * (or not) of an upstream keepalive connection. If this is not done then - * load balancing against multiple backend servers breaks (one backend - * server ends up taking 100% of the load), and the risk is run of - * downstream keepalive connections being kept open unnecessarily. This - * keeps webservers busy and ties up resources. - * - * As a result, we allocate all sockets out of the upstream connection - * pool, and when we want to reuse a socket, we check first whether the - * connection ID of the current upstream connection is the same as that - * of the connection when the socket was opened. - */ - apr_pool_t *p = r->connection->pool; - conn_rec *c = r->connection; - apr_bucket *e; - apr_bucket_brigade *bb = apr_brigade_create(p); - - /* is it for us? */ - if (strncasecmp(url, "http:", 5)) { - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: HTTP: rejecting URL %s", url); - return DECLINED; /* only interested in HTTP */ - } - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: HTTP: serving URL %s", url); - - /* create space for state information */ - backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config, &proxy_http_module); - if (!backend) { - backend = ap_pcalloc(c->pool, sizeof(proxy_conn_rec)); - backend->connection = NULL; - backend->hostname = NULL; - backend->port = 0; - ap_set_module_config(c->conn_config, &proxy_http_module, backend); - } - - /* - * Step One: Determine Who To Connect To - * - * Break up the URL to determine the host to connect to - */ - - /* we break the URL into host, port, uri */ - if (HTTP_OK != ap_parse_uri_components(p, url, &uri)) { - return ap_proxyerror(r, HTTP_BAD_REQUEST, - apr_pstrcat(p,"URI cannot be parsed: ", url, NULL)); - } - if (!uri.port) { - uri.port = ap_default_port_for_scheme(uri.scheme); - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: HTTP connecting %s to %s:%d", url, uri.hostname, uri.port); - - /* do a DNS lookup for the destination host */ - /* see memory note above */ - err = apr_sockaddr_info_get(&uri_addr, apr_pstrdup(c->pool, uri.hostname), APR_UNSPEC, uri.port, 0, c->pool); - - /* allocate these out of the connection pool - the check on r->connection->id makes - * sure that this string does not get accessed past the connection lifetime */ - /* are we connecting directly, or via a proxy? */ - if (proxyname) { - connectname = apr_pstrdup(c->pool,proxyname); - connectport = proxyport; - /* see memory note above */ - err = apr_sockaddr_info_get(&connect_addr, connectname, APR_UNSPEC, connectport, 0, c->pool); - } - else { - connectname = apr_pstrdup(c->pool, uri.hostname); - connectport = uri.port; - connect_addr = uri_addr; - url = apr_pstrcat(p, uri.path, uri.query ? "?" : "", - uri.query ? uri.query : "", uri.fragment ? "#" : "", - uri.fragment ? uri.fragment : "", NULL); - } - - - /* Get the server port for the Via headers */ - { - i = ap_get_server_port(r); - if (ap_is_default_port(i,r)) { - strcpy(server_portstr,""); - } else { - apr_snprintf(server_portstr, sizeof server_portstr, ":%d", i); - } - } - - /* check if ProxyBlock directive on this host */ - if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) { - return ap_proxyerror(r, HTTP_FORBIDDEN, - "Connect to remote machine blocked"); - } - - - /* - * Step Two: Make the Connection - * - * We have determined who to connect to. Now make the connection, supporting - * a KeepAlive connection. - */ - - /* get all the possible IP addresses for the destname and loop through them - * until we get a successful connection - */ - if (APR_SUCCESS != err) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p, - "DNS lookup failure for: ", - connectname, NULL)); - } - - /* if a keepalive socket is already open, check whether it must stay - * open, or whether it should be closed and a new socket created. - */ - /* see memory note above */ - if (backend->connection) { - if ((backend->connection->id == c->id) && - (backend->port == connectport) && - (backend->hostname) && - (!apr_strnatcasecmp(backend->hostname,connectname))) { - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: keepalive address match (keep original socket)"); - } - else { - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: keepalive address mismatch / connection has" - " changed (close old socket (%s/%s, %d/%d))", - connectname, backend->hostname, - connectport, backend->port); - apr_socket_close(backend->connection->client_socket); - backend->connection = NULL; - } - } - - /* get a socket - either a keepalive one, or a new one */ - new = 1; - if ((backend->connection) && (backend->connection->id == c->id)) { - - /* use previous keepalive socket */ - origin = backend->connection; - sock = origin->client_socket; - new = 0; - - /* reset the connection filters */ - ap_proxy_reset_output_filters(origin); - - /* XXX FIXME: If the socket has since closed, change new to 1 so - * a new socket is opened */ - } - if (new) { - - /* create a new socket */ - backend->connection = NULL; - - /* see memory note above */ - if ((rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, c->pool)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: error creating socket"); - return HTTP_INTERNAL_SERVER_ERROR; - } - -#if !defined(TPF) && !defined(BEOS) - if (conf->recv_buffer_size > 0 && (rv = apr_setsocketopt(sock, APR_SO_RCVBUF, - conf->recv_buffer_size))) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default"); - } -#endif - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: socket has been created"); - - /* - * At this point we have a list of one or more IP addresses of - * the machine to connect to. If configured, reorder this - * list so that the "best candidate" is first try. "best - * candidate" could mean the least loaded server, the fastest - * responding server, whatever. - * - * For now we do nothing, ie we get DNS round robin. - * XXX FIXME - */ - - - /* try each IP address until we connect successfully */ - failed = 1; - while (connect_addr) { - - /* make the connection out of the socket */ - rv = apr_connect(sock, connect_addr); - - /* if an error occurred, loop round and try again */ - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: attempt to connect to %pI (%s) failed", - connect_addr, connectname); - connect_addr = connect_addr->next; - continue; - } - - /* if we get here, all is well */ - failed = 0; - break; - } - - /* handle a permanent error from the above loop */ - if (failed) { - apr_socket_close(sock); - if (proxyname) { - return DECLINED; - } - else { - return HTTP_BAD_GATEWAY; - } - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: socket is connected"); - - /* the socket is now open, create a new backend server connection */ - origin = ap_new_connection(c->pool, r->server, sock, r->connection->id); - if (!origin) { - /* the peer reset the connection already; ap_new_connection() - * closed the socket */ - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: an error occurred creating a new connection to %pI (%s)", connect_addr, connectname); - apr_socket_close(sock); - return HTTP_INTERNAL_SERVER_ERROR; - } - backend->connection = origin; - backend->hostname = apr_pstrdup(c->pool, connectname); - backend->port = connectport; - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: connection complete"); - - /* set up the connection filters */ - ap_proxy_pre_http_connection(origin, NULL); - - } - - - /* - * Step Three: Send the Request - * - * Send the HTTP/1.1 request to the remote server - */ - - - /* strip connection listed hop-by-hop headers from the request */ - /* even though in theory a connection: close coming from the client - * should not affect the connection to the server, it's unlikely - * that subsequent client requests will hit this thread/process, so - * we cancel server keepalive if the client does. - */ - close += ap_proxy_liststr(apr_table_get(r->headers_in, "Connection"), "close"); - ap_proxy_clear_connection(p, r->headers_in); - if (close) { - apr_table_mergen(r->headers_in, "Connection", "close"); - origin->keepalive = 0; - } - - buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - if (uri.port_str && uri.port != DEFAULT_HTTP_PORT) { - buf = apr_pstrcat(p, "Host: ", uri.hostname, ":", uri.port_str, CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - } - else { - buf = apr_pstrcat(p, "Host: ", uri.hostname, CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - } - - /* handle Via */ - if (conf->viaopt == via_block) { - /* Block all outgoing Via: headers */ - apr_table_unset(r->headers_in, "Via"); - } else if (conf->viaopt != via_off) { - /* Create a "Via:" request header entry and merge it */ - /* Generate outgoing Via: header with/without server comment: */ - apr_table_mergen(r->headers_in, "Via", - (conf->viaopt == via_full) - ? apr_psprintf(p, "%d.%d %s%s (%s)", - HTTP_VERSION_MAJOR(r->proto_num), - HTTP_VERSION_MINOR(r->proto_num), - ap_get_server_name(r), server_portstr, - AP_SERVER_BASEVERSION) - : apr_psprintf(p, "%d.%d %s%s", - HTTP_VERSION_MAJOR(r->proto_num), - HTTP_VERSION_MINOR(r->proto_num), - ap_get_server_name(r), server_portstr) - ); - } - - /* X-Forwarded-*: handling - * - * XXX Privacy Note: - * ----------------- - * - * These request headers are only really useful when the mod_proxy - * is used in a reverse proxy configuration, so that useful info - * about the client can be passed through the reverse proxy and on - * to the backend server, which may require the information to - * function properly. - * - * In a forward proxy situation, these options are a potential - * privacy violation, as information about clients behind the proxy - * are revealed to arbitrary servers out there on the internet. - * - * The HTTP/1.1 Via: header is designed for passing client - * information through proxies to a server, and should be used in - * a forward proxy configuation instead of X-Forwarded-*. See the - * ProxyVia option for details. - */ - - if (PROXYREQ_REVERSE == r->proxyreq) { - const char *buf; - - /* Add X-Forwarded-For: so that the upstream has a chance to - * determine, where the original request came from. - */ - apr_table_mergen(r->headers_in, "X-Forwarded-For", r->connection->remote_ip); - - /* Add X-Forwarded-Host: so that upstream knows what the - * original request hostname was. - */ - if ((buf = apr_table_get(r->headers_in, "Host"))) { - apr_table_mergen(r->headers_in, "X-Forwarded-Host", buf); - } - - /* Add X-Forwarded-Server: so that upstream knows what the - * name of this proxy server is (if there are more than one) - * XXX: This duplicates Via: - do we strictly need it? - */ - apr_table_mergen(r->headers_in, "X-Forwarded-Server", - r->server->server_hostname); - } - - /* send request headers */ - headers_in_array = apr_table_elts(r->headers_in); - headers_in = (apr_table_entry_t *) headers_in_array->elts; - for (i = 0; i < headers_in_array->nelts; i++) { - if (headers_in[i].key == NULL || headers_in[i].val == NULL - - /* Clear out hop-by-hop request headers not to send - * RFC2616 13.5.1 says we should strip these headers - */ - || !apr_strnatcasecmp(headers_in[i].key, "Host") /* Already sent */ - || !apr_strnatcasecmp(headers_in[i].key, "Keep-Alive") - || !apr_strnatcasecmp(headers_in[i].key, "TE") - || !apr_strnatcasecmp(headers_in[i].key, "Trailer") - || !apr_strnatcasecmp(headers_in[i].key, "Transfer-Encoding") - || !apr_strnatcasecmp(headers_in[i].key, "Upgrade") - - /* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be - * suppressed if THIS server requested the authentication, - * not when a frontend proxy requested it! - * - * The solution to this problem is probably to strip out - * the Proxy-Authorisation header in the authorisation - * code itself, not here. This saves us having to signal - * somehow whether this request was authenticated or not. - */ - || !apr_strnatcasecmp(headers_in[i].key, "Proxy-Authorization") - || !apr_strnatcasecmp(headers_in[i].key, "Proxy-Authenticate")) - continue; - - buf = apr_pstrcat(p, headers_in[i].key, ": ", headers_in[i].val, CRLF, NULL); - e = apr_bucket_pool_create(buf, strlen(buf), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - - } - - /* add empty line at the end of the headers */ - e = apr_bucket_pool_create(CRLF, strlen(CRLF), p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - - ap_pass_brigade(origin->output_filters, bb); - - /* send the request data, if any. */ - if (ap_should_client_block(r)) { - while ((i = ap_get_client_block(r, buffer, sizeof buffer)) > 0) { - e = apr_bucket_pool_create(buffer, i, p); - APR_BRIGADE_INSERT_TAIL(bb, e); - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(origin->output_filters, bb); - apr_brigade_cleanup(bb); - } - } - - - /* - * Step Four: Receive the Response - * - * Get response from the remote server, and pass it up the - * filter chain - */ - - rp = make_fake_req(origin, r); - - apr_brigade_cleanup(bb); - - if (APR_SUCCESS != (rv = ap_proxy_string_read(origin, bb, buffer, sizeof(buffer), &eos))) { - apr_socket_close(sock); - backend->connection = NULL; - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "proxy: error reading status line from remote server %s", - connectname); - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - "Error reading from remote server"); - } - len = strlen(buffer); - - /* Is it an HTTP/1 response? This is buggy if we ever see an HTTP/1.10 */ - if (ap_checkmask(buffer, "HTTP/#.# ###*")) { - int major, minor; - - if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) { - major = 1; - minor = 1; - } - - /* If not an HTTP/1 message or if the status line was > 8192 bytes */ - else if ((buffer[5] != '1') || (len >= sizeof(buffer)-1)) { - apr_socket_close(sock); - backend->connection = NULL; - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - apr_pstrcat(p, "Corrupt status line returned by remote server: ", buffer, NULL)); - } - backasswards = 0; - buffer[--len] = '\0'; - - buffer[12] = '\0'; - r->status = atoi(&buffer[9]); - - buffer[12] = ' '; - r->status_line = apr_pstrdup(p, &buffer[9]); - - /* read the headers. */ - /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */ - /* Also, take care with headers with multiple occurences. */ - - r->headers_out = ap_proxy_read_headers(r, rp, buffer, sizeof(buffer), origin); - if (r->headers_out == NULL) { - ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server, - "proxy: bad HTTP/%d.%d header returned by %s (%s)", - major, minor, r->uri, r->method); - close += 1; - } - else - { - /* strip connection listed hop-by-hop headers from response */ - const char *buf; - close += ap_proxy_liststr(apr_table_get(r->headers_out, "Connection"), "close"); - ap_proxy_clear_connection(p, r->headers_out); - if ((buf = apr_table_get(r->headers_out, "Content-Type"))) { - r->content_type = apr_pstrdup(p, buf); - } - } - - /* handle Via header in response */ - if (conf->viaopt != via_off && conf->viaopt != via_block) { - /* create a "Via:" response header entry and merge it */ - ap_table_mergen(r->headers_out, "Via", - (conf->viaopt == via_full) - ? apr_psprintf(p, "%d.%d %s%s (%s)", - HTTP_VERSION_MAJOR(r->proto_num), - HTTP_VERSION_MINOR(r->proto_num), - ap_get_server_name(r), server_portstr, - AP_SERVER_BASEVERSION) - : apr_psprintf(p, "%d.%d %s%s", - HTTP_VERSION_MAJOR(r->proto_num), - HTTP_VERSION_MINOR(r->proto_num), - ap_get_server_name(r), server_portstr) - ); - } - - /* cancel keepalive if HTTP/1.0 or less */ - if ((major < 1) || (minor < 1)) { - close += 1; - origin->keepalive = 0; - } - } - else { - /* an http/0.9 response */ - backasswards = 1; - r->status = 200; - r->status_line = "200 OK"; - close += 1; - } - - /* we must accept 3 kinds of date, but generate only 1 kind of date */ - { - const char *buf; - if ((buf = apr_table_get(r->headers_out, "Date")) != NULL) { - apr_table_set(r->headers_out, "Date", ap_proxy_date_canon(p, buf)); - } - if ((buf = apr_table_get(r->headers_out, "Expires")) != NULL) { - apr_table_set(r->headers_out, "Expires", ap_proxy_date_canon(p, buf)); - } - if ((buf = apr_table_get(r->headers_out, "Last-Modified")) != NULL) { - apr_table_set(r->headers_out, "Last-Modified", ap_proxy_date_canon(p, buf)); - } - } - - /* munge the Location and URI response headers according to ProxyPassReverse */ - { - const char *buf; - if ((buf = apr_table_get(r->headers_out, "Location")) != NULL) { - apr_table_set(r->headers_out, "Location", ap_proxy_location_reverse_map(r, conf, buf)); - } - if ((buf = apr_table_get(r->headers_out, "Content-Location")) != NULL) { - apr_table_set(r->headers_out, "Content-Location", ap_proxy_location_reverse_map(r, conf, buf)); - } - if ((buf = apr_table_get(r->headers_out, "URI")) != NULL) { - apr_table_set(r->headers_out, "URI", ap_proxy_location_reverse_map(r, conf, buf)); - } - } - - r->sent_bodyct = 1; - /* Is it an HTTP/0.9 response? If so, send the extra data */ - if (backasswards) { - apr_ssize_t cntr = len; - e = apr_bucket_heap_create(buffer, cntr, 0, NULL); - APR_BRIGADE_INSERT_TAIL(bb, e); - } - - /* send body - but only if a body is expected */ - if ((!r->header_only) && /* not HEAD request */ - (r->status > 199) && /* not any 1xx response */ - (r->status != HTTP_NO_CONTENT) && /* not 204 */ - (r->status != HTTP_RESET_CONTENT) && /* not 205 */ - (r->status != HTTP_NOT_MODIFIED)) { /* not 304 */ - - const char *buf; - apr_size_t readbytes; - - /* if chunked - insert DECHUNK filter */ - if (ap_proxy_liststr((buf = apr_table_get(r->headers_out, "Transfer-Encoding")), "chunked")) { - rp->read_chunked = 1; - apr_table_unset(r->headers_out, "Transfer-Encoding"); - if ((buf = ap_proxy_removestr(r->pool, buf, "chunked"))) { - apr_table_set(r->headers_out, "Transfer-Encoding", buf); - } - ap_add_input_filter("DECHUNK", NULL, rp, origin); - readbytes = -1; - } - - /* if content length - set the length to read */ - else if ((buf = apr_table_get(r->headers_out, "Content-Length"))) { - readbytes = atol(buf); - } - - /* no chunked / no length therefore read till EOF and cancel keepalive */ - else { - close += 1; - } - - /* if keepalive cancelled, read to EOF */ - if (close) { - readbytes = -1; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: start body send"); - - /* read the body, pass it to the output filters */ - while (ap_get_brigade(rp->input_filters, bb, AP_MODE_BLOCKING, &readbytes) == APR_SUCCESS) { - if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) { - e = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(r->output_filters, bb); - break; - } - ap_pass_brigade(r->output_filters, bb); - apr_brigade_cleanup(bb); - } - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: end body send"); - } - else { - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: header only"); - } - - - /* - * Step Five: Clean Up - * - * If there are no KeepAlives, or if the connection has been signalled - * to close, close the socket and clean up - */ - - /* if the connection is < HTTP/1.1, or Connection: close, - * we close the socket, otherwise we leave it open for KeepAlive support - */ - if (close || (r->proto_num < HTTP_VERSION(1,1))) { - apr_socket_close(sock); - backend->connection = NULL; - } - - return OK; -} - -static void ap_proxy_http_register_hook(apr_pool_t *p) -{ - proxy_hook_scheme_handler(ap_proxy_http_handler, NULL, NULL, APR_HOOK_FIRST); - proxy_hook_canon_handler(ap_proxy_http_canon, NULL, NULL, APR_HOOK_FIRST); -} - -module AP_MODULE_DECLARE_DATA proxy_http_module = { - STANDARD20_MODULE_STUFF, - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - NULL, /* command apr_table_t */ - ap_proxy_http_register_hook /* register hooks */ -}; diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c deleted file mode 100644 index b51feb1a11..0000000000 --- a/modules/proxy/proxy_util.c +++ /dev/null @@ -1,1187 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* Utility routines for Apache proxy */ -#include "mod_proxy.h" - - -static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r); -static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r); -static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r); -static int proxy_match_word(struct dirconn_entry *This, request_rec *r); -static struct per_thread_data *get_per_thread_data(void); - -/* already called in the knowledge that the characters are hex digits */ -int ap_proxy_hex2c(const char *x) -{ - int i, ch; - -#if !APR_CHARSET_EBCDIC - ch = x[0]; - if (apr_isdigit(ch)) - i = ch - '0'; - else if (apr_isupper(ch)) - i = ch - ('A' - 10); - else - i = ch - ('a' - 10); - i <<= 4; - - ch = x[1]; - if (apr_isdigit(ch)) - i += ch - '0'; - else if (apr_isupper(ch)) - i += ch - ('A' - 10); - else - i += ch - ('a' - 10); - return i; -#else /*APR_CHARSET_EBCDIC*/ - return (1 == sscanf(x, "%2x", &i)) ? os_toebcdic[i&0xFF] : 0; -#endif /*APR_CHARSET_EBCDIC*/ -} - -void ap_proxy_c2hex(int ch, char *x) -{ -#if !APR_CHARSET_EBCDIC - int i; - - x[0] = '%'; - i = (ch & 0xF0) >> 4; - if (i >= 10) - x[1] = ('A' - 10) + i; - else - x[1] = '0' + i; - - i = ch & 0x0F; - if (i >= 10) - x[2] = ('A' - 10) + i; - else - x[2] = '0' + i; -#else /*APR_CHARSET_EBCDIC*/ - static const char ntoa[] = { "0123456789ABCDEF" }; - ch &= 0xFF; - x[0] = '%'; - x[1] = ntoa[(os_toascii[ch]>>4)&0x0F]; - x[2] = ntoa[os_toascii[ch]&0x0F]; - x[3] = '\0'; -#endif /*APR_CHARSET_EBCDIC*/ -} - -/* - * canonicalise a URL-encoded string - */ - -/* - * Convert a URL-encoded string to canonical form. - * It decodes characters which need not be encoded, - * and encodes those which must be encoded, and does not touch - * those which must not be touched. - */ -char *ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t, - int isenc) -{ - int i, j, ch; - char *y; - char *allowed; /* characters which should not be encoded */ - char *reserved; /* characters which much not be en/de-coded */ - -/* N.B. in addition to :@&=, this allows ';' in an http path - * and '?' in an ftp path -- this may be revised - * - * Also, it makes a '+' character in a search string reserved, as - * it may be form-encoded. (Although RFC 1738 doesn't allow this - - * it only permits ; / ? : @ = & as reserved chars.) - */ - if (t == enc_path) - allowed = "$-_.+!*'(),;:@&="; - else if (t == enc_search) - allowed = "$-_.!*'(),;:@&="; - else if (t == enc_user) - allowed = "$-_.+!*'(),;@&="; - else if (t == enc_fpath) - allowed = "$-_.+!*'(),?:@&="; - else /* if (t == enc_parm) */ - allowed = "$-_.+!*'(),?/:@&="; - - if (t == enc_path) - reserved = "/"; - else if (t == enc_search) - reserved = "+"; - else - reserved = ""; - - y = apr_palloc(p, 3 * len + 1); - - for (i = 0, j = 0; i < len; i++, j++) { -/* always handle '/' first */ - ch = x[i]; - if (strchr(reserved, ch)) { - y[j] = ch; - continue; - } -/* decode it if not already done */ - if (isenc && ch == '%') { - if (!ap_isxdigit(x[i + 1]) || !ap_isxdigit(x[i + 2])) - return NULL; - ch = ap_proxy_hex2c(&x[i + 1]); - i += 2; - if (ch != 0 && strchr(reserved, ch)) { /* keep it encoded */ - ap_proxy_c2hex(ch, &y[j]); - j += 2; - continue; - } - } -/* recode it, if necessary */ - if (!apr_isalnum(ch) && !strchr(allowed, ch)) { - ap_proxy_c2hex(ch, &y[j]); - j += 2; - } - else - y[j] = ch; - } - y[j] = '\0'; - return y; -} - -/* - * Parses network-location. - * urlp on input the URL; on output the path, after the leading / - * user NULL if no user/password permitted - * password holder for password - * host holder for host - * port port number; only set if one is supplied. - * - * Returns an error string. - */ -char * - ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp, - char **passwordp, char **hostp, apr_port_t *port) -{ - apr_port_t i; - char *strp, *host, *url = *urlp; - char *user = NULL, *password = NULL; - - if (url[0] != '/' || url[1] != '/') - return "Malformed URL"; - host = url + 2; - url = strchr(host, '/'); - if (url == NULL) - url = ""; - else - *(url++) = '\0'; /* skip seperating '/' */ - - /* find _last_ '@' since it might occur in user/password part */ - strp = strrchr(host, '@'); - - if (strp != NULL) { - *strp = '\0'; - user = host; - host = strp + 1; - -/* find password */ - strp = strchr(user, ':'); - if (strp != NULL) { - *strp = '\0'; - password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1); - if (password == NULL) - return "Bad %-escape in URL (password)"; - } - - user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1); - if (user == NULL) - return "Bad %-escape in URL (username)"; - } - if (userp != NULL) { - *userp = user; - } - if (passwordp != NULL) { - *passwordp = password; - } - - strp = strrchr(host, ':'); - if (strp != NULL) { - *(strp++) = '\0'; - - for (i = 0; strp[i] != '\0'; i++) - if (!apr_isdigit(strp[i])) - break; - - /* if (i == 0) the no port was given; keep default */ - if (strp[i] != '\0') { - return "Bad port number in URL"; - } else if (i > 0) { - *port = atoi(strp); - if (*port > 65535) - return "Port number in URL > 65535"; - } - } - ap_str_tolower(host); /* DNS names are case-insensitive */ - if (*host == '\0') - return "Missing host in URL"; -/* check hostname syntax */ - for (i = 0; host[i] != '\0'; i++) - if (!apr_isdigit(host[i]) && host[i] != '.') - break; - /* must be an IP address */ -#if defined(WIN32) || defined(NETWARE) || defined(TPF) || defined(BEOS) - if (host[i] == '\0' && (inet_addr(host) == -1)) -#else - if (host[i] == '\0' && (ap_inet_addr(host) == -1 || inet_network(host) == -1)) -#endif - { - return "Bad IP address in URL"; - } - -/* if (strchr(host,'.') == NULL && domain != NULL) - host = pstrcat(p, host, domain, NULL); - */ - *urlp = url; - *hostp = host; - - return NULL; -} - -static const char * const lwday[7] = -{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; - -/* - * If the date is a valid RFC 850 date or asctime() date, then it - * is converted to the RFC 1123 format, otherwise it is not modified. - * This routine is not very fast at doing conversions, as it uses - * sscanf and sprintf. However, if the date is already correctly - * formatted, then it exits very quickly. - */ -const char * - ap_proxy_date_canon(apr_pool_t *p, const char *x1) -{ - char *x = apr_pstrdup(p, x1); - int wk, mday, year, hour, min, sec, mon; - char *q, month[4], zone[4], week[4]; - - q = strchr(x, ','); - /* check for RFC 850 date */ - if (q != NULL && q - x > 3 && q[1] == ' ') { - *q = '\0'; - for (wk = 0; wk < 7; wk++) - if (strcmp(x, lwday[wk]) == 0) - break; - *q = ','; - if (wk == 7) - return x; /* not a valid date */ - if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' || - q[17] != ':' || strcmp(&q[20], " GMT") != 0) - return x; - if (sscanf(q + 2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year, - &hour, &min, &sec, zone) != 7) - return x; - if (year < 70) - year += 2000; - else - year += 1900; - } - else { -/* check for acstime() date */ - if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' || - x[16] != ':' || x[19] != ' ' || x[24] != '\0') - return x; - if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour, - &min, &sec, &year) != 7) - return x; - for (wk = 0; wk < 7; wk++) - if (strcmp(week, ap_day_snames[wk]) == 0) - break; - if (wk == 7) - return x; - } - -/* check date */ - for (mon = 0; mon < 12; mon++) - if (strcmp(month, ap_month_snames[mon]) == 0) - break; - if (mon == 12) - return x; - - q = apr_palloc(p, 30); - apr_snprintf(q, 30, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", ap_day_snames[wk], - mday, ap_month_snames[mon], year, hour, min, sec); - return q; -} - -request_rec *make_fake_req(conn_rec *c, request_rec *r) -{ - request_rec *rp = apr_pcalloc(c->pool, sizeof(*r)); - core_request_config *req_cfg; - - rp->pool = c->pool; - rp->status = HTTP_OK; - - rp->headers_in = apr_table_make(c->pool, 50); - rp->subprocess_env = apr_table_make(c->pool, 50); - rp->headers_out = apr_table_make(c->pool, 12); - rp->err_headers_out = apr_table_make(c->pool, 5); - rp->notes = apr_table_make(c->pool, 5); - - rp->server = r->server; - rp->request_time = r->request_time; - rp->connection = c; - rp->output_filters = c->output_filters; - rp->input_filters = c->input_filters; - - rp->request_config = ap_create_request_config(c->pool); - req_cfg = apr_pcalloc(rp->pool, sizeof(core_request_config)); - req_cfg->bb = apr_brigade_create(c->pool); - ap_set_module_config(rp->request_config, &core_module, req_cfg); - - return rp; -} - -/* - * Reads headers from a buffer and returns an array of headers. - * Returns NULL on file error - * This routine tries to deal with too long lines and continuation lines. - * @@@: XXX: FIXME: currently the headers are passed thru un-merged. - * Is that okay, or should they be collapsed where possible? - */ -apr_table_t *ap_proxy_read_headers(request_rec *r, request_rec *rr, char *buffer, int size, conn_rec *c) -{ - apr_table_t *headers_out; - int len; - char *value, *end; - char field[MAX_STRING_LEN]; - - headers_out = ap_make_table(r->pool, 20); - - /* - * Read header lines until we get the empty separator line, a read error, - * the connection closes (EOF), or we timeout. - */ - while ((len = ap_getline(buffer, size, rr, 1)) > 0) { - - if (!(value = strchr(buffer, ':'))) { /* Find the colon separator */ - - /* Buggy MS IIS servers sometimes return invalid headers - * (an extra "HTTP/1.0 200, OK" line sprinkled in between - * the usual MIME headers). Try to deal with it in a sensible - * way, but log the fact. - * XXX: The mask check is buggy if we ever see an HTTP/1.10 */ - - if (!ap_checkmask(buffer, "HTTP/#.# ###*")) { - /* Nope, it wasn't even an extra HTTP header. Give up. */ - return NULL; - } - - ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server, - "proxy: Ignoring duplicate HTTP header " - "returned by %s (%s)", r->uri, r->method); - continue; - } - - *value = '\0'; - ++value; - /* XXX: RFC2068 defines only SP and HT as whitespace, this test is - * wrong... and so are many others probably. - */ - while (apr_isspace(*value)) - ++value; /* Skip to start of value */ - - /* should strip trailing whitespace as well */ - for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end) - *end = '\0'; - - apr_table_add(headers_out, buffer, value); - - /* the header was too long; at the least we should skip extra data */ - if (len >= size - 1) { - while ((len = ap_getline(field, MAX_STRING_LEN, rr, 1)) - >= MAX_STRING_LEN - 1) { - /* soak up the extra data */ - } - if (len == 0) /* time to exit the larger loop as well */ - break; - } - } - return headers_out; -} - - -/* - * list is a comma-separated list of case-insensitive tokens, with - * optional whitespace around the tokens. - * The return returns 1 if the token val is found in the list, or 0 - * otherwise. - */ -int ap_proxy_liststr(const char *list, const char *val) -{ - int len, i; - const char *p; - - len = strlen(val); - - while (list != NULL) { - p = ap_strchr_c(list, ','); - if (p != NULL) { - i = p - list; - do - p++; - while (apr_isspace(*p)); - } - else - i = strlen(list); - - while (i > 0 && apr_isspace(list[i - 1])) - i--; - if (i == len && strncasecmp(list, val, len) == 0) - return 1; - list = p; - } - return 0; -} - -/* - * list is a comma-separated list of case-insensitive tokens, with - * optional whitespace around the tokens. - * The return returns 1 if the token val is found in the list, or 0 - * otherwise. - */ -char *ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val) -{ - int len, i; - const char *p; - char *new = NULL; - - len = strlen(val); - - while (list != NULL) { - p = ap_strchr_c(list, ','); - if (p != NULL) { - i = p - list; - do - p++; - while (apr_isspace(*p)); - } - else - i = strlen(list); - - while (i > 0 && apr_isspace(list[i - 1])) - i--; - if (i == len && strncasecmp(list, val, len) == 0) { - /* do nothing */ - } - else { - if (new) - new = apr_pstrcat(pool, new, ",", apr_pstrndup(pool, list, i), NULL); - else - new = apr_pstrndup(pool, list, i); - } - list = p; - } - return new; -} - -/* - * Converts 8 hex digits to a time integer - */ -int ap_proxy_hex2sec(const char *x) -{ - int i, ch; - unsigned int j; - - for (i = 0, j = 0; i < 8; i++) { - ch = x[i]; - j <<= 4; - if (apr_isdigit(ch)) - j |= ch - '0'; - else if (apr_isupper(ch)) - j |= ch - ('A' - 10); - else - j |= ch - ('a' - 10); - } - if (j == 0xffffffff) - return -1; /* so that it works with 8-byte ints */ - else - return j; -} - -/* - * Converts a time integer to 8 hex digits - */ -void ap_proxy_sec2hex(int t, char *y) -{ - int i, ch; - unsigned int j = t; - - for (i = 7; i >= 0; i--) { - ch = j & 0xF; - j >>= 4; - if (ch >= 10) - y[i] = ch + ('A' - 10); - else - y[i] = ch + '0'; - } - y[8] = '\0'; -} - -int ap_proxyerror(request_rec *r, int statuscode, const char *message) -{ - apr_table_setn(r->notes, "error-notes", - apr_pstrcat(r->pool, - "The proxy server could not handle the request " - "<EM><A HREF=\"", ap_escape_uri(r->pool, r->uri), - "\">", ap_escape_html(r->pool, r->method), - " ", - ap_escape_html(r->pool, r->uri), "</A></EM>.<P>\n" - "Reason: <STRONG>", - ap_escape_html(r->pool, message), - "</STRONG>", NULL)); - - /* Allow "error-notes" string to be printed by ap_send_error_response() */ - apr_table_setn(r->notes, "verbose-error-to", apr_pstrdup(r->pool, "*")); - - r->status_line = apr_psprintf(r->pool, "%3.3u Proxy Error", statuscode); - return statuscode; -} - -/* - * This routine returns its own error message - */ -const char *ap_proxy_host2addr(const char *host, struct hostent *reqhp) -{ - int i; - struct hostent *hp; - struct per_thread_data *ptd = get_per_thread_data(); - - for (i = 0; host[i] != '\0'; i++) - if (!apr_isdigit(host[i]) && host[i] != '.') - break; - - if (host[i] != '\0') { - hp = gethostbyname(host); - if (hp == NULL) - return "Host not found"; - } - else { - ptd->ipaddr = ap_inet_addr(host); - hp = gethostbyaddr((char *) &ptd->ipaddr, sizeof(ptd->ipaddr), AF_INET); - if (hp == NULL) { - memset(&ptd->hpbuf, 0, sizeof(ptd->hpbuf)); - ptd->hpbuf.h_name = 0; - ptd->hpbuf.h_addrtype = AF_INET; - ptd->hpbuf.h_length = sizeof(ptd->ipaddr); - ptd->hpbuf.h_addr_list = ptd->charpbuf; - ptd->hpbuf.h_addr_list[0] = (char *) &ptd->ipaddr; - ptd->hpbuf.h_addr_list[1] = 0; - hp = &ptd->hpbuf; - } - } - *reqhp = *hp; - return NULL; -} - -static const char * - proxy_get_host_of_request(request_rec *r) -{ - char *url, *user = NULL, *password = NULL, *err, *host; - apr_port_t port = -1; - - if (r->hostname != NULL) - return r->hostname; - - /* Set url to the first char after "scheme://" */ - if ((url = strchr(r->uri, ':')) == NULL - || url[1] != '/' || url[2] != '/') - return NULL; - - url = apr_pstrdup(r->pool, &url[1]); /* make it point to "//", which is what proxy_canon_netloc expects */ - - err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port); - - if (err != NULL) - ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, - "%s", err); - - r->hostname = host; - - return host; /* ought to return the port, too */ -} - -/* Return TRUE if addr represents an IP address (or an IP network address) */ -int ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p) -{ - const char *addr = This->name; - long ip_addr[4]; - int i, quads; - long bits; - - /* if the address is given with an explicit netmask, use that */ - /* Due to a deficiency in ap_inet_addr(), it is impossible to parse */ - /* "partial" addresses (with less than 4 quads) correctly, i.e. */ - /* 192.168.123 is parsed as 192.168.0.123, which is not what I want. */ - /* I therefore have to parse the IP address manually: */ - /*if (proxy_readmask(This->name, &This->addr.s_addr, &This->mask.s_addr) == 0) */ - /* addr and mask were set by proxy_readmask() */ - /*return 1; */ - - /* Parse IP addr manually, optionally allowing */ - /* abbreviated net addresses like 192.168. */ - - /* Iterate over up to 4 (dotted) quads. */ - for (quads = 0; quads < 4 && *addr != '\0'; ++quads) { - char *tmp; - - if (*addr == '/' && quads > 0) /* netmask starts here. */ - break; - - if (!apr_isdigit(*addr)) - return 0; /* no digit at start of quad */ - - ip_addr[quads] = strtol(addr, &tmp, 0); - - if (tmp == addr) /* expected a digit, found something else */ - return 0; - - if (ip_addr[quads] < 0 || ip_addr[quads] > 255) { - /* invalid octet */ - return 0; - } - - addr = tmp; - - if (*addr == '.' && quads != 3) - ++addr; /* after the 4th quad, a dot would be illegal */ - } - - for (This->addr.s_addr = 0, i = 0; i < quads; ++i) - This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i)); - - if (addr[0] == '/' && apr_isdigit(addr[1])) { /* net mask follows: */ - char *tmp; - - ++addr; - - bits = strtol(addr, &tmp, 0); - - if (tmp == addr) /* expected a digit, found something else */ - return 0; - - addr = tmp; - - if (bits < 0 || bits > 32) /* netmask must be between 0 and 32 */ - return 0; - - } - else { - /* Determine (i.e., "guess") netmask by counting the */ - /* number of trailing .0's; reduce #quads appropriately */ - /* (so that 192.168.0.0 is equivalent to 192.168.) */ - while (quads > 0 && ip_addr[quads - 1] == 0) - --quads; - - /* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */ - if (quads < 1) - return 0; - - /* every zero-byte counts as 8 zero-bits */ - bits = 8 * quads; - - if (bits != 32) /* no warning for fully qualified IP address */ - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld\n", - inet_ntoa(This->addr), bits); - } - - This->mask.s_addr = htonl(APR_INADDR_NONE << (32 - bits)); - - if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Warning: NetMask and IP-Addr disagree in %s/%ld\n", - inet_ntoa(This->addr), bits); - This->addr.s_addr &= This->mask.s_addr; - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " Set to %s/%ld\n", - inet_ntoa(This->addr), bits); - } - - if (*addr == '\0') { - This->matcher = proxy_match_ipaddr; - return 1; - } - else - return (*addr == '\0'); /* okay iff we've parsed the whole string */ -} - -/* Return TRUE if addr represents an IP address (or an IP network address) */ -static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r) -{ - int i; - int ip_addr[4]; - struct in_addr addr; - struct in_addr *ip_list; - char **ip_listptr; - const char *found; - const char *host = proxy_get_host_of_request(r); - - if (host == NULL) /* oops! */ - return 0; - - memset(&addr, '\0', sizeof addr); - memset(ip_addr, '\0', sizeof ip_addr); - - if (4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3])) { - for (addr.s_addr = 0, i = 0; i < 4; ++i) - addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i)); - - if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) { -#if DEBUGGING - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "1)IP-Match: %s[%s] <-> ", host, inet_ntoa(addr)); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "%s/", inet_ntoa(This->addr)); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "%s", inet_ntoa(This->mask)); -#endif - return 1; - } -#if DEBUGGING - else { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "1)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(addr)); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "%s/", inet_ntoa(This->addr)); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "%s", inet_ntoa(This->mask)); - } -#endif - } - else { - struct hostent the_host; - - memset(&the_host, '\0', sizeof the_host); - found = ap_proxy_host2addr(host, &the_host); - - if (found != NULL) { -#if DEBUGGING - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "2)IP-NoMatch: hostname=%s msg=%s", host, found); -#endif - return 0; - } - - if (the_host.h_name != NULL) - found = the_host.h_name; - else - found = host; - - /* Try to deal with multiple IP addr's for a host */ - for (ip_listptr = the_host.h_addr_list; *ip_listptr; ++ip_listptr) { - ip_list = (struct in_addr *) *ip_listptr; - if (This->addr.s_addr == (ip_list->s_addr & This->mask.s_addr)) { -#if DEBUGGING - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "3)IP-Match: %s[%s] <-> ", found, inet_ntoa(*ip_list)); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "%s/", inet_ntoa(This->addr)); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "%s", inet_ntoa(This->mask)); -#endif - return 1; - } -#if DEBUGGING - else { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "3)IP-NoMatch: %s[%s] <-> ", found, inet_ntoa(*ip_list)); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "%s/", inet_ntoa(This->addr)); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "%s", inet_ntoa(This->mask)); - } -#endif - } - } - - return 0; -} - -/* Return TRUE if addr represents a domain name */ -int ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p) -{ - char *addr = This->name; - int i; - - /* Domain name must start with a '.' */ - if (addr[0] != '.') - return 0; - - /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */ - for (i = 0; apr_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i) - continue; - -#if 0 - if (addr[i] == ':') { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "@@@@ handle optional port in proxy_is_domainname()"); - /* @@@@ handle optional port */ - } -#endif - - if (addr[i] != '\0') - return 0; - - /* Strip trailing dots */ - for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i) - addr[i] = '\0'; - - This->matcher = proxy_match_domainname; - return 1; -} - -/* Return TRUE if host "host" is in domain "domain" */ -static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r) -{ - const char *host = proxy_get_host_of_request(r); - int d_len = strlen(This->name), h_len; - - if (host == NULL) /* some error was logged already */ - return 0; - - h_len = strlen(host); - - /* @@@ do this within the setup? */ - /* Ignore trailing dots in domain comparison: */ - while (d_len > 0 && This->name[d_len - 1] == '.') - --d_len; - while (h_len > 0 && host[h_len - 1] == '.') - --h_len; - return h_len > d_len - && strncasecmp(&host[h_len - d_len], This->name, d_len) == 0; -} - -/* Create a copy of a "struct hostent" record; it was presumably returned - * from a call to gethostbyname() and lives in static storage. - * By creating a copy we can tuck it away for later use. - */ -static struct hostent * pduphostent(apr_pool_t *p, const struct hostent *hp) -{ - struct hostent *newent; - char **ptrs; - char **aliases; - struct in_addr *addrs; - int i = 0, j = 0; - - if (hp == NULL) - return NULL; - - /* Count number of alias entries */ - if (hp->h_aliases != NULL) - for (; hp->h_aliases[j] != NULL; ++j) - continue; - - /* Count number of in_addr entries */ - if (hp->h_addr_list != NULL) - for (; hp->h_addr_list[i] != NULL; ++i) - continue; - - /* Allocate hostent structure, alias ptrs, addr ptrs, addrs */ - newent = (struct hostent *) apr_palloc(p, sizeof(*hp)); - aliases = (char **) apr_palloc(p, (j+1) * sizeof(char*)); - ptrs = (char **) apr_palloc(p, (i+1) * sizeof(char*)); - addrs = (struct in_addr *) apr_palloc(p, (i+1) * sizeof(struct in_addr)); - - *newent = *hp; - newent->h_name = apr_pstrdup(p, hp->h_name); - newent->h_aliases = aliases; - newent->h_addr_list = (char**) ptrs; - - /* Copy Alias Names: */ - for (j = 0; hp->h_aliases[j] != NULL; ++j) { - aliases[j] = apr_pstrdup(p, hp->h_aliases[j]); - } - aliases[j] = NULL; - - /* Copy address entries */ - for (i = 0; hp->h_addr_list[i] != NULL; ++i) { - ptrs[i] = (char*) &addrs[i]; - addrs[i] = *(struct in_addr *) hp->h_addr_list[i]; - } - ptrs[i] = NULL; - - return newent; -} - -/* Return TRUE if addr represents a host name */ -int ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p) -{ - struct hostent host; - char *addr = This->name; - int i; - - /* Host names must not start with a '.' */ - if (addr[0] == '.') - return 0; - - /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */ - for (i = 0; apr_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i); - - if (addr[i] != '\0' || ap_proxy_host2addr(addr, &host) != NULL) - return 0; - - This->hostentry = pduphostent (p, &host); - - /* Strip trailing dots */ - for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i) - addr[i] = '\0'; - - This->matcher = proxy_match_hostname; - return 1; -} - -/* Return TRUE if host "host" is equal to host2 "host2" */ -static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r) -{ - char *host = This->name; - const char *host2 = proxy_get_host_of_request(r); - int h2_len; - int h1_len; - - if (host == NULL || host2 == NULL) - return 0; /* oops! */ - - h2_len = strlen(host2); - h1_len = strlen(host); - -#if 0 - unsigned long *ip_list; - - /* Try to deal with multiple IP addr's for a host */ - for (ip_list = *This->hostentry->h_addr_list; *ip_list != 0UL; ++ip_list) - if (*ip_list == ? ? ? ? ? ? ? ? ? ? ? ? ?) - return 1; -#endif - - /* Ignore trailing dots in host2 comparison: */ - while (h2_len > 0 && host2[h2_len - 1] == '.') - --h2_len; - while (h1_len > 0 && host[h1_len - 1] == '.') - --h1_len; - return h1_len == h2_len - && strncasecmp(host, host2, h1_len) == 0; -} - -/* Return TRUE if addr is to be matched as a word */ -int ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p) -{ - This->matcher = proxy_match_word; - return 1; -} - -/* Return TRUE if string "str2" occurs literally in "str1" */ -static int proxy_match_word(struct dirconn_entry *This, request_rec *r) -{ - const char *host = proxy_get_host_of_request(r); - return host != NULL && ap_strstr_c(host, This->name) != NULL; -} - -/* checks whether a host in uri_addr matches proxyblock */ -int ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, - apr_sockaddr_t *uri_addr) -{ - int j; - /* XXX FIXME: conf->noproxies->elts is part of an opaque structure */ - for (j = 0; j < conf->noproxies->nelts; j++) { - struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts; - struct apr_sockaddr_t *conf_addr = npent[j].addr; - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: checking remote machine [%s] against [%s]", uri_addr->hostname, npent[j].name); - if ((npent[j].name && ap_strstr_c(uri_addr->hostname, npent[j].name)) - || npent[j].name[0] == '*') { - ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server, - "proxy: connect to remote machine %s blocked: name %s matched", uri_addr->hostname, npent[j].name); - return HTTP_FORBIDDEN; - } - while (conf_addr) { - while (uri_addr) { - char *conf_ip; - char *uri_ip; - apr_sockaddr_ip_get(&conf_ip, conf_addr); - apr_sockaddr_ip_get(&uri_ip, uri_addr); - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server, - "proxy: ProxyBlock comparing %s and %s", conf_ip, uri_ip); - if (!apr_strnatcasecmp(conf_ip, uri_ip)) { - ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server, - "proxy: connect to remote machine %s blocked: IP %s matched", uri_addr->hostname, conf_ip); - return HTTP_FORBIDDEN; - } - uri_addr = uri_addr->next; - } - conf_addr = conf_addr->next; - } - } - return OK; -} - -/* set up the minimal filter set */ -int ap_proxy_pre_http_connection(conn_rec *c, request_rec *r) -{ - ap_add_input_filter("HTTP_IN", NULL, r, c); - ap_add_input_filter("CORE_IN", NULL, r, c); - ap_add_output_filter("CORE", NULL, r, c); - return OK; -} - -/* converts a series of buckets into a string */ -apr_status_t ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb, - char *buff, size_t bufflen, int *eos) -{ - apr_bucket *e; - apr_status_t rv; - apr_size_t readbytes = 0; /* line-at-a-time */ - char *pos = buff; - char *response; - int found = 0; - apr_size_t len; - - /* start with an empty string */ - buff[0] = 0; - *eos = 0; - - /* loop through each brigade */ - while (!found) { - - /* get brigade from network one line at a time */ - if (APR_SUCCESS != (rv = ap_get_brigade(c->input_filters, bb, AP_MODE_BLOCKING, &readbytes))) { - return rv; - } - - /* loop through each bucket */ - while (!found && !APR_BRIGADE_EMPTY(bb)) { - e = APR_BRIGADE_FIRST(bb); - if (APR_BUCKET_IS_EOS(e)) { - *eos = 1; - } - if (APR_SUCCESS != apr_bucket_read(e, (const char **)&response, &len, APR_BLOCK_READ)) { - return rv; - } - /* is string LF terminated? */ - if (memchr(response, APR_ASCII_LF, len)) { - found = 1; - } - /* concat strings until buff is full - then throw the data away */ - if (len > ((bufflen-1)-(pos-buff))) { - len = (bufflen-1)-(pos-buff); - } - if (len > 0) { - pos = apr_cpystrn(pos, response, len); - } - APR_BUCKET_REMOVE(e); - apr_bucket_destroy(e); - } - } - - return APR_SUCCESS; - -} - -/* remove other filters (like DECHUNK) from filter stack */ -void ap_proxy_reset_output_filters(conn_rec *c) -{ - ap_filter_t *f = c->output_filters; - - while (f) { - if (!strcasecmp(f->frec->name, "CORE") || - !strcasecmp(f->frec->name, "CONTENT_LENGTH") || - !strcasecmp(f->frec->name, "HTTP_HEADER")) { - f = f->next; - continue; - } - else { - ap_remove_output_filter(f); - f = f->next; - } - } -} - -#if defined WIN32 - -static DWORD tls_index; - -BOOL WINAPI DllMain (HINSTANCE dllhandle, DWORD reason, LPVOID reserved) -{ - LPVOID memptr; - - switch (reason) { - case DLL_PROCESS_ATTACH: - tls_index = TlsAlloc(); - case DLL_THREAD_ATTACH: /* intentional no break */ - TlsSetValue (tls_index, malloc (sizeof (struct per_thread_data))); - break; - case DLL_THREAD_DETACH: - memptr = TlsGetValue (tls_index); - if (memptr) { - free (memptr); - TlsSetValue (tls_index, 0); - } - break; - } - - return TRUE; -} - -#endif - -static struct per_thread_data *get_per_thread_data(void) -{ - return NULL; -} diff --git a/modules/ssl/.cvsignore b/modules/ssl/.cvsignore deleted file mode 100644 index 65f0cc30cf..0000000000 --- a/modules/ssl/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -.deps -.libs -*.la -modules.mk -Makefile -*.lo -*.slo -*.so -Debug -Release diff --git a/modules/ssl/README b/modules/ssl/README deleted file mode 100644 index ca9e225bf8..0000000000 --- a/modules/ssl/README +++ /dev/null @@ -1,163 +0,0 @@ - _ _ - _ __ ___ ___ __| | ___ ___| | - | '_ ` _ \ / _ \ / _` | / __/ __| | - | | | | | | (_) | (_| | \__ \__ \ | ``mod_ssl combines the flexibility of - |_| |_| |_|\___/ \__,_|___|___/___/_| Apache with the security of OpenSSL.'' - |_____| - mod_ssl ``Ralf Engelschall has released an - Apache Interface to OpenSSL excellent module that integrates - http://www.modssl.org/ Apache and SSLeay.'' - Version 2.8 -- Tim J. Hudson - - SYNOPSIS - - This Apache module provides strong cryptography for the Apache 1.3 webserver - via the Secure Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS - v1) protocols by the help of the SSL/TLS implementation library OpenSSL which - is based on SSLeay from Eric A. Young and Tim J. Hudson. The mod_ssl package - was created in April 1998 by Ralf S. Engelschall and was originally derived - from software developed by Ben Laurie for use in the Apache-SSL HTTP server - project. - - SOURCES - - Here is a short overview of the source files: - - Makefile.libdir ......... dummy for Apache config mechanism - Makefile.tmpl ........... Makefile template for Unix platform - Makefile.win32 .......... Makefile template for Win32 platform - libssl.module ........... stub called from the Apache config mechanism - libssl.version .......... file containing the mod_ssl version information - mod_ssl.c ............... main source file containing API structures - mod_ssl.h ............... common header file of mod_ssl - ssl_engine_compat.c ..... backward compatibility support - ssl_engine_config.c ..... module configuration handling - ssl_engine_dh.c ......... DSA/DH support - ssl_engine_ds.c ......... data structures - ssl_engine_ext.c ........ Extensions to other Apache parts - ssl_engine_init.c ....... module initialization - ssl_engine_io.c ......... I/O support - ssl_engine_kernel.c ..... SSL engine kernel - ssl_engine_log.c ........ logfile support - ssl_engine_mutex.c ...... mutual exclusion support - ssl_engine_pphrase.c .... pass-phrase handling - ssl_engine_rand.c ....... PRNG support - ssl_engine_vars.c ....... Variable Expansion support - ssl_expr.c .............. expression handling main source - ssl_expr.h .............. expression handling common header - ssl_expr_scan.c ......... expression scanner automaton (pre-generated) - ssl_expr_scan.l ......... expression scanner source - ssl_expr_parse.c ........ expression parser automaton (pre-generated) - ssl_expr_parse.h ........ expression parser header (pre-generated) - ssl_expr_parse.y ........ expression parser source - ssl_expr_eval.c ......... expression machine evaluation - ssl_scache.c ............ session cache abstraction layer - ssl_scache_dbm.c ........ session cache via DBM file - ssl_scache_shmcb.c ...... session cache via shared memory cyclic buffer - ssl_scache_shmht.c ...... session cache via shared memory hash table - ssl_util.c .............. utility functions - ssl_util_ssl.c .......... the OpenSSL companion source - ssl_util_ssl.h .......... the OpenSSL companion header - ssl_util_sdbm.c ......... the SDBM library source - ssl_util_sdbm.h ......... the SDBM library header - ssl_util_table.c ........ the hash table library source - ssl_util_table.h ........ the hash table library header - - The source files are written in clean ANSI C and pass the ``gcc -O -g - -ggdb3 -Wall -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes - -Wmissing-declarations -Wnested-externs -Winline'' compiler test - (assuming `gcc' is GCC 2.95.2 or newer) without any complains. When - you make changes or additions make sure the source still passes this - compiler test. - - FUNCTIONS - - Inside the source code you will be confronted with the following types of - functions which can be identified by their prefixes: - - ap_xxxx() ............... Apache API function - ssl_xxxx() .............. mod_ssl function - SSL_xxxx() .............. OpenSSL function (SSL library) - OpenSSL_xxxx() .......... OpenSSL function (SSL library) - X509_xxxx() ............. OpenSSL function (Crypto library) - PEM_xxxx() .............. OpenSSL function (Crypto library) - EVP_xxxx() .............. OpenSSL function (Crypto library) - RSA_xxxx() .............. OpenSSL function (Crypto library) - - DATA STRUCTURES - - Inside the source code you will be confronted with the following - data structures: - - ap_ctx .................. Apache EAPI Context - server_rec .............. Apache (Virtual) Server - conn_rec ................ Apache Connection - BUFF .................... Apache Connection Buffer - request_rec ............. Apache Request - SSLModConfig ............ mod_ssl (Global) Module Configuration - SSLSrvConfig ............ mod_ssl (Virtual) Server Configuration - SSLDirConfig ............ mod_ssl Directory Configuration - SSL_CTX ................. OpenSSL Context - SSL_METHOD .............. OpenSSL Protocol Method - SSL_CIPHER .............. OpenSSL Cipher - SSL_SESSION ............. OpenSSL Session - SSL ..................... OpenSSL Connection - BIO ..................... OpenSSL Connection Buffer - - For an overview how these are related and chained together have a look at the - page in README.dsov.{fig,ps}. It contains overview diagrams for those data - structures. It's designed for DIN A4 paper size, but you can easily generate - a smaller version inside XFig by specifing a magnification on the Export - panel. - - EXPERIMENTAL CODE - - Experimental code is always encapsulated as following: - - | #ifdef SSL_EXPERIMENTAL_xxxx - | ... - | #endif - - This way it is only compiled in when this define is enabled with - the APACI --enable-rule=SSL_EXPERIMENTAL option and as long as the - C pre-processor variable SSL_EXPERIMENTAL_xxxx_IGNORE is _NOT_ - defined (via CFLAGS). Or in other words: SSL_EXPERIMENTAL enables all - SSL_EXPERIMENTAL_xxxx variables, except if SSL_EXPERIMENTAL_xxxx_IGNORE - is already defined. Currently the following features are experimental: - - o SSL_EXPERIMENTAL_PERDIRCA - The ability to use SSLCACertificateFile and SSLCACertificatePath - in a per-directory context (.htaccess). This is provided by some nasty - reconfiguration hacks until OpenSSL has better support for this. It - should work on non-multithreaded platforms (all but Win32). - - o SSL_EXPERIMENTAL_PROXY - The ability to use various additional SSLProxyXXX directives in - oder to control extended client functionality in the HTTPS proxy - code. - - o SSL_EXPERIMENTAL_ENGINE - The ability to support the new forthcoming OpenSSL ENGINE stuff. - Until this development branch of OpenSSL is merged into the main - stream, you have to use openssl-engine-0.9.x.tar.gz for this. - mod_ssl automatically recognizes this OpenSSL variant and then can - activate external crypto devices through SSLCryptoDevice directive. - - VENDOR EXTENSIONS - - Inside the mod_ssl sources you can enable various EAPI vendor hooks - (`ap::mod_ssl::vendor::xxxx') by using the APACI --enable-rule=SSL_VENDOR - option. These hooks can be used to change or extend mod_ssl by a vendor - without patching the source code. Grep for `ap::mod_ssl::vendor::'. - Additionally vendors can add their own source code to files named - ssl_vendor.c, ssl_vendor_XXX.c, etc. The libssl.module script automatically - picks these up under configuration time and mod_ssl under run-time calls the - functions `void ssl_vendor_register(void)' and `void - ssl_vendor_unregister(void)' inside these objects to bootstrap them. - - An ssl_vendor.c should at least contain the following contents: - - | #include "mod_ssl.h" - | void ssl_vendor_register(void) { return; } - | void ssl_vendor_unregister(void) { return; } - diff --git a/modules/ssl/README.dsov.fig b/modules/ssl/README.dsov.fig deleted file mode 100644 index d8d03db247..0000000000 --- a/modules/ssl/README.dsov.fig +++ /dev/null @@ -1,346 +0,0 @@ -#FIG 3.2 -Landscape -Center -Metric -Letter -100.00 -Single --2 -1200 2 -0 32 #616561 -0 33 #b6b2b6 -0 34 #f7f3f7 -0 35 #cfcfcf -0 36 #ffffff -6 6345 2835 7155 3150 -6 6345 2970 7110 3150 -4 0 0 200 0 20 8 0.0000 4 120 585 6345 3105 "ssl_module")\001 --6 -4 0 0 200 0 20 8 0.0000 4 120 660 6345 2970 ap_ctx_get(...,\001 --6 -6 10800 2610 12240 3060 -4 0 0 200 0 20 8 0.0000 4 120 1170 10800 2745 ap_get_module_config(...\001 -4 0 0 200 0 20 8 0.0000 4 120 795 10800 2880 ->per_dir_config,\001 -4 0 0 200 0 20 8 0.0000 4 120 585 10800 3015 &ssl_module)\001 --6 -6 7920 4770 9135 4995 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 9135 4995 7920 4995 7920 4770 9135 4770 9135 4995 -4 0 0 100 0 18 12 0.0000 4 180 1065 8010 4950 request_rec\001 --6 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 6975 3330 7425 2520 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 7200 4230 9450 2520 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 7875 4905 7200 5220 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 6750 5130 6750 4545 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 6705 5445 7155 6120 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 7875 4815 7200 4590 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 9585 2565 11475 4230 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 10170 5130 11835 4545 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 7920 6075 9855 5400 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 9990 5445 10935 5625 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 10215 5310 10935 5310 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 11925 4590 11925 5085 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 9810 5490 9810 6840 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 9945 5445 10935 6030 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 8865 4725 10800 2565 -2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 - 675 6075 5850 6075 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 675 6525 675 6075 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 0 1.00 60.00 120.00 - 5850 6075 5850 6525 -2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 - 900 5625 5625 5625 -2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 - 1125 5175 5400 5175 -2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 - 1350 4725 5175 4725 -2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 - 1575 4275 4950 4275 -2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 - 1800 3825 4725 3825 -2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 - 2025 3375 4500 3375 -2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 - 2250 2925 4275 2925 -2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 - 2475 2475 4050 2475 -2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 - 2700 2025 3825 2025 -2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 - 2925 1575 3600 1575 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 900 6075 900 5625 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 1125 6525 1125 5175 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 1350 5175 1350 4725 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 1575 4725 1575 4275 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 1800 6525 1800 3825 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 2025 3825 2025 3375 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 2250 3375 2250 2925 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 2475 2925 2475 2475 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 0 1.00 60.00 120.00 - 5625 5625 5625 6075 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 0 1.00 60.00 120.00 - 5400 5175 5400 6525 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 0 1.00 60.00 120.00 - 5175 4725 5175 5175 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 0 1.00 60.00 120.00 - 4950 4275 4950 4725 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 0 1.00 60.00 120.00 - 4725 3825 4725 6525 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 0 1.00 60.00 120.00 - 4500 3375 4500 3825 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 0 1.00 60.00 120.00 - 4275 2925 4275 3375 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 0 1.00 60.00 120.00 - 4050 2475 4050 2925 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 2700 6525 2700 2025 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 0 1.00 60.00 120.00 - 3825 2025 3825 6525 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 0 1.00 60.00 120.00 - 3600 1575 3600 2025 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 2925 2025 2925 1575 -2 1 0 4 0 0 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 4.00 60.00 120.00 - 540 6525 6300 6525 -2 3 0 1 7 7 800 0 20 0.000 0 0 -1 0 0 9 - 675 6525 5850 6525 5850 6075 5625 6075 5625 5625 900 5625 - 900 6075 675 6075 675 6525 -2 3 0 1 34 34 700 0 20 0.000 0 0 -1 0 0 13 - 1125 6525 5355 6525 5400 5175 5175 5175 5175 4725 4950 4725 - 4950 4275 1575 4275 1575 4725 1350 4725 1350 5175 1125 5175 - 1125 6525 -2 3 0 1 35 35 500 0 20 0.000 0 0 -1 0 0 17 - 1800 6525 4725 6525 4725 3825 4500 3825 4500 3375 4275 3375 - 4275 2925 4050 2925 4050 2475 2475 2475 2475 2925 2250 2925 - 2250 3375 2025 3375 2025 3825 1800 3825 1800 6525 -2 3 0 1 33 33 400 0 20 0.000 0 0 -1 0 0 9 - 2700 6525 3825 6525 3825 2025 3600 2025 3600 1575 2925 1575 - 2925 2025 2700 2025 2700 6525 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 1 2 - 2 0 1.00 60.00 120.00 - 2 0 1.00 60.00 120.00 - 2700 6750 3825 6750 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 1 2 - 2 0 1.00 60.00 120.00 - 2 0 1.00 60.00 120.00 - 1125 7200 5400 7200 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 1 2 - 2 0 1.00 60.00 120.00 - 2 0 1.00 60.00 120.00 - 1800 6975 4725 6975 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 1 2 - 2 0 1.00 60.00 120.00 - 2 0 1.00 60.00 120.00 - 675 7425 5850 7425 -2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 - 675 6570 675 7650 -2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 - 1125 6570 1125 7650 -2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 - 1800 6570 1800 7650 -2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 - 2700 6570 2700 7650 -2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 - 3825 6570 3825 7650 -2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 - 4725 6570 4725 7650 -2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 - 5400 6570 5400 7650 -2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 - 5850 6570 5850 7650 -2 4 0 2 0 7 100 0 -1 0.000 0 0 20 0 0 5 - 12600 8550 450 8550 450 225 12600 225 12600 8550 -2 4 0 1 0 34 200 0 20 0.000 0 0 20 0 0 5 - 12600 1350 450 1350 450 225 12600 225 12600 1350 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 10170 2475 8775 2475 8775 2250 10170 2250 10170 2475 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 11925 2475 10575 2475 10575 2250 11925 2250 11925 2475 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 12375 4500 11430 4500 11430 4275 12375 4275 12375 4500 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 12375 5400 10980 5400 10980 5175 12375 5175 12375 5400 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 10170 5400 9675 5400 9675 5175 10170 5175 10170 5400 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 7875 6300 7200 6300 7200 6075 7875 6075 7875 6300 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 8190 2475 6750 2475 6750 2250 8190 2250 8190 2475 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 7605 3600 6300 3600 6300 3375 7605 3375 7605 3600 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 7335 4500 6300 4500 6300 4275 7335 4275 7335 4500 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 7200 5400 6300 5400 6300 5175 7200 5175 7200 5400 -2 1 0 6 7 7 600 0 -1 0.000 0 0 -1 0 0 2 - 9450 4500 6075 1935 -2 1 0 6 7 7 600 0 -1 0.000 0 0 4 0 0 2 - 9450 4500 12465 2205 -2 1 0 6 7 7 600 0 -1 0.000 0 0 4 0 0 2 - 9450 4500 9450 7785 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 9630 5310 7245 5310 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 11385 4365 7380 4365 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 12240 5805 10980 5805 10980 5580 12240 5580 12240 5805 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 12375 6210 10980 6210 10980 5985 12375 5985 12375 6210 -2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 11205 6885 9900 5445 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 12285 7155 10530 7155 10530 6930 12285 6930 12285 7155 -2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 - 10170 7155 9630 7155 9630 6930 10170 6930 10170 7155 -2 1 0 6 7 7 600 0 -1 0.000 0 0 4 0 0 2 - 12510 6435 9450 6435 -2 1 0 1 0 34 300 0 20 0.000 0 0 7 1 0 4 - 1 1 1.00 60.00 120.00 - 12375 4455 12510 4635 12510 6210 11970 6885 -2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 - 1 1 1.00 60.00 120.00 - 9850 5143 9175 4918 -3 1 0 1 34 34 800 0 20 0.000 0 0 0 41 - 7380 1710 6390 2115 5535 2115 6075 3015 5670 3465 6165 3915 - 5715 4410 6030 5040 6030 5310 6480 5715 6390 6255 6975 6300 - 7065 6975 7965 6750 8100 7560 8955 7290 9360 7740 9720 7560 - 10755 8145 12060 8280 12375 7650 12420 7200 12510 7065 12330 6660 - 12510 6390 12420 5940 12375 5400 12510 5220 12510 4725 12600 4275 - 12375 3645 12105 3240 12150 2745 12375 2700 12330 1980 11790 1575 - 11250 1935 10125 1485 8955 2070 7785 1620 7695 1575 - 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 - 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 - 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 - 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 - 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 - 1.000 -4 0 0 100 0 0 12 0.0000 4 180 1440 10575 675 Ralf S. Engelschall\001 -4 0 0 100 0 18 20 0.0000 4 270 3840 4275 675 Apache+mod_ssl+OpenSSL\001 -4 0 0 100 0 0 10 0.0000 4 135 1320 10575 855 rse@engelschall.com\001 -4 0 0 100 0 0 10 0.0000 4 135 1410 10575 1035 www.engelschall.com\001 -4 0 0 100 0 0 12 0.0000 4 135 870 900 675 Version 1.3\001 -4 0 0 100 0 0 12 0.0000 4 180 1035 900 855 12-Apr-1999\001 -4 0 0 200 0 20 8 0.0000 4 60 390 6210 4680 ->server\001 -4 0 0 200 0 20 8 0.0000 4 120 855 8280 6120 ap_ctx_get(...,"ssl")\001 -4 0 0 200 0 20 8 0.0000 4 120 1170 7740 2700 ap_get_module_config(...\001 -4 0 0 200 0 20 8 0.0000 4 120 810 7740 2835 ->module_config,\001 -4 0 0 200 0 20 8 0.0000 4 120 585 7740 2970 &ssl_module)\001 -4 0 0 100 0 18 20 0.0000 4 270 1200 9000 8100 Chaining\001 -4 0 0 100 0 18 20 0.0000 4 210 1095 2745 8100 Lifetime\001 -4 0 0 100 0 18 12 0.0000 4 180 1215 810 6255 ap_global_ctx\001 -4 0 0 100 0 18 12 0.0000 4 180 1305 990 5805 SSLModConfig\001 -4 0 0 100 0 18 12 0.0000 4 180 840 4050 4455 SSL_CTX\001 -4 0 0 100 0 18 12 0.0000 4 150 975 4455 5355 server_rec\001 -4 0 0 100 0 18 12 0.0000 4 180 1260 3870 4905 SSLSrvConfig\001 -4 0 0 100 0 18 12 0.0000 4 135 480 1845 4005 BUFF\001 -4 0 0 100 0 18 12 0.0000 4 150 810 2070 3555 conn_rec\001 -4 0 0 100 0 18 12 0.0000 4 135 345 2295 3105 BIO\001 -4 0 0 100 0 18 12 0.0000 4 135 375 2565 2655 SSL\001 -4 0 0 100 0 18 12 0.0000 4 180 1185 3645 1620 SSLDirConfig\001 -4 0 0 100 0 18 12 0.0000 4 180 1065 3915 2070 request_rec\001 -4 0 0 200 0 0 8 0.0000 4 120 1440 900 7560 Startup, Runtime, Shutdown\001 -4 0 0 200 0 0 8 0.0000 4 105 975 1350 7335 Configuration Time\001 -4 0 0 200 0 0 8 0.0000 4 90 1050 2025 7110 Connection Duration\001 -4 0 0 200 0 0 8 0.0000 4 120 885 2835 6885 Request Duration\001 -4 0 0 200 0 18 20 0.0000 4 195 90 6345 6795 t\001 -4 0 0 200 0 20 8 0.0000 4 90 345 7110 5985 ->client\001 -4 0 0 100 0 18 12 0.0000 4 180 1305 6795 2430 SSLModConfig\001 -4 0 0 100 0 18 12 0.0000 4 180 1260 8865 2430 SSLSrvConfig\001 -4 0 0 100 0 18 12 0.0000 4 180 1215 6345 3555 ap_global_ctx\001 -4 0 0 100 0 18 12 0.0000 4 150 975 6345 4455 server_rec\001 -4 0 0 100 0 18 12 0.0000 4 150 810 6345 5355 conn_rec\001 -4 0 0 100 0 18 12 0.0000 4 135 375 9720 5355 SSL\001 -4 0 0 100 0 18 12 0.0000 4 180 1185 10665 2430 SSLDirConfig\001 -4 0 0 100 0 18 12 0.0000 4 135 480 7290 6255 BUFF\001 -4 0 0 100 0 18 12 0.0000 4 180 1305 11025 5355 SSL_METHOD\001 -4 0 0 100 0 18 12 0.0000 4 180 840 11475 4455 SSL_CTX\001 -4 0 0 100 0 18 24 0.0000 4 285 4365 3915 1080 Data Structure Overview\001 -4 0 0 200 0 20 8 0.0000 4 90 615 7065 5085 ->connection\001 -4 0 0 200 0 20 8 0.0000 4 60 390 7065 4770 ->server\001 -4 0 0 200 0 20 8 0.0000 4 120 960 8010 5445 SSL_get_app_data()\001 -4 0 0 200 0 20 8 0.0000 4 120 510 10530 4050 ->pSSLCtx\001 -4 0 0 200 0 20 8 0.0000 4 120 1215 7875 4275 SSL_CTX_get_app_data()\001 -4 0 0 200 0 20 8 0.0000 4 120 1155 10305 5535 SSL_get_current_cipher()\001 -4 0 0 100 0 18 12 0.0000 4 180 1170 11025 5760 SSL_CIPHER\001 -4 0 0 100 0 18 12 0.0000 4 180 1350 10980 6165 SSL_SESSION\001 -4 0 0 200 0 20 8 0.0000 4 120 840 10440 5940 SSL_get_session()\001 -4 0 0 100 0 18 12 0.0000 4 180 1665 10575 7110 X509_STORE_CTX\001 -4 0 0 100 0 18 12 0.0000 4 135 345 9720 7110 BIO\001 -4 0 0 200 0 20 8 0.0000 4 120 840 9540 7335 SSL_get_{r,w}bio()\001 -4 0 0 100 0 18 20 0.0000 4 270 1170 8730 3465 mod_ssl\001 -4 0 0 100 0 18 20 0.0000 4 270 1050 8145 6750 Apache\001 -4 0 0 200 0 20 8 0.0000 4 120 945 10125 4680 SSL_get_SSL_CTX()\001 -4 0 0 200 0 20 8 0.0000 4 120 1170 10350 5175 SSL_get_SSL_METHOD()\001 -4 0 0 200 0 20 8 0.0000 4 90 465 11745 4770 ->method\001 -4 0 0 200 0 20 8 0.0000 4 120 1665 9945 6480 X509_STORE_CTX_get_app_data()\001 -4 0 0 200 0 20 8 0.0000 4 120 1215 10980 6705 SSL_CTX_get_cert_store()\001 -4 0 0 200 0 20 8 0.0000 4 120 1020 8280 5130 SSL_get_app_data2()\001 -4 0 0 100 0 18 20 0.0000 4 270 1290 10710 7605 OpenSSL\001 -4 0 0 100 0 18 12 0.0000 4 180 720 10710 7785 [Crypto]\001 -4 0 0 100 0 18 20 0.0000 4 270 1290 10935 3645 OpenSSL\001 -4 0 0 100 0 18 12 0.0000 4 180 495 10935 3825 [SSL]\001 diff --git a/modules/ssl/README.dsov.ps b/modules/ssl/README.dsov.ps deleted file mode 100644 index def19dbecf..0000000000 --- a/modules/ssl/README.dsov.ps +++ /dev/null @@ -1,1138 +0,0 @@ -%!PS-Adobe-2.0 -%%Title: README.dsov.ps -%%Creator: fig2dev Version 3.2 Patchlevel 1 -%%CreationDate: Mon Apr 12 17:09:11 1999 -%%For: rse@en1.engelschall.com (Ralf S. Engelschall) -%%Orientation: Landscape -%%BoundingBox: 59 37 553 755 -%%Pages: 1 -%%BeginSetup -%%IncludeFeature: *PageSize Letter -%%EndSetup -%%Magnification: 0.9340 -%%EndComments -/$F2psDict 200 dict def -$F2psDict begin -$F2psDict /mtrx matrix put -/col-1 {0 setgray} bind def -/col0 {0.000 0.000 0.000 srgb} bind def -/col1 {0.000 0.000 1.000 srgb} bind def -/col2 {0.000 1.000 0.000 srgb} bind def -/col3 {0.000 1.000 1.000 srgb} bind def -/col4 {1.000 0.000 0.000 srgb} bind def -/col5 {1.000 0.000 1.000 srgb} bind def -/col6 {1.000 1.000 0.000 srgb} bind def -/col7 {1.000 1.000 1.000 srgb} bind def -/col8 {0.000 0.000 0.560 srgb} bind def -/col9 {0.000 0.000 0.690 srgb} bind def -/col10 {0.000 0.000 0.820 srgb} bind def -/col11 {0.530 0.810 1.000 srgb} bind def -/col12 {0.000 0.560 0.000 srgb} bind def -/col13 {0.000 0.690 0.000 srgb} bind def -/col14 {0.000 0.820 0.000 srgb} bind def -/col15 {0.000 0.560 0.560 srgb} bind def -/col16 {0.000 0.690 0.690 srgb} bind def -/col17 {0.000 0.820 0.820 srgb} bind def -/col18 {0.560 0.000 0.000 srgb} bind def -/col19 {0.690 0.000 0.000 srgb} bind def -/col20 {0.820 0.000 0.000 srgb} bind def -/col21 {0.560 0.000 0.560 srgb} bind def -/col22 {0.690 0.000 0.690 srgb} bind def -/col23 {0.820 0.000 0.820 srgb} bind def -/col24 {0.500 0.190 0.000 srgb} bind def -/col25 {0.630 0.250 0.000 srgb} bind def -/col26 {0.750 0.380 0.000 srgb} bind def -/col27 {1.000 0.500 0.500 srgb} bind def -/col28 {1.000 0.630 0.630 srgb} bind def -/col29 {1.000 0.750 0.750 srgb} bind def -/col30 {1.000 0.880 0.880 srgb} bind def -/col31 {1.000 0.840 0.000 srgb} bind def -/col32 {0.380 0.396 0.380 srgb} bind def -/col33 {0.714 0.698 0.714 srgb} bind def -/col34 {0.969 0.953 0.969 srgb} bind def -/col35 {0.812 0.812 0.812 srgb} bind def -/col36 {1.000 1.000 1.000 srgb} bind def - -end -save -48.0 12.0 translate - 90 rotate -1 -1 scale - -/cp {closepath} bind def -/ef {eofill} bind def -/gr {grestore} bind def -/gs {gsave} bind def -/sa {save} bind def -/rs {restore} bind def -/l {lineto} bind def -/m {moveto} bind def -/rm {rmoveto} bind def -/n {newpath} bind def -/s {stroke} bind def -/sh {show} bind def -/slc {setlinecap} bind def -/slj {setlinejoin} bind def -/slw {setlinewidth} bind def -/srgb {setrgbcolor} bind def -/rot {rotate} bind def -/sc {scale} bind def -/sd {setdash} bind def -/ff {findfont} bind def -/sf {setfont} bind def -/scf {scalefont} bind def -/sw {stringwidth} bind def -/tr {translate} bind def -/tnt {dup dup currentrgbcolor - 4 -2 roll dup 1 exch sub 3 -1 roll mul add - 4 -2 roll dup 1 exch sub 3 -1 roll mul add - 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} - bind def -/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul - 4 -2 roll mul srgb} bind def -/reencdict 12 dict def /ReEncode { reencdict begin -/newcodesandnames exch def /newfontname exch def /basefontname exch def -/basefontdict basefontname findfont def /newfont basefontdict maxlength dict def -basefontdict { exch dup /FID ne { dup /Encoding eq -{ exch dup length array copy newfont 3 1 roll put } -{ exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall -newfont /FontName newfontname put newcodesandnames aload pop -128 1 255 { newfont /Encoding get exch /.notdef put } for -newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat -newfontname newfont definefont pop end } def -/isovec [ -8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde -8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis -8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron -8#220 /dotlessi 8#230 /oe 8#231 /OE -8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling -8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis -8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot -8#255 /endash 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus -8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph -8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine -8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf -8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute -8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring -8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute -8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute -8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve -8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply -8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex -8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave -8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring -8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute -8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute -8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve -8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide -8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex -8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis] def -/Times-Roman /Times-Roman-iso isovec ReEncode -/Helvetica-Bold /Helvetica-Bold-iso isovec ReEncode -/Helvetica-Narrow /Helvetica-Narrow-iso isovec ReEncode -/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def -/$F2psEnd {$F2psEnteredState restore end} def -%%EndProlog - -$F2psBegin -10 setmiterlimit -n -1000 9572 m -1000 -1000 l 13622 -1000 l 13622 9572 l cp clip - 0.05883 0.05883 sc -%%Page: 1 1 -% Polyline -7.500 slw -n 6413 2048 m 6380 2054 l 6348 2061 l 6315 2067 l 6283 2073 l 6250 2079 l - 6217 2084 l 6185 2090 l 6152 2095 l 6120 2101 l 6088 2107 l - 6057 2113 l 6027 2120 l 5998 2126 l 5970 2134 l 5943 2141 l - 5918 2149 l 5894 2158 l 5873 2167 l 5853 2177 l 5835 2187 l - 5819 2198 l 5805 2210 l 5793 2222 l 5782 2235 l 5774 2250 l - 5768 2265 l 5763 2281 l 5760 2299 l 5759 2318 l 5759 2339 l - 5761 2360 l 5764 2383 l 5768 2408 l 5774 2433 l 5780 2460 l - 5788 2488 l 5797 2516 l 5806 2546 l 5815 2575 l 5825 2606 l - 5836 2636 l 5846 2666 l 5856 2696 l 5866 2726 l 5875 2755 l - 5884 2784 l 5892 2812 l 5899 2839 l 5905 2866 l 5910 2891 l - 5915 2916 l 5918 2940 l 5919 2968 l 5920 2995 l 5919 3022 l - 5916 3048 l 5912 3075 l 5908 3101 l 5902 3127 l 5895 3153 l - 5887 3179 l 5880 3205 l 5871 3230 l 5863 3254 l 5855 3278 l - 5848 3302 l 5841 3324 l 5834 3346 l 5829 3367 l 5824 3388 l - 5821 3408 l 5819 3427 l 5819 3446 l 5820 3465 l 5823 3484 l - 5827 3503 l 5833 3522 l 5840 3542 l 5848 3562 l 5858 3582 l - 5868 3603 l 5880 3625 l 5891 3647 l 5904 3669 l 5916 3691 l - 5929 3713 l 5941 3736 l 5953 3758 l 5964 3779 l 5974 3801 l - 5983 3822 l 5991 3843 l 5997 3863 l 6002 3883 l 6006 3903 l - 6008 3923 l 6008 3942 l 6006 3962 l 6003 3983 l 5998 4004 l - 5992 4025 l 5985 4048 l 5977 4070 l 5968 4094 l 5958 4118 l - 5947 4142 l 5936 4167 l 5925 4192 l 5913 4216 l 5902 4241 l - 5892 4266 l 5882 4291 l 5872 4315 l 5864 4339 l 5857 4362 l - 5851 4386 l 5846 4409 l 5843 4433 l 5840 4456 l 5840 4480 l - 5840 4505 l 5842 4530 l 5845 4556 l 5849 4582 l 5854 4609 l - 5860 4636 l 5867 4664 l 5875 4692 l 5883 4720 l 5892 4747 l - 5901 4774 l 5910 4801 l 5920 4827 l 5929 4852 l 5938 4875 l - 5947 4898 l 5955 4920 l 5963 4941 l 5971 4961 l 5978 4980 l - 5985 5002 l 5992 5024 l 5999 5046 l 6005 5067 l 6010 5088 l - 6016 5109 l 6022 5129 l 6027 5150 l 6033 5170 l 6039 5190 l - 6045 5209 l 6052 5228 l 6059 5246 l 6067 5264 l 6075 5281 l - 6084 5298 l 6094 5315 l 6105 5333 l 6115 5347 l 6125 5361 l - 6137 5376 l 6149 5392 l 6162 5408 l 6176 5425 l 6191 5443 l - 6206 5461 l 6221 5480 l 6237 5499 l 6253 5519 l 6269 5539 l - 6284 5559 l 6299 5579 l 6313 5599 l 6327 5619 l 6340 5639 l - 6352 5659 l 6363 5679 l 6373 5698 l 6382 5718 l 6390 5738 l - 6398 5759 l 6404 5782 l 6410 5805 l 6415 5828 l 6420 5852 l - 6424 5877 l 6428 5902 l 6431 5927 l 6435 5952 l 6438 5977 l - 6442 6001 l 6446 6025 l 6450 6048 l 6455 6069 l 6461 6090 l - 6467 6109 l 6474 6127 l 6483 6143 l 6492 6159 l 6503 6173 l - 6515 6185 l 6528 6197 l 6543 6209 l 6560 6220 l 6578 6230 l - 6598 6240 l 6619 6250 l 6641 6260 l 6663 6270 l 6687 6281 l - 6710 6291 l 6733 6302 l 6757 6312 l 6779 6324 l 6801 6335 l - 6821 6348 l 6841 6361 l 6859 6374 l 6876 6389 l 6893 6405 l - 6906 6421 l 6919 6437 l 6932 6455 l 6944 6475 l 6955 6495 l - 6967 6516 l 6979 6538 l 6991 6561 l 7003 6584 l 7015 6608 l - 7027 6631 l 7040 6654 l 7053 6677 l 7067 6699 l 7081 6720 l - 7096 6739 l 7111 6758 l 7127 6774 l 7144 6789 l 7161 6803 l - 7180 6815 l 7200 6825 l 7220 6833 l 7240 6840 l 7263 6845 l - 7286 6850 l 7311 6854 l 7338 6857 l 7365 6859 l 7394 6861 l - 7424 6862 l 7454 6864 l 7485 6865 l 7516 6866 l 7547 6867 l - 7578 6868 l 7609 6870 l 7639 6872 l 7668 6875 l 7696 6879 l - 7723 6883 l 7748 6889 l 7773 6895 l 7795 6903 l 7817 6912 l - 7838 6923 l 7857 6934 l 7875 6948 l 7892 6963 l 7909 6980 l - 7926 6998 l 7941 7017 l 7957 7038 l 7972 7060 l 7987 7083 l - 8002 7106 l 8017 7130 l 8031 7154 l 8046 7178 l 8061 7202 l - 8075 7225 l 8090 7247 l 8105 7269 l 8120 7289 l 8135 7308 l - 8151 7326 l 8167 7342 l 8184 7356 l 8202 7369 l 8220 7380 l - 8239 7390 l 8260 7397 l 8282 7404 l 8305 7409 l 8330 7413 l - 8356 7416 l 8383 7418 l 8412 7420 l 8441 7420 l 8471 7419 l - 8502 7418 l 8534 7417 l 8565 7415 l 8597 7413 l 8629 7411 l - 8660 7409 l 8690 7407 l 8720 7405 l 8749 7404 l 8777 7404 l - 8804 7404 l 8830 7405 l 8856 7407 l 8880 7410 l 8906 7414 l - 8931 7420 l 8956 7427 l 8981 7435 l 9005 7444 l 9029 7455 l - 9053 7466 l 9077 7478 l 9100 7491 l 9123 7504 l 9146 7517 l - 9168 7531 l 9190 7544 l 9210 7557 l 9230 7570 l 9250 7582 l - 9268 7593 l 9286 7604 l 9304 7613 l 9320 7621 l 9336 7629 l - 9353 7635 l 9370 7641 l 9388 7645 l 9406 7648 l 9425 7650 l - 9444 7652 l 9464 7653 l 9485 7653 l 9508 7653 l 9531 7653 l - 9555 7653 l 9579 7653 l 9605 7654 l 9631 7655 l 9658 7656 l - 9685 7659 l 9713 7662 l 9742 7666 l 9771 7672 l 9801 7679 l - 9833 7688 l 9853 7694 l 9874 7700 l 9895 7708 l 9918 7716 l - 9941 7725 l 9966 7734 l 9991 7745 l 10017 7755 l 10045 7767 l - 10073 7779 l 10102 7791 l 10132 7804 l 10163 7818 l 10194 7831 l - 10227 7845 l 10259 7860 l 10293 7874 l 10326 7889 l 10360 7903 l - 10394 7918 l 10429 7932 l 10463 7947 l 10497 7961 l 10531 7974 l - 10565 7988 l 10599 8001 l 10633 8013 l 10667 8025 l 10700 8037 l - 10733 8049 l 10767 8059 l 10800 8070 l 10834 8080 l 10868 8090 l - 10902 8099 l 10937 8108 l 10973 8117 l 11009 8125 l 11045 8133 l - 11083 8141 l 11120 8148 l 11158 8155 l 11197 8161 l 11236 8167 l - 11275 8172 l 11313 8177 l 11352 8181 l 11391 8184 l 11429 8187 l - 11467 8190 l 11504 8191 l 11540 8192 l 11576 8192 l 11610 8192 l - 11644 8191 l 11676 8189 l 11707 8187 l 11738 8184 l 11767 8180 l - 11794 8176 l 11821 8171 l 11847 8165 l 11871 8159 l 11895 8153 l - 11923 8143 l 11950 8133 l 11976 8122 l 12001 8109 l 12025 8096 l - 12048 8081 l 12071 8065 l 12092 8048 l 12113 8031 l 12133 8012 l - 12153 7992 l 12171 7972 l 12188 7951 l 12205 7930 l 12220 7909 l - 12235 7887 l 12248 7865 l 12260 7843 l 12272 7822 l 12282 7800 l - 12292 7779 l 12301 7759 l 12309 7739 l 12316 7719 l 12323 7699 l - 12330 7680 l 12338 7655 l 12345 7631 l 12352 7607 l 12359 7582 l - 12365 7558 l 12371 7533 l 12377 7508 l 12382 7484 l 12388 7460 l - 12392 7436 l 12397 7414 l 12401 7391 l 12405 7370 l 12409 7350 l - 12412 7331 l 12415 7313 l 12418 7297 l 12421 7281 l 12424 7266 l - 12428 7253 l 12432 7234 l 12437 7216 l 12442 7199 l 12446 7183 l - 12451 7166 l 12456 7150 l 12460 7134 l 12463 7117 l 12466 7101 l - 12468 7086 l 12469 7070 l 12469 7054 l 12467 7037 l 12465 7020 l - 12462 7006 l 12459 6991 l 12455 6975 l 12450 6958 l 12445 6940 l - 12440 6921 l 12434 6901 l 12428 6880 l 12422 6859 l 12416 6838 l - 12411 6817 l 12406 6796 l 12401 6776 l 12397 6756 l 12394 6736 l - 12392 6718 l 12390 6700 l 12390 6683 l 12390 6665 l 12392 6649 l - 12394 6631 l 12397 6614 l 12401 6597 l 12406 6579 l 12411 6561 l - 12416 6542 l 12422 6524 l 12428 6505 l 12434 6487 l 12440 6468 l - 12445 6450 l 12450 6432 l 12455 6414 l 12459 6396 l 12462 6378 l - 12465 6360 l 12467 6343 l 12468 6326 l 12469 6308 l 12469 6289 l - 12468 6269 l 12468 6249 l 12466 6227 l 12464 6205 l 12462 6182 l - 12460 6159 l 12457 6135 l 12454 6111 l 12451 6087 l 12447 6063 l - 12444 6040 l 12441 6016 l 12437 5993 l 12434 5970 l 12431 5948 l - 12428 5925 l 12424 5902 l 12421 5879 l 12419 5855 l 12416 5831 l - 12413 5806 l 12411 5781 l 12408 5755 l 12406 5729 l 12404 5702 l - 12403 5676 l 12401 5651 l 12400 5625 l 12400 5601 l 12399 5578 l - 12399 5555 l 12400 5534 l 12401 5514 l 12402 5495 l 12403 5477 l - 12405 5460 l 12408 5440 l 12411 5421 l 12416 5402 l 12420 5384 l - 12426 5365 l 12431 5347 l 12437 5329 l 12444 5311 l 12450 5293 l - 12456 5275 l 12462 5258 l 12468 5240 l 12474 5222 l 12479 5205 l - 12483 5186 l 12488 5168 l 12490 5152 l 12493 5135 l 12496 5117 l - 12498 5099 l 12500 5079 l 12502 5058 l 12504 5036 l 12506 5014 l - 12507 4990 l 12509 4966 l 12510 4942 l 12512 4918 l 12513 4893 l - 12515 4869 l 12516 4845 l 12518 4822 l 12520 4799 l 12521 4776 l - 12523 4754 l 12525 4733 l 12527 4713 l 12529 4693 l 12531 4673 l - 12534 4653 l 12536 4632 l 12539 4610 l 12541 4588 l 12543 4566 l - 12546 4543 l 12548 4520 l 12550 4497 l 12552 4473 l 12553 4450 l - 12554 4426 l 12555 4403 l 12555 4380 l 12555 4357 l 12555 4334 l - 12554 4312 l 12552 4290 l 12550 4267 l 12548 4245 l 12545 4224 l - 12541 4203 l 12537 4181 l 12533 4159 l 12528 4136 l 12523 4112 l - 12517 4088 l 12510 4064 l 12503 4038 l 12496 4013 l 12488 3987 l - 12479 3961 l 12471 3935 l 12462 3909 l 12452 3884 l 12443 3859 l - 12434 3835 l 12424 3811 l 12415 3788 l 12405 3766 l 12396 3744 l - 12386 3723 l 12377 3702 l 12368 3683 l 12357 3661 l 12347 3640 l - 12336 3619 l 12325 3598 l 12314 3576 l 12303 3555 l 12291 3533 l - 12280 3511 l 12269 3489 l 12257 3467 l 12246 3446 l 12235 3424 l - 12225 3402 l 12215 3381 l 12206 3360 l 12197 3340 l 12189 3320 l - 12181 3301 l 12174 3281 l 12168 3262 l 12162 3244 l 12158 3225 l - 12153 3204 l 12149 3183 l 12145 3162 l 12142 3139 l 12140 3117 l - 12138 3094 l 12137 3071 l 12137 3047 l 12138 3024 l 12139 3001 l - 12141 2978 l 12143 2956 l 12146 2935 l 12150 2915 l 12154 2896 l - 12158 2879 l 12163 2862 l 12168 2847 l 12174 2833 l 12180 2820 l - 12188 2805 l 12197 2792 l 12206 2779 l 12216 2766 l 12227 2754 l - 12238 2742 l 12249 2730 l 12260 2717 l 12272 2704 l 12282 2691 l - 12292 2676 l 12302 2661 l 12310 2645 l 12318 2627 l 12324 2608 l - 12330 2588 l 12334 2571 l 12336 2553 l 12339 2534 l 12341 2513 l - 12342 2491 l 12343 2467 l 12343 2442 l 12342 2416 l 12340 2389 l - 12338 2360 l 12335 2332 l 12331 2303 l 12326 2273 l 12320 2244 l - 12314 2215 l 12307 2187 l 12299 2159 l 12290 2132 l 12280 2106 l - 12270 2081 l 12259 2056 l 12248 2033 l 12236 2011 l 12224 1990 l - 12210 1970 l 12196 1949 l 12181 1929 l 12164 1910 l 12147 1890 l - 12129 1871 l 12110 1853 l 12090 1835 l 12070 1818 l 12049 1802 l - 12027 1787 l 12005 1773 l 11983 1761 l 11961 1749 l 11939 1739 l - 11917 1730 l 11895 1722 l 11874 1716 l 11852 1710 l 11831 1707 l - 11811 1704 l 11790 1703 l 11769 1702 l 11748 1703 l 11727 1705 l - 11706 1708 l 11683 1711 l 11660 1716 l 11636 1721 l 11612 1727 l - 11587 1733 l 11560 1740 l 11534 1747 l 11506 1754 l 11479 1761 l - 11450 1768 l 11422 1774 l 11393 1780 l 11364 1786 l 11334 1791 l - 11305 1795 l 11275 1798 l 11245 1800 l 11215 1801 l 11184 1801 l - 11153 1800 l 11128 1798 l 11104 1796 l 11078 1793 l 11052 1790 l - 11025 1785 l 10997 1781 l 10968 1776 l 10939 1770 l 10908 1764 l - 10877 1758 l 10844 1751 l 10811 1744 l 10778 1737 l 10743 1730 l - 10708 1722 l 10673 1715 l 10637 1708 l 10601 1701 l 10565 1695 l - 10530 1688 l 10494 1682 l 10458 1677 l 10422 1672 l 10387 1668 l - 10352 1664 l 10318 1661 l 10284 1658 l 10250 1657 l 10216 1656 l - 10183 1655 l 10150 1656 l 10118 1658 l 10087 1660 l 10055 1663 l - 10024 1666 l 9992 1671 l 9960 1676 l 9927 1682 l 9894 1688 l - 9861 1695 l 9827 1703 l 9792 1711 l 9757 1720 l 9721 1729 l - 9685 1738 l 9649 1748 l 9613 1757 l 9576 1767 l 9539 1778 l - 9502 1788 l 9465 1798 l 9429 1807 l 9392 1817 l 9356 1826 l - 9320 1835 l 9285 1844 l 9250 1852 l 9216 1860 l 9182 1867 l - 9148 1873 l 9115 1879 l 9082 1884 l 9050 1889 l 9018 1892 l - 8987 1895 l 8955 1898 l 8919 1899 l 8883 1900 l 8847 1899 l - 8811 1898 l 8774 1896 l 8737 1893 l 8699 1889 l 8661 1884 l - 8623 1878 l 8585 1872 l 8546 1865 l 8508 1857 l 8470 1849 l - 8432 1840 l 8395 1830 l 8358 1821 l 8322 1811 l 8287 1801 l - 8254 1790 l 8221 1780 l 8189 1770 l 8159 1760 l 8130 1750 l - 8102 1740 l 8076 1730 l 8051 1721 l 8028 1712 l 8006 1703 l - 7985 1695 l 7965 1688 l 7931 1674 l 7899 1662 l 7871 1650 l - 7844 1640 l 7820 1631 l 7798 1623 l 7778 1617 l 7760 1611 l - 7743 1607 l 7728 1603 l 7715 1601 l 7702 1600 l 7691 1600 l - 7680 1601 l 7669 1603 l 7658 1605 l 7648 1607 l 7638 1610 l - 7627 1613 l 7615 1617 l 7601 1621 l 7587 1626 l 7571 1632 l - 7554 1638 l 7536 1645 l 7517 1653 l 7496 1661 l 7474 1670 l - 7452 1679 l 7428 1689 l 7403 1699 l 7378 1709 l 7352 1720 l - 7325 1731 l 7297 1743 l 7268 1755 l 7247 1763 l 7226 1772 l - 7204 1781 l 7182 1790 l 7158 1800 l 7133 1810 l 7108 1820 l - 7081 1831 l 7053 1842 l 7025 1853 l 6996 1864 l 6966 1875 l - 6935 1886 l 6904 1898 l 6873 1909 l 6841 1921 l 6809 1932 l - 6776 1943 l 6744 1954 l 6712 1964 l 6680 1974 l 6649 1984 l - 6618 1994 l 6587 2003 l 6557 2011 l 6527 2019 l 6498 2027 l - 6469 2034 l 6441 2041 l cp gs col34 1.00 shd ef gr gs col34 s gr -% Polyline -n 675 6525 m 5850 6525 l 5850 6075 l 5625 6075 l 5625 5625 l 900 5625 l - 900 6075 l 675 6075 l cp gs col7 1.00 shd ef gr gs col7 s gr -% Polyline -n 1125 6525 m 5355 6525 l 5400 5175 l 5175 5175 l 5175 4725 l 4950 4725 l - 4950 4275 l 1575 4275 l 1575 4725 l 1350 4725 l 1350 5175 l - 1125 5175 l cp gs col34 1.00 shd ef gr gs col34 s gr -% Polyline -75.000 slw -n 9450 4500 m 12465 2205 l gs col7 s gr -% Polyline -n 9450 4500 m 9450 7785 l gs col7 s gr -% Polyline -n 9450 4500 m 6075 1935 l gs col7 s gr -% Polyline -n 12510 6435 m 9450 6435 l gs col7 s gr -% Polyline -7.500 slw -n 1800 6525 m 4725 6525 l 4725 3825 l 4500 3825 l 4500 3375 l 4275 3375 l - 4275 2925 l 4050 2925 l 4050 2475 l 2475 2475 l 2475 2925 l - 2250 2925 l 2250 3375 l 2025 3375 l 2025 3825 l 1800 3825 l - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -n 2700 6525 m 3825 6525 l 3825 2025 l 3600 2025 l 3600 1575 l 2925 1575 l - 2925 2025 l 2700 2025 l cp gs col33 1.00 shd ef gr gs col33 s gr -% Polyline -gs clippath -12068 6810 m 11970 6885 l 12022 6773 l 11937 6878 l 11984 6915 l cp -clip -n 12375 4455 m 12510 4635 l 12510 6210 l 11970 6885 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 12068 6810 m 11970 6885 l 12022 6773 l 12045 6791 l 12068 6810 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -7113 6004 m 7155 6120 l 7063 6037 l 7138 6149 l 7188 6116 l cp -clip -n 6705 5445 m 7155 6120 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 7113 6004 m 7155 6120 l 7063 6037 l 7088 6020 l 7113 6004 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -7304 4656 m 7200 4590 l 7323 4599 l 7195 4557 l 7176 4614 l cp -clip -n 7875 4815 m 7200 4590 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 7304 4656 m 7200 4590 l 7323 4599 l 7314 4628 l 7304 4656 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -11405 4128 m 11475 4230 l 11365 4173 l 11466 4262 l 11506 4217 l cp -clip -n 9585 2565 m 11475 4230 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 11405 4128 m 11475 4230 l 11365 4173 l 11385 4151 l 11405 4128 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -11712 4556 m 11835 4545 l 11732 4613 l 11859 4568 l 11839 4512 l cp -clip -n 10170 5130 m 11835 4545 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 11712 4556 m 11835 4545 l 11732 4613 l 11722 4585 l 11712 4556 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -9732 5411 m 9855 5400 l 9752 5468 l 9879 5423 l 9859 5367 l cp -clip -n 7920 6075 m 9855 5400 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 9732 5411 m 9855 5400 l 9752 5468 l 9742 5440 l 9732 5411 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -10823 5573 m 10935 5625 l 10812 5632 l 10944 5657 l 10955 5598 l cp -clip -n 9990 5445 m 10935 5625 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 10823 5573 m 10935 5625 l 10812 5632 l 10817 5603 l 10823 5573 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -10815 5280 m 10935 5310 l 10815 5340 l 10950 5340 l 10950 5280 l cp -clip -n 10215 5310 m 10935 5310 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 10815 5280 m 10935 5310 l 10815 5340 l 10815 5310 l 10815 5280 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -11955 4965 m 11925 5085 l 11895 4965 l 11895 5100 l 11955 5100 l cp -clip -n 11925 4590 m 11925 5085 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 11955 4965 m 11925 5085 l 11895 4965 l 11925 4965 l 11955 4965 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -9840 6720 m 9810 6840 l 9780 6720 l 9780 6855 l 9840 6855 l cp -clip -n 9810 5490 m 9810 6840 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 9840 6720 m 9810 6840 l 9780 6720 l 9810 6720 l 9840 6720 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -10847 5943 m 10935 6030 l 10816 5995 l 10933 6063 l 10963 6012 l cp -clip -n 9945 5445 m 10935 6030 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 10847 5943 m 10935 6030 l 10816 5995 l 10832 5969 l 10847 5943 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -10698 2634 m 10800 2565 l 10742 2674 l 10832 2574 l 10788 2534 l cp -clip -n 8865 4725 m 10800 2565 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 10698 2634 m 10800 2565 l 10742 2674 l 10720 2654 l 10698 2634 l cp gs 0.00 setgray ef gr col0 s -% Polyline -30.000 slw -n 675 6075 m 5850 6075 l gs col34 1.00 shd ef gr gs col0 s gr -% Polyline -7.500 slw - [15 15] 15 sd -gs clippath -645 6195 m 675 6075 l 705 6195 l 705 6060 l 645 6060 l cp -clip -n 675 6525 m 675 6075 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 645 6195 m 675 6075 l 705 6195 l 675 6195 l 645 6195 l cp gs 0.00 setgray ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -5880 6405 m 5850 6525 l 5820 6405 l 5820 6540 l 5880 6540 l cp -clip -n 5850 6075 m 5850 6525 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 5880 6405 m 5850 6525 l 5820 6405 l 5850 6405 l 5880 6405 l cp gs col7 1.00 shd ef gr col0 s -% Polyline -30.000 slw -n 900 5625 m 5625 5625 l gs col34 1.00 shd ef gr gs col0 s gr -% Polyline -n 1125 5175 m 5400 5175 l gs col34 1.00 shd ef gr gs col0 s gr -% Polyline -n 1350 4725 m 5175 4725 l gs col34 1.00 shd ef gr gs col0 s gr -% Polyline -n 1575 4275 m 4950 4275 l gs col34 1.00 shd ef gr gs col0 s gr -% Polyline -n 1800 3825 m 4725 3825 l gs col34 1.00 shd ef gr gs col0 s gr -% Polyline -n 2025 3375 m 4500 3375 l gs col34 1.00 shd ef gr gs col0 s gr -% Polyline -n 2250 2925 m 4275 2925 l gs col34 1.00 shd ef gr gs col0 s gr -% Polyline -n 2475 2475 m 4050 2475 l gs col34 1.00 shd ef gr gs col0 s gr -% Polyline -n 2700 2025 m 3825 2025 l gs col34 1.00 shd ef gr gs col0 s gr -% Polyline -n 2925 1575 m 3600 1575 l gs col34 1.00 shd ef gr gs col0 s gr -% Polyline -7.500 slw - [15 15] 15 sd -gs clippath -870 5745 m 900 5625 l 930 5745 l 930 5610 l 870 5610 l cp -clip -n 900 6075 m 900 5625 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 870 5745 m 900 5625 l 930 5745 l 900 5745 l 870 5745 l cp gs 0.00 setgray ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -1095 5295 m 1125 5175 l 1155 5295 l 1155 5160 l 1095 5160 l cp -clip -n 1125 6525 m 1125 5175 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 1095 5295 m 1125 5175 l 1155 5295 l 1125 5295 l 1095 5295 l cp gs 0.00 setgray ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -1320 4845 m 1350 4725 l 1380 4845 l 1380 4710 l 1320 4710 l cp -clip -n 1350 5175 m 1350 4725 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 1320 4845 m 1350 4725 l 1380 4845 l 1350 4845 l 1320 4845 l cp gs 0.00 setgray ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -1545 4395 m 1575 4275 l 1605 4395 l 1605 4260 l 1545 4260 l cp -clip -n 1575 4725 m 1575 4275 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 1545 4395 m 1575 4275 l 1605 4395 l 1575 4395 l 1545 4395 l cp gs 0.00 setgray ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -1770 3945 m 1800 3825 l 1830 3945 l 1830 3810 l 1770 3810 l cp -clip -n 1800 6525 m 1800 3825 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 1770 3945 m 1800 3825 l 1830 3945 l 1800 3945 l 1770 3945 l cp gs 0.00 setgray ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -1995 3495 m 2025 3375 l 2055 3495 l 2055 3360 l 1995 3360 l cp -clip -n 2025 3825 m 2025 3375 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 1995 3495 m 2025 3375 l 2055 3495 l 2025 3495 l 1995 3495 l cp gs 0.00 setgray ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -2220 3045 m 2250 2925 l 2280 3045 l 2280 2910 l 2220 2910 l cp -clip -n 2250 3375 m 2250 2925 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 2220 3045 m 2250 2925 l 2280 3045 l 2250 3045 l 2220 3045 l cp gs 0.00 setgray ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -2445 2595 m 2475 2475 l 2505 2595 l 2505 2460 l 2445 2460 l cp -clip -n 2475 2925 m 2475 2475 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 2445 2595 m 2475 2475 l 2505 2595 l 2475 2595 l 2445 2595 l cp gs 0.00 setgray ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -5655 5955 m 5625 6075 l 5595 5955 l 5595 6090 l 5655 6090 l cp -clip -n 5625 5625 m 5625 6075 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 5655 5955 m 5625 6075 l 5595 5955 l 5625 5955 l 5655 5955 l cp gs col7 1.00 shd ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -5430 6405 m 5400 6525 l 5370 6405 l 5370 6540 l 5430 6540 l cp -clip -n 5400 5175 m 5400 6525 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 5430 6405 m 5400 6525 l 5370 6405 l 5400 6405 l 5430 6405 l cp gs col7 1.00 shd ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -5205 5055 m 5175 5175 l 5145 5055 l 5145 5190 l 5205 5190 l cp -clip -n 5175 4725 m 5175 5175 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 5205 5055 m 5175 5175 l 5145 5055 l 5175 5055 l 5205 5055 l cp gs col7 1.00 shd ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -4980 4605 m 4950 4725 l 4920 4605 l 4920 4740 l 4980 4740 l cp -clip -n 4950 4275 m 4950 4725 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 4980 4605 m 4950 4725 l 4920 4605 l 4950 4605 l 4980 4605 l cp gs col7 1.00 shd ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -4755 6405 m 4725 6525 l 4695 6405 l 4695 6540 l 4755 6540 l cp -clip -n 4725 3825 m 4725 6525 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 4755 6405 m 4725 6525 l 4695 6405 l 4725 6405 l 4755 6405 l cp gs col7 1.00 shd ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -4530 3705 m 4500 3825 l 4470 3705 l 4470 3840 l 4530 3840 l cp -clip -n 4500 3375 m 4500 3825 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 4530 3705 m 4500 3825 l 4470 3705 l 4500 3705 l 4530 3705 l cp gs col7 1.00 shd ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -4305 3255 m 4275 3375 l 4245 3255 l 4245 3390 l 4305 3390 l cp -clip -n 4275 2925 m 4275 3375 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 4305 3255 m 4275 3375 l 4245 3255 l 4275 3255 l 4305 3255 l cp gs col7 1.00 shd ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -4080 2805 m 4050 2925 l 4020 2805 l 4020 2940 l 4080 2940 l cp -clip -n 4050 2475 m 4050 2925 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 4080 2805 m 4050 2925 l 4020 2805 l 4050 2805 l 4080 2805 l cp gs col7 1.00 shd ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -2670 2145 m 2700 2025 l 2730 2145 l 2730 2010 l 2670 2010 l cp -clip -n 2700 6525 m 2700 2025 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 2670 2145 m 2700 2025 l 2730 2145 l 2700 2145 l 2670 2145 l cp gs 0.00 setgray ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -3855 6405 m 3825 6525 l 3795 6405 l 3795 6540 l 3855 6540 l cp -clip -n 3825 2025 m 3825 6525 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 3855 6405 m 3825 6525 l 3795 6405 l 3825 6405 l 3855 6405 l cp gs col7 1.00 shd ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -3630 1905 m 3600 2025 l 3570 1905 l 3570 2040 l 3630 2040 l cp -clip -n 3600 1575 m 3600 2025 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 3630 1905 m 3600 2025 l 3570 1905 l 3600 1905 l 3630 1905 l cp gs col7 1.00 shd ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -2895 1695 m 2925 1575 l 2955 1695 l 2955 1560 l 2895 1560 l cp -clip -n 2925 2025 m 2925 1575 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 2895 1695 m 2925 1575 l 2955 1695 l 2925 1695 l 2895 1695 l cp gs 0.00 setgray ef gr col0 s -% Polyline -45.000 slw -gs clippath -6087 6495 m 6207 6525 l 6087 6555 l 6360 6555 l 6360 6495 l cp -clip -n 540 6525 m 6300 6525 l gs 0.00 setgray ef gr gs col0 s gr gr - -% arrowhead -n 6087 6495 m 6207 6525 l 6087 6555 l 6087 6525 l 6087 6495 l cp gs 0.00 setgray ef gr col0 s -% Polyline -7.500 slw -gs clippath -3681 6720 m 3825 6750 l 3681 6780 l 3840 6780 l 3840 6720 l cp -2844 6780 m 2700 6750 l 2844 6720 l 2685 6720 l 2685 6780 l cp -clip -n 2700 6750 m 3825 6750 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 2844 6780 m 2700 6750 l 2844 6720 l 2820 6750 l 2844 6780 l cp gs col7 1.00 shd ef gr col0 s -% arrowhead -n 3681 6720 m 3825 6750 l 3681 6780 l 3705 6750 l 3681 6720 l cp gs col7 1.00 shd ef gr col0 s -% Polyline -gs clippath -5256 7170 m 5400 7200 l 5256 7230 l 5415 7230 l 5415 7170 l cp -1269 7230 m 1125 7200 l 1269 7170 l 1110 7170 l 1110 7230 l cp -clip -n 1125 7200 m 5400 7200 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 1269 7230 m 1125 7200 l 1269 7170 l 1245 7200 l 1269 7230 l cp gs col7 1.00 shd ef gr col0 s -% arrowhead -n 5256 7170 m 5400 7200 l 5256 7230 l 5280 7200 l 5256 7170 l cp gs col7 1.00 shd ef gr col0 s -% Polyline -gs clippath -4581 6945 m 4725 6975 l 4581 7005 l 4740 7005 l 4740 6945 l cp -1944 7005 m 1800 6975 l 1944 6945 l 1785 6945 l 1785 7005 l cp -clip -n 1800 6975 m 4725 6975 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 1944 7005 m 1800 6975 l 1944 6945 l 1920 6975 l 1944 7005 l cp gs col7 1.00 shd ef gr col0 s -% arrowhead -n 4581 6945 m 4725 6975 l 4581 7005 l 4605 6975 l 4581 6945 l cp gs col7 1.00 shd ef gr col0 s -% Polyline -gs clippath -5706 7395 m 5850 7425 l 5706 7455 l 5865 7455 l 5865 7395 l cp -819 7455 m 675 7425 l 819 7395 l 660 7395 l 660 7455 l cp -clip -n 675 7425 m 5850 7425 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 819 7455 m 675 7425 l 819 7395 l 795 7425 l 819 7455 l cp gs col7 1.00 shd ef gr col0 s -% arrowhead -n 5706 7395 m 5850 7425 l 5706 7455 l 5730 7425 l 5706 7395 l cp gs col7 1.00 shd ef gr col0 s -% Polyline -1 slc - [15 45] 45 sd -n 675 6570 m 675 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd -% Polyline - [15 45] 45 sd -n 1125 6570 m 1125 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd -% Polyline - [15 45] 45 sd -n 1800 6570 m 1800 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd -% Polyline - [15 45] 45 sd -n 2700 6570 m 2700 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd -% Polyline - [15 45] 45 sd -n 3825 6570 m 3825 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd -% Polyline - [15 45] 45 sd -n 4725 6570 m 4725 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd -% Polyline - [15 45] 45 sd -n 5400 6570 m 5400 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd -% Polyline - [15 45] 45 sd -n 5850 6570 m 5850 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd -% Polyline -0 slc -n 750 225 m 450 225 450 1050 300 arcto 4 {pop} repeat - 450 1350 12300 1350 300 arcto 4 {pop} repeat - 12600 1350 12600 525 300 arcto 4 {pop} repeat - 12600 225 750 225 300 arcto 4 {pop} repeat - cp gs col34 1.00 shd ef gr gs col0 s gr -% Polyline -n 8835 2250 m 8775 2250 8775 2415 60 arcto 4 {pop} repeat - 8775 2475 10110 2475 60 arcto 4 {pop} repeat - 10170 2475 10170 2310 60 arcto 4 {pop} repeat - 10170 2250 8835 2250 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -n 10635 2250 m 10575 2250 10575 2415 60 arcto 4 {pop} repeat - 10575 2475 11865 2475 60 arcto 4 {pop} repeat - 11925 2475 11925 2310 60 arcto 4 {pop} repeat - 11925 2250 10635 2250 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -n 11490 4275 m 11430 4275 11430 4440 60 arcto 4 {pop} repeat - 11430 4500 12315 4500 60 arcto 4 {pop} repeat - 12375 4500 12375 4335 60 arcto 4 {pop} repeat - 12375 4275 11490 4275 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -n 11040 5175 m 10980 5175 10980 5340 60 arcto 4 {pop} repeat - 10980 5400 12315 5400 60 arcto 4 {pop} repeat - 12375 5400 12375 5235 60 arcto 4 {pop} repeat - 12375 5175 11040 5175 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -n 9735 5175 m 9675 5175 9675 5340 60 arcto 4 {pop} repeat - 9675 5400 10110 5400 60 arcto 4 {pop} repeat - 10170 5400 10170 5235 60 arcto 4 {pop} repeat - 10170 5175 9735 5175 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -n 7260 6075 m 7200 6075 7200 6240 60 arcto 4 {pop} repeat - 7200 6300 7815 6300 60 arcto 4 {pop} repeat - 7875 6300 7875 6135 60 arcto 4 {pop} repeat - 7875 6075 7260 6075 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -n 6810 2250 m 6750 2250 6750 2415 60 arcto 4 {pop} repeat - 6750 2475 8130 2475 60 arcto 4 {pop} repeat - 8190 2475 8190 2310 60 arcto 4 {pop} repeat - 8190 2250 6810 2250 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -n 6360 3375 m 6300 3375 6300 3540 60 arcto 4 {pop} repeat - 6300 3600 7545 3600 60 arcto 4 {pop} repeat - 7605 3600 7605 3435 60 arcto 4 {pop} repeat - 7605 3375 6360 3375 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -n 6360 4275 m 6300 4275 6300 4440 60 arcto 4 {pop} repeat - 6300 4500 7275 4500 60 arcto 4 {pop} repeat - 7335 4500 7335 4335 60 arcto 4 {pop} repeat - 7335 4275 6360 4275 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -n 6360 5175 m 6300 5175 6300 5340 60 arcto 4 {pop} repeat - 6300 5400 7140 5400 60 arcto 4 {pop} repeat - 7200 5400 7200 5235 60 arcto 4 {pop} repeat - 7200 5175 6360 5175 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -gs clippath -7365 5340 m 7245 5310 l 7365 5280 l 7230 5280 l 7230 5340 l cp -clip -n 9630 5310 m 7245 5310 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 7365 5340 m 7245 5310 l 7365 5280 l 7365 5310 l 7365 5340 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -7500 4395 m 7380 4365 l 7500 4335 l 7365 4335 l 7365 4395 l cp -clip -n 11385 4365 m 7380 4365 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 7500 4395 m 7380 4365 l 7500 4335 l 7500 4365 l 7500 4395 l cp gs 0.00 setgray ef gr col0 s -% Polyline -n 11040 5580 m 10980 5580 10980 5745 60 arcto 4 {pop} repeat - 10980 5805 12180 5805 60 arcto 4 {pop} repeat - 12240 5805 12240 5640 60 arcto 4 {pop} repeat - 12240 5580 11040 5580 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -n 11040 5985 m 10980 5985 10980 6150 60 arcto 4 {pop} repeat - 10980 6210 12315 6210 60 arcto 4 {pop} repeat - 12375 6210 12375 6045 60 arcto 4 {pop} repeat - 12375 5985 11040 5985 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -gs clippath -9958 5554 m 9900 5445 l 10003 5514 l 9912 5414 l 9868 5454 l cp -clip -n 11205 6885 m 9900 5445 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 9958 5554 m 9900 5445 l 10003 5514 l 9981 5534 l 9958 5554 l cp gs 0.00 setgray ef gr col0 s -% Polyline -n 10590 6930 m 10530 6930 10530 7095 60 arcto 4 {pop} repeat - 10530 7155 12225 7155 60 arcto 4 {pop} repeat - 12285 7155 12285 6990 60 arcto 4 {pop} repeat - 12285 6930 10590 6930 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -n 9690 6930 m 9630 6930 9630 7095 60 arcto 4 {pop} repeat - 9630 7155 10110 7155 60 arcto 4 {pop} repeat - 10170 7155 10170 6990 60 arcto 4 {pop} repeat - 10170 6930 9690 6930 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -/Times-Roman-iso ff 120.00 scf sf -900 7560 m -gs 1 -1 sc (Startup, Runtime, Shutdown) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -6345 2970 m -gs 1 -1 sc (ap_ctx_get\(...,) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -10800 2745 m -gs 1 -1 sc (ap_get_module_config\(...) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -10800 2880 m -gs 1 -1 sc (->per_dir_config,) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -10800 3015 m -gs 1 -1 sc (&ssl_module\)) col0 sh gr -% Polyline -n 7980 4770 m 7920 4770 7920 4935 60 arcto 4 {pop} repeat - 7920 4995 9075 4995 60 arcto 4 {pop} repeat - 9135 4995 9135 4830 60 arcto 4 {pop} repeat - 9135 4770 7980 4770 60 arcto 4 {pop} repeat - cp gs col35 1.00 shd ef gr gs col35 s gr -% Polyline -gs clippath -7340 2610 m 7425 2520 l 7393 2639 l 7459 2521 l 7406 2492 l cp -clip -n 6975 3330 m 7425 2520 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 7340 2610 m 7425 2520 l 7393 2639 l 7367 2625 l 7340 2610 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -9336 2569 m 9450 2520 l 9373 2616 l 9480 2535 l 9444 2487 l cp -clip -n 7200 4230 m 9450 2520 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 9336 2569 m 9450 2520 l 9373 2616 l 9354 2593 l 9336 2569 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -7321 5196 m 7200 5220 l 7296 5142 l 7174 5199 l 7199 5254 l cp -clip -n 7875 4905 m 7200 5220 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 7321 5196 m 7200 5220 l 7296 5142 l 7309 5169 l 7321 5196 l cp gs 0.00 setgray ef gr col0 s -% Polyline -gs clippath -6720 4665 m 6750 4545 l 6780 4665 l 6780 4530 l 6720 4530 l cp -clip -n 6750 5130 m 6750 4545 l gs col34 1.00 shd ef gr gs col0 s gr gr - -% arrowhead -n 6720 4665 m 6750 4545 l 6780 4665 l 6750 4665 l 6720 4665 l cp gs 0.00 setgray ef gr col0 s -% Polyline - [15 15] 15 sd -gs clippath -9279 4984 m 9175 4918 l 9298 4927 l 9170 4885 l 9151 4942 l cp -clip -n 9850 5143 m 9175 4918 l gs col34 1.00 shd ef gr gs col0 s gr gr - [] 0 sd -% arrowhead -n 9279 4984 m 9175 4918 l 9298 4927 l 9289 4956 l 9279 4984 l cp gs 0.00 setgray ef gr col0 s -/Helvetica-Narrow-iso ff 120.00 scf sf -6210 4680 m -gs 1 -1 sc (->server) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -8280 6120 m -gs 1 -1 sc (ap_ctx_get\(...,"ssl"\)) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -7740 2700 m -gs 1 -1 sc (ap_get_module_config\(...) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -7740 2835 m -gs 1 -1 sc (->module_config,) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -7740 2970 m -gs 1 -1 sc (&ssl_module\)) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -6345 3105 m -gs 1 -1 sc ("ssl_module"\)) col0 sh gr -/Times-Roman-iso ff 120.00 scf sf -1350 7335 m -gs 1 -1 sc (Configuration Time) col0 sh gr -/Times-Roman-iso ff 120.00 scf sf -2025 7110 m -gs 1 -1 sc (Connection Duration) col0 sh gr -/Times-Roman-iso ff 120.00 scf sf -2835 6885 m -gs 1 -1 sc (Request Duration) col0 sh gr -/Helvetica-Bold-iso ff 300.00 scf sf -6345 6795 m -gs 1 -1 sc (t) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -7110 5985 m -gs 1 -1 sc (->client) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -7065 5085 m -gs 1 -1 sc (->connection) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -7065 4770 m -gs 1 -1 sc (->server) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -8010 5445 m -gs 1 -1 sc (SSL_get_app_data\(\)) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -10530 4050 m -gs 1 -1 sc (->pSSLCtx) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -7875 4275 m -gs 1 -1 sc (SSL_CTX_get_app_data\(\)) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -10305 5535 m -gs 1 -1 sc (SSL_get_current_cipher\(\)) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -10440 5940 m -gs 1 -1 sc (SSL_get_session\(\)) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -9540 7335 m -gs 1 -1 sc (SSL_get_{r,w}bio\(\)) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -10125 4680 m -gs 1 -1 sc (SSL_get_SSL_CTX\(\)) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -10350 5175 m -gs 1 -1 sc (SSL_get_SSL_METHOD\(\)) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -11745 4770 m -gs 1 -1 sc (->method) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -9945 6480 m -gs 1 -1 sc (X509_STORE_CTX_get_app_data\(\)) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -10980 6705 m -gs 1 -1 sc (SSL_CTX_get_cert_store\(\)) col0 sh gr -/Helvetica-Narrow-iso ff 120.00 scf sf -8280 5130 m -gs 1 -1 sc (SSL_get_app_data2\(\)) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -3645 1620 m -gs 1 -1 sc (SSLDirConfig) col0 sh gr -/Helvetica-Bold-iso ff 300.00 scf sf -10935 3645 m -gs 1 -1 sc (OpenSSL) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -10935 3825 m -gs 1 -1 sc ([SSL]) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -11025 5760 m -gs 1 -1 sc (SSL_CIPHER) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -10980 6165 m -gs 1 -1 sc (SSL_SESSION) col0 sh gr -/Helvetica-Bold-iso ff 300.00 scf sf -10710 7605 m -gs 1 -1 sc (OpenSSL) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -10575 7110 m -gs 1 -1 sc (X509_STORE_CTX) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -6795 2430 m -gs 1 -1 sc (SSLModConfig) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -8865 2430 m -gs 1 -1 sc (SSLSrvConfig) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -6345 3555 m -gs 1 -1 sc (ap_global_ctx) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -6345 4455 m -gs 1 -1 sc (server_rec) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -6345 5355 m -gs 1 -1 sc (conn_rec) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -9720 5355 m -gs 1 -1 sc (SSL) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -10665 2430 m -gs 1 -1 sc (SSLDirConfig) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -7290 6255 m -gs 1 -1 sc (BUFF) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -11025 5355 m -gs 1 -1 sc (SSL_METHOD) col0 sh gr -% Polyline -15.000 slw -n 750 225 m 450 225 450 8250 300 arcto 4 {pop} repeat - 450 8550 12300 8550 300 arcto 4 {pop} repeat - 12600 8550 12600 525 300 arcto 4 {pop} repeat - 12600 225 750 225 300 arcto 4 {pop} repeat - cp gs col0 s gr -/Helvetica-Bold-iso ff 180.00 scf sf -11475 4455 m -gs 1 -1 sc (SSL_CTX) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -8010 4950 m -gs 1 -1 sc (request_rec) col0 sh gr -/Times-Roman-iso ff 180.00 scf sf -10575 675 m -gs 1 -1 sc (Ralf S. Engelschall) col0 sh gr -/Helvetica-Bold-iso ff 300.00 scf sf -4275 675 m -gs 1 -1 sc (Apache+mod_ssl+OpenSSL) col0 sh gr -/Times-Roman-iso ff 150.00 scf sf -10575 855 m -gs 1 -1 sc (rse@engelschall.com) col0 sh gr -/Times-Roman-iso ff 150.00 scf sf -10575 1035 m -gs 1 -1 sc (www.engelschall.com) col0 sh gr -/Times-Roman-iso ff 180.00 scf sf -900 675 m -gs 1 -1 sc (Version 1.3) col0 sh gr -/Times-Roman-iso ff 180.00 scf sf -900 855 m -gs 1 -1 sc (12-Apr-1999) col0 sh gr -/Helvetica-Bold-iso ff 360.00 scf sf -3915 1080 m -gs 1 -1 sc (Data Structure Overview) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -9720 7110 m -gs 1 -1 sc (BIO) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -10710 7785 m -gs 1 -1 sc ([Crypto]) col0 sh gr -/Helvetica-Bold-iso ff 300.00 scf sf -8730 3465 m -gs 1 -1 sc (mod_ssl) col0 sh gr -/Helvetica-Bold-iso ff 300.00 scf sf -8145 6750 m -gs 1 -1 sc (Apache) col0 sh gr -/Helvetica-Bold-iso ff 300.00 scf sf -9000 8100 m -gs 1 -1 sc (Chaining) col0 sh gr -/Helvetica-Bold-iso ff 300.00 scf sf -2745 8100 m -gs 1 -1 sc (Lifetime) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -810 6255 m -gs 1 -1 sc (ap_global_ctx) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -990 5805 m -gs 1 -1 sc (SSLModConfig) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -4050 4455 m -gs 1 -1 sc (SSL_CTX) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -4455 5355 m -gs 1 -1 sc (server_rec) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -3870 4905 m -gs 1 -1 sc (SSLSrvConfig) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -1845 4005 m -gs 1 -1 sc (BUFF) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -2070 3555 m -gs 1 -1 sc (conn_rec) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -2295 3105 m -gs 1 -1 sc (BIO) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -2565 2655 m -gs 1 -1 sc (SSL) col0 sh gr -/Helvetica-Bold-iso ff 180.00 scf sf -3915 2070 m -gs 1 -1 sc (request_rec) col0 sh gr -$F2psEnd -rs -showpage diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c deleted file mode 100644 index 2d1b5e1b0a..0000000000 --- a/modules/ssl/mod_ssl.c +++ /dev/null @@ -1,248 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** mod_ssl.c -** Apache API interface structures -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - /* ``I'll be surprised if - others think that what you - are doing is honourable.'' - -- Ben Laurie, Apache-SSL author */ -#include "mod_ssl.h" - -/* _________________________________________________________________ -** -** Apache API glue structures -** _________________________________________________________________ -*/ - -/* - * identify the module to SCCS `what' and RCS `ident' commands - */ -static char const sccsid[] = "@(#) mod_ssl/" MOD_SSL_VERSION " >"; -static char const rcsid[] = "$Id: mod_ssl.c,v 1.1 2001/05/04 21:54:42 rse Exp $"; - -/* - * the table of configuration directives we provide - */ -static command_rec ssl_config_cmds[] = { - /* - * Global (main-server) context configuration directives - */ - AP_SRV_CMD(Mutex, TAKE1, - "SSL lock for handling internal mutual exclusions " - "(`none', `file:/path/to/file')") - AP_SRV_CMD(PassPhraseDialog, TAKE1, - "SSL dialog mechanism for the pass phrase query " - "(`builtin', `exec:/path/to/program')") - AP_SRV_CMD(SessionCache, TAKE1, - "SSL Session Cache storage " - "(`none', `dbm:/path/to/file')") -#ifdef SSL_EXPERIMENTAL_ENGINE - AP_SRV_CMD(CryptoDevice, TAKE1, - "SSL external Crypto Device usage " - "(`builtin', `...')") -#endif - AP_SRV_CMD(RandomSeed, TAKE23, - "SSL Pseudo Random Number Generator (PRNG) seeding source " - "(`startup|connect builtin|file:/path|exec:/path [bytes]')") - - /* - * Per-server context configuration directives - */ - AP_SRV_CMD(Engine, FLAG, - "SSL switch for the protocol engine " - "(`on', `off')") - AP_ALL_CMD(CipherSuite, TAKE1, - "Colon-delimited list of permitted SSL Ciphers " - "(`XXX:...:XXX' - see manual)") - AP_SRV_CMD(CertificateFile, TAKE1, - "SSL Server Certificate file " - "(`/path/to/file' - PEM or DER encoded)") - AP_SRV_CMD(CertificateKeyFile, TAKE1, - "SSL Server Private Key file " - "(`/path/to/file' - PEM or DER encoded)") - AP_SRV_CMD(CertificateChainFile, TAKE1, - "SSL Server CA Certificate Chain file " - "(`/path/to/file' - PEM encoded)") -#ifdef SSL_EXPERIMENTAL_PERDIRCA - AP_ALL_CMD(CACertificatePath, TAKE1, - "SSL CA Certificate path " - "(`/path/to/dir' - contains PEM encoded files)") - AP_ALL_CMD(CACertificateFile, TAKE1, - "SSL CA Certificate file " - "(`/path/to/file' - PEM encoded)") -#else - AP_SRV_CMD(CACertificatePath, TAKE1, - "SSL CA Certificate path " - "(`/path/to/dir' - contains PEM encoded files)") - AP_SRV_CMD(CACertificateFile, TAKE1, - "SSL CA Certificate file " - "(`/path/to/file' - PEM encoded)") -#endif - AP_SRV_CMD(CARevocationPath, TAKE1, - "SSL CA Certificate Revocation List (CRL) path " - "(`/path/to/dir' - contains PEM encoded files)") - AP_SRV_CMD(CARevocationFile, TAKE1, - "SSL CA Certificate Revocation List (CRL) file " - "(`/path/to/file' - PEM encoded)") - AP_ALL_CMD(VerifyClient, TAKE1, - "SSL Client verify type " - "(`none', `optional', `require', `optional_no_ca')") - AP_ALL_CMD(VerifyDepth, TAKE1, - "SSL Client verify depth " - "(`N' - number of intermediate certificates)") - AP_SRV_CMD(SessionCacheTimeout, TAKE1, - "SSL Session Cache object lifetime " - "(`N' - number of seconds)") - AP_SRV_CMD(Log, TAKE1, - "SSL logfile for SSL-related messages " - "(`/path/to/file', `|/path/to/program')") - AP_SRV_CMD(LogLevel, TAKE1, - "SSL logfile verbosity level " - "(`none', `error', `warn', `info', `debug')") - AP_SRV_CMD(Protocol, RAW_ARGS, - "Enable or disable various SSL protocols" - "(`[+-][SSLv2|SSLv3|TLSv1] ...' - see manual)") - -#ifdef SSL_EXPERIMENTAL_PROXY - /* - * Proxy configuration for remote SSL connections - */ - AP_SRV_CMD(ProxyProtocol, RAW_ARGS, - "SSL Proxy: enable or disable SSL protocol flavors " - "(`[+-][SSLv2|SSLv3|TLSv1] ...' - see manual)") - AP_SRV_CMD(ProxyCipherSuite, TAKE1, - "SSL Proxy: colon-delimited list of permitted SSL ciphers " - "(`XXX:...:XXX' - see manual)") - AP_SRV_CMD(ProxyVerify, FLAG, - "SSL Proxy: whether to verify the remote certificate " - "(`on' or `off')") - AP_SRV_CMD(ProxyVerifyDepth, TAKE1, - "SSL Proxy: maximum certificate verification depth " - "(`N' - number of intermediate certificates)") - AP_SRV_CMD(ProxyCACertificateFile, TAKE1, - "SSL Proxy: file containing server certificates " - "(`/path/to/file' - PEM encoded certificates)") - AP_SRV_CMD(ProxyCACertificatePath, TAKE1, - "SSL Proxy: directory containing server certificates " - "(`/path/to/dir' - contains PEM encoded certificates)") - AP_SRV_CMD(ProxyMachineCertificateFile, TAKE1, - "SSL Proxy: file containing client certificates " - "(`/path/to/file' - PEM encoded certificates)") - AP_SRV_CMD(ProxyMachineCertificatePath, TAKE1, - "SSL Proxy: directory containing client certificates " - "(`/path/to/dir' - contains PEM encoded certificates)") -#endif - - /* - * Per-directory context configuration directives - */ - AP_DIR_CMD(Options, OPTIONS, RAW_ARGS, - "Set one of more options to configure the SSL engine" - "(`[+-]option[=value] ...' - see manual)") - AP_DIR_CMD(RequireSSL, AUTHCFG, NO_ARGS, - "Require the SSL protocol for the per-directory context " - "(no arguments)") - AP_DIR_CMD(Require, AUTHCFG, RAW_ARGS, - "Require a boolean expresion to evaluate to true for granting access" - "(arbitrary complex boolean expression - see manual)") - - AP_END_CMD -}; - -static const handler_rec ssl_config_handler[] = { - { "mod_ssl:content-handler", ssl_hook_Handler }, - { NULL, NULL } -}; - -/* - * the main Apache API config structure - */ -module MODULE_VAR_EXPORT ssl_module = { - STANDARD_MODULE_STUFF, - - /* Standard API (always present) */ - - ssl_init_Module, /* module initializer */ - ssl_config_perdir_create, /* create per-dir config structures */ - ssl_config_perdir_merge, /* merge per-dir config structures */ - ssl_config_server_create, /* create per-server config structures */ - ssl_config_server_merge, /* merge per-server config structures */ - ssl_config_cmds, /* table of config file commands */ - ssl_config_handler, /* [#8] MIME-typed-dispatched handlers */ - ssl_hook_Translate, /* [#1] URI to filename translation */ - ssl_hook_Auth, /* [#4] validate user id from request */ - ssl_hook_UserCheck, /* [#5] check if the user is ok _here_ */ - ssl_hook_Access, /* [#3] check access by host address */ - NULL, /* [#6] determine MIME type */ - ssl_hook_Fixup, /* [#7] pre-run fixups */ - NULL, /* [#9] log a transaction */ - NULL, /* [#2] header parser */ - ssl_init_Child, /* child_init */ - NULL, /* child_exit */ - ssl_hook_ReadReq, /* [#0] post read-request */ - - /* Extended API (forced to be enabled with mod_ssl) */ - - ssl_hook_AddModule, /* after modules was added to core */ - ssl_hook_RemoveModule, /* before module is removed from core */ - ssl_hook_RewriteCommand, /* configuration command rewriting */ - ssl_hook_NewConnection, /* socket connection open */ - ssl_hook_CloseConnection /* socket connection close */ -}; - diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h deleted file mode 100644 index 8731ef9de4..0000000000 --- a/modules/ssl/mod_ssl.h +++ /dev/null @@ -1,854 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** mod_ssl.h -** Global header -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - /* ``The Apache Group: a collection - of talented individuals who are - trying to perfect the art of - never finishing something.'' - -- Rob Hartill */ -#ifndef MOD_SSL_H -#define MOD_SSL_H 1 - -/* - * Check whether Extended API (EAPI) is enabled - */ -#ifndef EAPI -#error "mod_ssl requires Extended API (EAPI)" -#endif - -/* - * Optionally enable the experimental stuff, but allow the user to - * override the decision which experimental parts are included by using - * CFLAGS="-DSSL_EXPERIMENTAL_xxxx_IGNORE". - */ -#ifdef SSL_EXPERIMENTAL -#ifndef SSL_EXPERIMENTAL_PERDIRCA_IGNORE -#define SSL_EXPERIMENTAL_PERDIRCA -#endif -#ifndef SSL_EXPERIMENTAL_PROXY_IGNORE -#define SSL_EXPERIMENTAL_PROXY -#endif -#ifdef SSL_ENGINE -#ifndef SSL_EXPERIMENTAL_ENGINE_IGNORE -#define SSL_EXPERIMENTAL_ENGINE -#endif -#endif -#endif /* SSL_EXPERIMENTAL */ - -/* - * Power up our brain... - */ - -/* OS headers */ -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <time.h> -#ifndef WIN32 -#include <sys/time.h> -#endif -#ifdef WIN32 -#include <wincrypt.h> -#include <winsock2.h> -#endif - -/* OpenSSL headers */ -#include <openssl/ssl.h> -#include <openssl/err.h> -#include <openssl/x509.h> -#include <openssl/x509v3.h> -#include <openssl/pem.h> -#include <openssl/crypto.h> -#include <openssl/evp.h> -#include <openssl/rand.h> -#ifdef SSL_EXPERIMENTAL_ENGINE -#include <openssl/engine.h> -#endif - -/* Apache headers */ -#define CORE_PRIVATE -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_conf_globals.h" -#include "http_protocol.h" -#include "http_request.h" -#include "http_main.h" -#include "http_core.h" -#include "http_log.h" -#include "scoreboard.h" -#include "util_md5.h" -#include "fnmatch.h" -#undef CORE_PRIVATE - -/* mod_ssl headers */ -#include "ssl_expr.h" -#include "ssl_util_ssl.h" -#include "ssl_util_table.h" - -/* - * Provide reasonable default for some defines - */ -#ifndef FALSE -#define FALSE (0) -#endif -#ifndef TRUE -#define TRUE (!FALSE) -#endif -#ifndef PFALSE -#define PFALSE ((void *)FALSE) -#endif -#ifndef PTRUE -#define PTRUE ((void *)TRUE) -#endif -#ifndef UNSET -#define UNSET (-1) -#endif -#ifndef NUL -#define NUL '\0' -#endif -#ifndef RAND_MAX -#include <limits.h> -#define RAND_MAX INT_MAX -#endif - -/* - * Provide reasonable defines for some types - */ -#ifndef BOOL -#define BOOL unsigned int -#endif -#ifndef UCHAR -#define UCHAR unsigned char -#endif - -/* - * Provide useful shorthands - */ -#define strEQ(s1,s2) (strcmp(s1,s2) == 0) -#define strNE(s1,s2) (strcmp(s1,s2) != 0) -#define strEQn(s1,s2,n) (strncmp(s1,s2,n) == 0) -#define strNEn(s1,s2,n) (strncmp(s1,s2,n) != 0) - -#define strcEQ(s1,s2) (strcasecmp(s1,s2) == 0) -#define strcNE(s1,s2) (strcasecmp(s1,s2) != 0) -#define strcEQn(s1,s2,n) (strncasecmp(s1,s2,n) == 0) -#define strcNEn(s1,s2,n) (strncasecmp(s1,s2,n) != 0) - -#define strIsEmpty(s) (s == NULL || s[0] == NUL) - -#define cfgMerge(el,unset) new->el = add->el == unset ? base->el : add->el -#define cfgMergeArray(el) new->el = ap_append_arrays(p, add->el, base->el) -#define cfgMergeTable(el) new->el = ap_overlay_tables(p, add->el, base->el) -#define cfgMergeCtx(el) new->el = ap_ctx_overlay(p, add->el, base->el) -#define cfgMergeString(el) cfgMerge(el, NULL) -#define cfgMergeBool(el) cfgMerge(el, UNSET) -#define cfgMergeInt(el) cfgMerge(el, UNSET) - -#define myModConfig() (SSLModConfigRec *)ap_ctx_get(ap_global_ctx, "ssl_module") -#define mySrvConfig(srv) (SSLSrvConfigRec *)ap_get_module_config(srv->module_config, &ssl_module) -#define myDirConfig(req) (SSLDirConfigRec *)ap_get_module_config(req->per_dir_config, &ssl_module) - -#define myCtxVarSet(mc,num,val) mc->rCtx.pV##num = val -#define myCtxVarGet(mc,num,type) (type)(mc->rCtx.pV##num) - -#define AP_ALL_CMD(name, args, desc) \ - { "SSL"#name, ssl_cmd_SSL##name, NULL, RSRC_CONF|OR_AUTHCFG, args, desc }, -#define AP_SRV_CMD(name, args, desc) \ - { "SSL"#name, ssl_cmd_SSL##name, NULL, RSRC_CONF, args, desc }, -#define AP_DIR_CMD(name, type, args, desc) \ - { "SSL"#name, ssl_cmd_SSL##name, NULL, OR_##type, args, desc }, -#define AP_END_CMD \ - { NULL } - -/* - * SSL Logging - */ -#define SSL_LOG_NONE (1<<0) -#define SSL_LOG_ERROR (1<<1) -#define SSL_LOG_WARN (1<<2) -#define SSL_LOG_INFO (1<<3) -#define SSL_LOG_TRACE (1<<4) -#define SSL_LOG_DEBUG (1<<5) -#define SSL_LOG_MASK (SSL_LOG_ERROR|SSL_LOG_WARN|SSL_LOG_INFO|SSL_LOG_TRACE|SSL_LOG_DEBUG) - -#define SSL_ADD_NONE (1<<8) -#define SSL_ADD_ERRNO (1<<9) -#define SSL_ADD_SSLERR (1<<10) -#define SSL_NO_TIMESTAMP (1<<11) -#define SSL_NO_LEVELID (1<<12) -#define SSL_NO_NEWLINE (1<<13) - -/* - * Defaults for the configuration - */ -#ifndef SSL_SESSION_CACHE_TIMEOUT -#define SSL_SESSION_CACHE_TIMEOUT 300 -#endif - -/* - * Support for file locking: Try to determine whether we should use fcntl() or - * flock(). Would be better ap_config.h could provide this... :-( - */ -#if defined(USE_FCNTL_SERIALIZED_ACCEPT) -#define SSL_USE_FCNTL 1 -#include <fcntl.h> -#endif -#if defined(USE_FLOCK_SERIALIZED_ACCEPT) -#define SSL_USE_FLOCK 1 -#include <sys/file.h> -#endif -#if !defined(SSL_USE_FCNTL) && !defined(SSL_USE_FLOCK) -#define SSL_USE_FLOCK 1 -#if !defined(MPE) && !defined(WIN32) -#include <sys/file.h> -#endif -#ifndef LOCK_UN -#undef SSL_USE_FLOCK -#define SSL_USE_FCNTL 1 -#include <fcntl.h> -#endif -#endif -#ifdef AIX -#undef SSL_USE_FLOCK -#define SSL_USE_FCNTL 1 -#include <fcntl.h> -#endif - -/* - * Support for Mutex - */ -#ifndef WIN32 -#define SSL_MUTEX_LOCK_MODE ( S_IRUSR|S_IWUSR ) -#else -#define SSL_MUTEX_LOCK_MODE (_S_IREAD|_S_IWRITE ) -#endif -#if defined(USE_SYSVSEM_SERIALIZED_ACCEPT) ||\ - (defined(__FreeBSD__) && defined(__FreeBSD_version) &&\ - __FreeBSD_version >= 300000) ||\ - (defined(LINUX) && defined(__GLIBC__) && defined(__GLIBC_MINOR__) &&\ - LINUX >= 2 && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) ||\ - defined(SOLARIS2) || defined(__hpux) ||\ - (defined (__digital__) && defined (__unix__)) -#define SSL_CAN_USE_SEM -#define SSL_HAVE_IPCSEM -#include <sys/types.h> -#include <sys/ipc.h> -#include <sys/sem.h> -/* - * Some platforms have a `union semun' pre-defined but Single Unix - * Specification (SUSv2) says in semctl(2): `If required, it is of - * type union semun, which the application program must explicitly - * declare'. So we define it always ourself to avoid problems (but under - * a different name to avoid a namespace clash). - */ -union ssl_ipc_semun { - long val; - struct semid_ds *buf; - unsigned short int *array; -}; -#endif -#ifdef WIN32 -#define SSL_CAN_USE_SEM -#define SSL_HAVE_W32SEM -#include "multithread.h" -#include <process.h> -#endif - -/* - * Support for MM library - */ -#ifndef WIN32 -#define SSL_MM_FILE_MODE ( S_IRUSR|S_IWUSR ) -#else -#define SSL_MM_FILE_MODE ( _S_IREAD|_S_IWRITE ) -#endif - -/* - * Support for DBM library - */ -#ifndef WIN32 -#define SSL_DBM_FILE_MODE ( S_IRUSR|S_IWUSR ) -#else -#define SSL_USE_SDBM -#define SSL_DBM_FILE_MODE ( _S_IREAD|_S_IWRITE ) -#endif - -#ifdef SSL_USE_SDBM -#include "ssl_util_sdbm.h" -#define ssl_dbm_open sdbm_open -#define ssl_dbm_close sdbm_close -#define ssl_dbm_store sdbm_store -#define ssl_dbm_fetch sdbm_fetch -#define ssl_dbm_delete sdbm_delete -#define ssl_dbm_firstkey sdbm_firstkey -#define ssl_dbm_nextkey sdbm_nextkey -#define SSL_DBM_FILE_SUFFIX_DIR ".dir" -#define SSL_DBM_FILE_SUFFIX_PAG ".pag" -#else /* !SSL_USE_SDBM */ -#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) \ - && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 -#include <db1/ndbm.h> -#else -#include <ndbm.h> -#endif -#define ssl_dbm_open dbm_open -#define ssl_dbm_close dbm_close -#define ssl_dbm_store dbm_store -#define ssl_dbm_fetch dbm_fetch -#define ssl_dbm_delete dbm_delete -#define ssl_dbm_firstkey dbm_firstkey -#define ssl_dbm_nextkey dbm_nextkey -#if !defined(SSL_DBM_FILE_SUFFIX_DIR) && !defined(SSL_DBM_FILE_SUFFIX_PAG) -#if defined(DBM_SUFFIX) -#define SSL_DBM_FILE_SUFFIX_DIR DBM_SUFFIX -#define SSL_DBM_FILE_SUFFIX_PAG DBM_SUFFIX -#elif defined(__FreeBSD__) || (defined(DB_LOCK) && defined(DB_SHMEM)) -#define SSL_DBM_FILE_SUFFIX_DIR ".db" -#define SSL_DBM_FILE_SUFFIX_PAG ".db" -#else -#define SSL_DBM_FILE_SUFFIX_DIR ".dir" -#define SSL_DBM_FILE_SUFFIX_PAG ".pag" -#endif -#endif -#endif /* !SSL_USE_SDBM */ - -/* - * Check for OpenSSL version - */ -#if SSL_LIBRARY_VERSION < 0x00903100 -#error "mod_ssl requires OpenSSL 0.9.3 or higher" -#endif - -/* - * The own data structures - */ -typedef struct { - pool *pPool; - pool *pSubPool; - array_header *aData; -} ssl_ds_array; - -typedef struct { - pool *pPool; - pool *pSubPool; - array_header *aKey; - array_header *aData; -} ssl_ds_table; - -/* - * Define the certificate algorithm types - */ - -typedef int ssl_algo_t; - -#define SSL_ALGO_UNKNOWN (0) -#define SSL_ALGO_RSA (1<<0) -#define SSL_ALGO_DSA (1<<1) -#define SSL_ALGO_ALL (SSL_ALGO_RSA|SSL_ALGO_DSA) - -#define SSL_AIDX_RSA (0) -#define SSL_AIDX_DSA (1) -#define SSL_AIDX_MAX (2) - -/* - * Define IDs for the temporary RSA keys and DH params - */ - -#define SSL_TKP_GEN (0) -#define SSL_TKP_ALLOC (1) -#define SSL_TKP_FREE (2) - -#define SSL_TKPIDX_RSA512 (0) -#define SSL_TKPIDX_RSA1024 (1) -#define SSL_TKPIDX_DH512 (2) -#define SSL_TKPIDX_DH1024 (3) -#define SSL_TKPIDX_MAX (4) - -/* - * Define the SSL options - */ -#define SSL_OPT_NONE (0) -#define SSL_OPT_RELSET (1<<0) -#define SSL_OPT_STDENVVARS (1<<1) -#define SSL_OPT_COMPATENVVARS (1<<2) -#define SSL_OPT_EXPORTCERTDATA (1<<3) -#define SSL_OPT_FAKEBASICAUTH (1<<4) -#define SSL_OPT_STRICTREQUIRE (1<<5) -#define SSL_OPT_OPTRENEGOTIATE (1<<6) -#define SSL_OPT_ALL (SSL_OPT_STDENVVARS|SSL_OPT_COMPATENVVAR|SSL_OPT_EXPORTCERTDATA|SSL_OPT_FAKEBASICAUTH|SSL_OPT_STRICTREQUIRE|SSL_OPT_OPTRENEGOTIATE) -typedef int ssl_opt_t; - -/* - * Define the SSL Protocol options - */ -#define SSL_PROTOCOL_NONE (0) -#define SSL_PROTOCOL_SSLV2 (1<<0) -#define SSL_PROTOCOL_SSLV3 (1<<1) -#define SSL_PROTOCOL_TLSV1 (1<<2) -#define SSL_PROTOCOL_ALL (SSL_PROTOCOL_SSLV2|SSL_PROTOCOL_SSLV3|SSL_PROTOCOL_TLSV1) -typedef int ssl_proto_t; - -/* - * Define the SSL verify levels - */ -typedef enum { - SSL_CVERIFY_UNSET = UNSET, - SSL_CVERIFY_NONE = 0, - SSL_CVERIFY_OPTIONAL = 1, - SSL_CVERIFY_REQUIRE = 2, - SSL_CVERIFY_OPTIONAL_NO_CA = 3 -} ssl_verify_t; - -/* - * Define the SSL pass phrase dialog types - */ -typedef enum { - SSL_PPTYPE_UNSET = UNSET, - SSL_PPTYPE_BUILTIN = 0, - SSL_PPTYPE_FILTER = 1 -} ssl_pphrase_t; - -/* - * Define the Path Checking modes - */ -#define SSL_PCM_EXISTS 1 -#define SSL_PCM_ISREG 2 -#define SSL_PCM_ISDIR 4 -#define SSL_PCM_ISNONZERO 8 -typedef unsigned int ssl_pathcheck_t; - -/* - * Define the SSL session cache modes and structures - */ -typedef enum { - SSL_SCMODE_UNSET = UNSET, - SSL_SCMODE_NONE = 0, - SSL_SCMODE_DBM = 1, - SSL_SCMODE_SHMHT = 2, - SSL_SCMODE_SHMCB = 3 -} ssl_scmode_t; - -/* - * Define the SSL mutex modes - */ -typedef enum { - SSL_MUTEXMODE_UNSET = UNSET, - SSL_MUTEXMODE_NONE = 0, - SSL_MUTEXMODE_FILE = 1, - SSL_MUTEXMODE_SEM = 2 -} ssl_mutexmode_t; - -/* - * Define the SSL requirement structure - */ -typedef struct { - char *cpExpr; - ssl_expr *mpExpr; -} ssl_require_t; - -/* - * Define the SSL random number generator seeding source - */ -typedef enum { - SSL_RSCTX_STARTUP = 1, - SSL_RSCTX_CONNECT = 2 -} ssl_rsctx_t; -typedef enum { - SSL_RSSRC_BUILTIN = 1, - SSL_RSSRC_FILE = 2, - SSL_RSSRC_EXEC = 3 -#if SSL_LIBRARY_VERSION >= 0x00905100 - ,SSL_RSSRC_EGD = 4 -#endif -} ssl_rssrc_t; -typedef struct { - ssl_rsctx_t nCtx; - ssl_rssrc_t nSrc; - char *cpPath; - int nBytes; -} ssl_randseed_t; - -/* - * Define the structure of an ASN.1 anything - */ -typedef struct { - long int nData; - unsigned char *cpData; -} ssl_asn1_t; - -/* - * Define the mod_ssl per-module configuration structure - * (i.e. the global configuration for each httpd process) - */ - -typedef struct { - pool *pPool; - BOOL bFixed; - int nInitCount; - int nSessionCacheMode; - char *szSessionCacheDataFile; - int nSessionCacheDataSize; - AP_MM *pSessionCacheDataMM; - table_t *tSessionCacheDataTable; - ssl_mutexmode_t nMutexMode; - char *szMutexFile; - int nMutexFD; - int nMutexSEMID; - array_header *aRandSeed; - ssl_ds_table *tTmpKeys; - void *pTmpKeys[SSL_TKPIDX_MAX]; - ssl_ds_table *tPublicCert; - ssl_ds_table *tPrivateKey; -#ifdef SSL_EXPERIMENTAL_ENGINE - char *szCryptoDevice; -#endif - struct { - void *pV1, *pV2, *pV3, *pV4, *pV5, *pV6, *pV7, *pV8, *pV9, *pV10; - } rCtx; -#ifdef SSL_VENDOR - ap_ctx *ctx; -#endif -} SSLModConfigRec; - -/* - * Define the mod_ssl per-server configuration structure - * (i.e. the configuration for the main server - * and all <VirtualHost> contexts) - */ -typedef struct { - BOOL bEnabled; - char *szPublicCertFile[SSL_AIDX_MAX]; - char *szPrivateKeyFile[SSL_AIDX_MAX]; - char *szCertificateChain; - char *szCACertificatePath; - char *szCACertificateFile; - char *szLogFile; - char *szCipherSuite; - FILE *fileLogFile; - int nLogLevel; - int nVerifyDepth; - ssl_verify_t nVerifyClient; - X509 *pPublicCert[SSL_AIDX_MAX]; - EVP_PKEY *pPrivateKey[SSL_AIDX_MAX]; - SSL_CTX *pSSLCtx; - int nSessionCacheTimeout; - int nPassPhraseDialogType; - char *szPassPhraseDialogPath; - ssl_proto_t nProtocol; - char *szCARevocationPath; - char *szCARevocationFile; - X509_STORE *pRevocationStore; -#ifdef SSL_EXPERIMENTAL_PROXY - /* Configuration details for proxy operation */ - ssl_proto_t nProxyProtocol; - int bProxyVerify; - int nProxyVerifyDepth; - char *szProxyCACertificatePath; - char *szProxyCACertificateFile; - char *szProxyClientCertificateFile; - char *szProxyClientCertificatePath; - char *szProxyCipherSuite; - SSL_CTX *pSSLProxyCtx; - STACK_OF(X509_INFO) *skProxyClientCerts; -#endif -#ifdef SSL_VENDOR - ap_ctx *ctx; -#endif -} SSLSrvConfigRec; - -/* - * Define the mod_ssl per-directory configuration structure - * (i.e. the local configuration for all <Directory> - * and .htaccess contexts) - */ -typedef struct { - BOOL bSSLRequired; - array_header *aRequirement; - ssl_opt_t nOptions; - ssl_opt_t nOptionsAdd; - ssl_opt_t nOptionsDel; - char *szCipherSuite; - ssl_verify_t nVerifyClient; - int nVerifyDepth; -#ifdef SSL_EXPERIMENTAL_PERDIRCA - char *szCACertificatePath; - char *szCACertificateFile; -#endif -#ifdef SSL_VENDOR - ap_ctx *ctx; -#endif -} SSLDirConfigRec; - -/* - * function prototypes - */ - -/* API glue structures */ -extern module MODULE_VAR_EXPORT ssl_module; - -/* configuration handling */ -void ssl_config_global_create(void); -void ssl_config_global_fix(void); -BOOL ssl_config_global_isfixed(void); -void *ssl_config_server_create(pool *, server_rec *); -void *ssl_config_server_merge(pool *, void *, void *); -void *ssl_config_perdir_create(pool *, char *); -void *ssl_config_perdir_merge(pool *, void *, void *); -const char *ssl_cmd_SSLMutex(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLPassPhraseDialog(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLCryptoDevice(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLRandomSeed(cmd_parms *, char *, char *, char *, char *); -const char *ssl_cmd_SSLEngine(cmd_parms *, char *, int); -const char *ssl_cmd_SSLCipherSuite(cmd_parms *, SSLDirConfigRec *, char *); -const char *ssl_cmd_SSLCertificateFile(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLCACertificatePath(cmd_parms *, SSLDirConfigRec *, char *); -const char *ssl_cmd_SSLCACertificateFile(cmd_parms *, SSLDirConfigRec *, char *); -const char *ssl_cmd_SSLCARevocationPath(cmd_parms *, SSLDirConfigRec *, char *); -const char *ssl_cmd_SSLCARevocationFile(cmd_parms *, SSLDirConfigRec *, char *); -const char *ssl_cmd_SSLVerifyClient(cmd_parms *, SSLDirConfigRec *, char *); -const char *ssl_cmd_SSLVerifyDepth(cmd_parms *, SSLDirConfigRec *, char *); -const char *ssl_cmd_SSLSessionCache(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLSessionCacheTimeout(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLLog(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLLogLevel(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLProtocol(cmd_parms *, char *, const char *); -const char *ssl_cmd_SSLOptions(cmd_parms *, SSLDirConfigRec *, const char *); -const char *ssl_cmd_SSLRequireSSL(cmd_parms *, SSLDirConfigRec *, char *); -const char *ssl_cmd_SSLRequire(cmd_parms *, SSLDirConfigRec *, char *); -#ifdef SSL_EXPERIMENTAL_PROXY -const char *ssl_cmd_SSLProxyProtocol(cmd_parms *, char *, const char *); -const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLProxyVerify(cmd_parms *, char *, int); -const char *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *, char *, char *); -const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *, char *, char *); -#endif - -/* module initialization */ -void ssl_init_Module(server_rec *, pool *); -void ssl_init_SSLLibrary(void); -void ssl_init_Engine(server_rec *, pool *); -void ssl_init_TmpKeysHandle(int, server_rec *, pool *); -void ssl_init_ConfigureServer(server_rec *, pool *, SSLSrvConfigRec *); -void ssl_init_CheckServers(server_rec *, pool *); -STACK_OF(X509_NAME) - *ssl_init_FindCAList(server_rec *, pool *, char *, char *); -void ssl_init_Child(server_rec *, pool *); -void ssl_init_ChildKill(void *); -void ssl_init_ModuleKill(void *); - -/* Apache API hooks */ -void ssl_hook_AddModule(module *); -void ssl_hook_RemoveModule(module *); -char *ssl_hook_RewriteCommand(cmd_parms *, void *, const char *); -void ssl_hook_NewConnection(conn_rec *); -void ssl_hook_TimeoutConnection(int); -void ssl_hook_CloseConnection(conn_rec *); -int ssl_hook_Translate(request_rec *); -int ssl_hook_Auth(request_rec *); -int ssl_hook_UserCheck(request_rec *); -int ssl_hook_Access(request_rec *); -int ssl_hook_Fixup(request_rec *); -int ssl_hook_ReadReq(request_rec *); -int ssl_hook_Handler(request_rec *); - -/* OpenSSL callbacks */ -RSA *ssl_callback_TmpRSA(SSL *, int, int); -DH *ssl_callback_TmpDH(SSL *, int, int); -int ssl_callback_SSLVerify(int, X509_STORE_CTX *); -int ssl_callback_SSLVerify_CRL(int, X509_STORE_CTX *, server_rec *); -int ssl_callback_NewSessionCacheEntry(SSL *, SSL_SESSION *); -SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL *, unsigned char *, int, int *); -void ssl_callback_DelSessionCacheEntry(SSL_CTX *, SSL_SESSION *); -void ssl_callback_LogTracingState(SSL *, int, int); - -/* Session Cache Support */ -void ssl_scache_init(server_rec *, pool *); -void ssl_scache_kill(server_rec *); -BOOL ssl_scache_store(server_rec *, UCHAR *, int, time_t, SSL_SESSION *); -SSL_SESSION *ssl_scache_retrieve(server_rec *, UCHAR *, int); -void ssl_scache_remove(server_rec *, UCHAR *, int); -void ssl_scache_expire(server_rec *); -void ssl_scache_status(server_rec *, pool *, void (*)(char *, void *), void *); -char *ssl_scache_id2sz(UCHAR *, int); -void ssl_scache_dbm_init(server_rec *, pool *); -void ssl_scache_dbm_kill(server_rec *); -BOOL ssl_scache_dbm_store(server_rec *, UCHAR *, int, time_t, SSL_SESSION *); -SSL_SESSION *ssl_scache_dbm_retrieve(server_rec *, UCHAR *, int); -void ssl_scache_dbm_remove(server_rec *, UCHAR *, int); -void ssl_scache_dbm_expire(server_rec *); -void ssl_scache_dbm_status(server_rec *, pool *, void (*)(char *, void *), void *); -void ssl_scache_shmht_init(server_rec *, pool *); -void ssl_scache_shmht_kill(server_rec *); -BOOL ssl_scache_shmht_store(server_rec *, UCHAR *, int, time_t, SSL_SESSION *); -SSL_SESSION *ssl_scache_shmht_retrieve(server_rec *, UCHAR *, int); -void ssl_scache_shmht_remove(server_rec *, UCHAR *, int); -void ssl_scache_shmht_expire(server_rec *); -void ssl_scache_shmht_status(server_rec *, pool *, void (*)(char *, void *), void *); -void ssl_scache_shmcb_init(server_rec *, pool *); -void ssl_scache_shmcb_kill(server_rec *); -BOOL ssl_scache_shmcb_store(server_rec *, UCHAR *, int, time_t, SSL_SESSION *); -SSL_SESSION *ssl_scache_shmcb_retrieve(server_rec *, UCHAR *, int); -void ssl_scache_shmcb_remove(server_rec *, UCHAR *, int); -void ssl_scache_shmcb_expire(server_rec *); -void ssl_scache_shmcb_status(server_rec *, pool *, void (*)(char *, void *), void *); - -/* Pass Phrase Support */ -void ssl_pphrase_Handle(server_rec *, pool *); -int ssl_pphrase_Handle_CB(char *, int, int); - -/* Diffie-Hellman Parameter Support */ -DH *ssl_dh_GetTmpParam(int); -DH *ssl_dh_GetParamFromFile(char *); - -/* Data Structures */ -ssl_ds_array *ssl_ds_array_make(pool *, int); -BOOL ssl_ds_array_isempty(ssl_ds_array *); -void *ssl_ds_array_push(ssl_ds_array *); -void *ssl_ds_array_get(ssl_ds_array *, int); -void ssl_ds_array_wipeout(ssl_ds_array *); -void ssl_ds_array_kill(ssl_ds_array *); -ssl_ds_table *ssl_ds_table_make(pool *, int); -BOOL ssl_ds_table_isempty(ssl_ds_table *); -void *ssl_ds_table_push(ssl_ds_table *, char *); -void *ssl_ds_table_get(ssl_ds_table *, char *); -void ssl_ds_table_wipeout(ssl_ds_table *); -void ssl_ds_table_kill(ssl_ds_table *); - -/* Mutex Support */ -void ssl_mutex_init(server_rec *, pool *); -void ssl_mutex_reinit(server_rec *, pool *); -void ssl_mutex_on(server_rec *); -void ssl_mutex_off(server_rec *); -void ssl_mutex_kill(server_rec *s); -void ssl_mutex_file_create(server_rec *, pool *); -void ssl_mutex_file_open(server_rec *, pool *); -void ssl_mutex_file_remove(void *); -BOOL ssl_mutex_file_acquire(void); -BOOL ssl_mutex_file_release(void); -void ssl_mutex_sem_create(server_rec *, pool *); -void ssl_mutex_sem_open(server_rec *, pool *); -void ssl_mutex_sem_remove(void *); -BOOL ssl_mutex_sem_acquire(void); -BOOL ssl_mutex_sem_release(void); - -/* Logfile Support */ -void ssl_log_open(server_rec *, server_rec *, pool *); -BOOL ssl_log_applies(server_rec *, int); -void ssl_log(server_rec *, int, const char *, ...); -void ssl_die(void); - -/* Variables */ -void ssl_var_register(void); -void ssl_var_unregister(void); -char *ssl_var_lookup(pool *, server_rec *, conn_rec *, request_rec *, char *); - -/* I/O */ -void ssl_io_register(void); -void ssl_io_unregister(void); -long ssl_io_data_cb(BIO *, int, const char *, int, long, long); -#ifndef SSL_CONSERVATIVE -void ssl_io_suck(request_rec *, SSL *); -#endif - -/* PRNG */ -int ssl_rand_seed(server_rec *, pool *, ssl_rsctx_t, char *); - -/* Extensions */ -void ssl_ext_register(void); -void ssl_ext_unregister(void); - -/* Compatibility */ -#ifdef SSL_COMPAT -char *ssl_compat_directive(server_rec *, pool *, const char *); -void ssl_compat_variables(request_rec *); -#endif - -/* Utility Functions */ -char *ssl_util_server_root_relative(pool *, char *, char *); -char *ssl_util_vhostid(pool *, server_rec *); -void ssl_util_strupper(char *); -void ssl_util_uuencode(char *, const char *, BOOL); -void ssl_util_uuencode_binary(unsigned char *, const unsigned char *, int, BOOL); -FILE *ssl_util_ppopen(server_rec *, pool *, char *); -int ssl_util_ppopen_child(void *, child_info *); -void ssl_util_ppclose(server_rec *, pool *, FILE *); -char *ssl_util_readfilter(server_rec *, pool *, char *); -BOOL ssl_util_path_check(ssl_pathcheck_t, char *); -ssl_algo_t ssl_util_algotypeof(X509 *, EVP_PKEY *); -char *ssl_util_algotypestr(ssl_algo_t); -char *ssl_util_ptxtsub(pool *, const char *, const char *, char *); -void ssl_util_thread_setup(void); - -/* Vendor extension support */ -#if defined(SSL_VENDOR) && defined(SSL_VENDOR_OBJS) -void ssl_vendor_register(void); -void ssl_vendor_unregister(void); -#endif - -#endif /* MOD_SSL_H */ diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c deleted file mode 100644 index c47340b223..0000000000 --- a/modules/ssl/ssl_engine_config.c +++ /dev/null @@ -1,1093 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_engine_config.c -** Apache Configuration Directives -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - - /* ``Damned if you do, - damned if you don't.'' - -- Unknown */ -#include "mod_ssl.h" - - -/* _________________________________________________________________ -** -** Support for Global Configuration -** _________________________________________________________________ -*/ - -void ssl_hook_AddModule(module *m) -{ - if (m == &ssl_module) { - /* - * Announce us for the configuration files - */ - ap_add_config_define("MOD_SSL"); - - /* - * Link ourself into the Apache kernel - */ - ssl_var_register(); - ssl_ext_register(); - ssl_io_register(); -#if defined(SSL_VENDOR) && defined(SSL_VENDOR_OBJS) - ssl_vendor_register(); -#endif - } - return; -} - -void ssl_hook_RemoveModule(module *m) -{ - if (m == &ssl_module) { - /* - * Unlink ourself from the Apache kernel - */ - ssl_var_unregister(); - ssl_ext_unregister(); - ssl_io_unregister(); -#if defined(SSL_VENDOR) && defined(SSL_VENDOR_OBJS) - ssl_vendor_unregister(); -#endif - } - return; -} - -void ssl_config_global_create(void) -{ - pool *pPool; - SSLModConfigRec *mc; - - mc = ap_ctx_get(ap_global_ctx, "ssl_module"); - if (mc == NULL) { - /* - * allocate an own subpool which survives server restarts - */ - pPool = ap_make_sub_pool(NULL); - mc = (SSLModConfigRec *)ap_palloc(pPool, sizeof(SSLModConfigRec)); - mc->pPool = pPool; - mc->bFixed = FALSE; - - /* - * initialize per-module configuration - */ - mc->nInitCount = 0; - mc->nSessionCacheMode = SSL_SCMODE_UNSET; - mc->szSessionCacheDataFile = NULL; - mc->nSessionCacheDataSize = 0; - mc->pSessionCacheDataMM = NULL; - mc->tSessionCacheDataTable = NULL; - mc->nMutexMode = SSL_MUTEXMODE_UNSET; - mc->szMutexFile = NULL; - mc->nMutexFD = -1; - mc->nMutexSEMID = -1; - mc->aRandSeed = ap_make_array(pPool, 4, sizeof(ssl_randseed_t)); - mc->tPrivateKey = ssl_ds_table_make(pPool, sizeof(ssl_asn1_t)); - mc->tPublicCert = ssl_ds_table_make(pPool, sizeof(ssl_asn1_t)); - mc->tTmpKeys = ssl_ds_table_make(pPool, sizeof(ssl_asn1_t)); -#ifdef SSL_EXPERIMENTAL_ENGINE - mc->szCryptoDevice = NULL; -#endif - - (void)memset(mc->pTmpKeys, 0, SSL_TKPIDX_MAX*sizeof(void *)); - -#ifdef SSL_VENDOR - mc->ctx = ap_ctx_new(pPool); - ap_hook_use("ap::mod_ssl::vendor::config_global_create", - AP_HOOK_SIG2(void,ptr), AP_HOOK_MODE_ALL, mc); -#endif - - /* - * And push it into Apache's global context - */ - ap_ctx_set(ap_global_ctx, "ssl_module", mc); - } - return; -} - -void ssl_config_global_fix(void) -{ - SSLModConfigRec *mc = myModConfig(); - mc->bFixed = TRUE; - return; -} - -BOOL ssl_config_global_isfixed(void) -{ - SSLModConfigRec *mc = myModConfig(); - return (mc->bFixed); -} - - -/* _________________________________________________________________ -** -** Configuration handling -** _________________________________________________________________ -*/ - -/* - * Create per-server SSL configuration - */ -void *ssl_config_server_create(pool *p, server_rec *s) -{ - SSLSrvConfigRec *sc; - - ssl_config_global_create(); - - sc = ap_palloc(p, sizeof(SSLSrvConfigRec)); - sc->bEnabled = UNSET; - sc->szCACertificatePath = NULL; - sc->szCACertificateFile = NULL; - sc->szCertificateChain = NULL; - sc->szLogFile = NULL; - sc->szCipherSuite = NULL; - sc->nLogLevel = SSL_LOG_NONE; - sc->nVerifyDepth = UNSET; - sc->nVerifyClient = SSL_CVERIFY_UNSET; - sc->nSessionCacheTimeout = UNSET; - sc->nPassPhraseDialogType = SSL_PPTYPE_UNSET; - sc->szPassPhraseDialogPath = NULL; - sc->nProtocol = SSL_PROTOCOL_ALL; - sc->fileLogFile = NULL; - sc->pSSLCtx = NULL; - sc->szCARevocationPath = NULL; - sc->szCARevocationFile = NULL; - sc->pRevocationStore = NULL; - -#ifdef SSL_EXPERIMENTAL_PROXY - sc->nProxyVerifyDepth = UNSET; - sc->szProxyCACertificatePath = NULL; - sc->szProxyCACertificateFile = NULL; - sc->szProxyClientCertificateFile = NULL; - sc->szProxyClientCertificatePath = NULL; - sc->szProxyCipherSuite = NULL; - sc->nProxyProtocol = SSL_PROTOCOL_ALL & ~SSL_PROTOCOL_TLSV1; - sc->bProxyVerify = UNSET; - sc->pSSLProxyCtx = NULL; -#endif - - (void)memset(sc->szPublicCertFile, 0, SSL_AIDX_MAX*sizeof(char *)); - (void)memset(sc->szPrivateKeyFile, 0, SSL_AIDX_MAX*sizeof(char *)); - (void)memset(sc->pPublicCert, 0, SSL_AIDX_MAX*sizeof(X509 *)); - (void)memset(sc->pPrivateKey, 0, SSL_AIDX_MAX*sizeof(EVP_PKEY *)); - -#ifdef SSL_VENDOR - sc->ctx = ap_ctx_new(p); - ap_hook_use("ap::mod_ssl::vendor::config_server_create", - AP_HOOK_SIG4(void,ptr,ptr,ptr), AP_HOOK_MODE_ALL, - p, s, sc); -#endif - - return sc; -} - -/* - * Merge per-server SSL configurations - */ -void *ssl_config_server_merge(pool *p, void *basev, void *addv) -{ - SSLSrvConfigRec *base = (SSLSrvConfigRec *)basev; - SSLSrvConfigRec *add = (SSLSrvConfigRec *)addv; - SSLSrvConfigRec *new = (SSLSrvConfigRec *)ap_palloc(p, sizeof(SSLSrvConfigRec)); - int i; - - cfgMergeBool(bEnabled); - cfgMergeString(szCACertificatePath); - cfgMergeString(szCACertificateFile); - cfgMergeString(szCertificateChain); - cfgMergeString(szLogFile); - cfgMergeString(szCipherSuite); - cfgMerge(nLogLevel, SSL_LOG_NONE); - cfgMergeInt(nVerifyDepth); - cfgMerge(nVerifyClient, SSL_CVERIFY_UNSET); - cfgMergeInt(nSessionCacheTimeout); - cfgMerge(nPassPhraseDialogType, SSL_PPTYPE_UNSET); - cfgMergeString(szPassPhraseDialogPath); - cfgMerge(nProtocol, SSL_PROTOCOL_ALL); - cfgMerge(fileLogFile, NULL); - cfgMerge(pSSLCtx, NULL); - cfgMerge(szCARevocationPath, NULL); - cfgMerge(szCARevocationFile, NULL); - cfgMerge(pRevocationStore, NULL); - - for (i = 0; i < SSL_AIDX_MAX; i++) { - cfgMergeString(szPublicCertFile[i]); - cfgMergeString(szPrivateKeyFile[i]); - cfgMerge(pPublicCert[i], NULL); - cfgMerge(pPrivateKey[i], NULL); - } - -#ifdef SSL_VENDOR - cfgMergeCtx(ctx); - ap_hook_use("ap::mod_ssl::vendor::config_server_merge", - AP_HOOK_SIG5(void,ptr,ptr,ptr,ptr), AP_HOOK_MODE_ALL, - p, base, add, new); -#endif - -#ifdef SSL_EXPERIMENTAL_PROXY - cfgMergeInt(nProxyVerifyDepth); - cfgMergeString(szProxyCACertificatePath); - cfgMergeString(szProxyCACertificateFile); - cfgMergeString(szProxyClientCertificateFile); - cfgMergeString(szProxyClientCertificatePath); - cfgMergeString(szProxyCipherSuite); - cfgMerge(nProxyProtocol, (SSL_PROTOCOL_ALL & ~SSL_PROTOCOL_TLSV1)); - cfgMergeBool(bProxyVerify); - cfgMerge(pSSLProxyCtx, NULL); -#endif - - return new; -} - -/* - * Create per-directory SSL configuration - */ -void *ssl_config_perdir_create(pool *p, char *dir) -{ - SSLDirConfigRec *dc = ap_palloc(p, sizeof(SSLDirConfigRec)); - - dc->bSSLRequired = FALSE; - dc->aRequirement = ap_make_array(p, 4, sizeof(ssl_require_t)); - dc->nOptions = SSL_OPT_NONE|SSL_OPT_RELSET; - dc->nOptionsAdd = SSL_OPT_NONE; - dc->nOptionsDel = SSL_OPT_NONE; - - dc->szCipherSuite = NULL; - dc->nVerifyClient = SSL_CVERIFY_UNSET; - dc->nVerifyDepth = UNSET; -#ifdef SSL_EXPERIMENTAL_PERDIRCA - dc->szCACertificatePath = NULL; - dc->szCACertificateFile = NULL; -#endif - -#ifdef SSL_VENDOR - dc->ctx = ap_ctx_new(p); - ap_hook_use("ap::mod_ssl::vendor::config_perdir_create", - AP_HOOK_SIG4(void,ptr,ptr,ptr), AP_HOOK_MODE_ALL, - p, dir, dc); -#endif - - return dc; -} - -/* - * Merge per-directory SSL configurations - */ -void *ssl_config_perdir_merge(pool *p, void *basev, void *addv) -{ - SSLDirConfigRec *base = (SSLDirConfigRec *)basev; - SSLDirConfigRec *add = (SSLDirConfigRec *)addv; - SSLDirConfigRec *new = (SSLDirConfigRec *)ap_palloc(p, - sizeof(SSLDirConfigRec)); - - cfgMerge(bSSLRequired, FALSE); - cfgMergeArray(aRequirement); - - if (add->nOptions & SSL_OPT_RELSET) { - new->nOptionsAdd = (base->nOptionsAdd & ~(add->nOptionsDel)) | add->nOptionsAdd; - new->nOptionsDel = (base->nOptionsDel & ~(add->nOptionsAdd)) | add->nOptionsDel; - new->nOptions = (base->nOptions & ~(new->nOptionsDel)) | new->nOptionsAdd; - } - else { - new->nOptions = add->nOptions; - new->nOptionsAdd = add->nOptionsAdd; - new->nOptionsDel = add->nOptionsDel; - } - - cfgMergeString(szCipherSuite); - cfgMerge(nVerifyClient, SSL_CVERIFY_UNSET); - cfgMergeInt(nVerifyDepth); -#ifdef SSL_EXPERIMENTAL_PERDIRCA - cfgMergeString(szCACertificatePath); - cfgMergeString(szCACertificateFile); -#endif - -#ifdef SSL_VENDOR - cfgMergeCtx(ctx); - ap_hook_use("ap::mod_ssl::vendor::config_perdir_merge", - AP_HOOK_SIG5(void,ptr,ptr,ptr,ptr), AP_HOOK_MODE_ALL, - p, base, add, new); -#endif - - return new; -} - -/* - * Directive Rewriting - */ - -char *ssl_hook_RewriteCommand(cmd_parms *cmd, void *config, const char *cmd_line) -{ -#ifdef SSL_COMPAT - return ssl_compat_directive(cmd->server, cmd->pool, cmd_line); -#else - return NULL; -#endif -} - -/* - * Configuration functions for particular directives - */ - -const char *ssl_cmd_SSLMutex( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - const char *err; - SSLModConfigRec *mc = myModConfig(); - - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY)) != NULL) - return err; - if (ssl_config_global_isfixed()) - return NULL; - if (strcEQ(arg, "none")) { - mc->nMutexMode = SSL_MUTEXMODE_NONE; - } - else if (strlen(arg) > 5 && strcEQn(arg, "file:", 5)) { -#ifndef WIN32 - mc->nMutexMode = SSL_MUTEXMODE_FILE; - mc->szMutexFile = ap_psprintf(mc->pPool, "%s.%lu", - ssl_util_server_root_relative(cmd->pool, "mutex", arg+5), - (unsigned long)getpid()); -#else - return "SSLMutex: Lockfiles not available on this platform"; -#endif - } - else if (strcEQ(arg, "sem")) { -#ifdef SSL_CAN_USE_SEM - mc->nMutexMode = SSL_MUTEXMODE_SEM; -#else - return "SSLMutex: Semaphores not available on this platform"; -#endif - } - else - return "SSLMutex: Invalid argument"; - return NULL; -} - -const char *ssl_cmd_SSLPassPhraseDialog( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - const char *err; - - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY)) != NULL) - return err; - if (strcEQ(arg, "builtin")) { - sc->nPassPhraseDialogType = SSL_PPTYPE_BUILTIN; - sc->szPassPhraseDialogPath = NULL; - } - else if (strlen(arg) > 5 && strEQn(arg, "exec:", 5)) { - sc->nPassPhraseDialogType = SSL_PPTYPE_FILTER; - sc->szPassPhraseDialogPath = ssl_util_server_root_relative(cmd->pool, "dialog", arg+5); - if (!ssl_util_path_check(SSL_PCM_EXISTS, sc->szPassPhraseDialogPath)) - return ap_pstrcat(cmd->pool, "SSLPassPhraseDialog: file '", - sc->szPassPhraseDialogPath, "' not exists", NULL); - } - else - return "SSLPassPhraseDialog: Invalid argument"; - return NULL; -} - -#ifdef SSL_EXPERIMENTAL_ENGINE -const char *ssl_cmd_SSLCryptoDevice( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - SSLModConfigRec *mc = myModConfig(); - const char *err; - ENGINE *e; -#if SSL_LIBRARY_VERSION >= 0x00907000 - static int loaded_engines = FALSE; - - /* early loading to make sure the engines are already - available for ENGINE_by_id() above... */ - if (!loaded_engines) { - ENGINE_load_builtin_engines(); - loaded_engines = TRUE; - } -#endif - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY)) != NULL) - return err; - if (strcEQ(arg, "builtin")) { - mc->szCryptoDevice = NULL; - } - else if ((e = ENGINE_by_id(arg)) != NULL) { - mc->szCryptoDevice = arg; - ENGINE_free(e); - } - else - return "SSLCryptoDevice: Invalid argument"; - return NULL; -} -#endif - -const char *ssl_cmd_SSLRandomSeed( - cmd_parms *cmd, char *struct_ptr, char *arg1, char *arg2, char *arg3) -{ - SSLModConfigRec *mc = myModConfig(); - const char *err; - ssl_randseed_t *pRS; - - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY)) != NULL) - return err; - if (ssl_config_global_isfixed()) - return NULL; - pRS = ap_push_array(mc->aRandSeed); - if (strcEQ(arg1, "startup")) - pRS->nCtx = SSL_RSCTX_STARTUP; - else if (strcEQ(arg1, "connect")) - pRS->nCtx = SSL_RSCTX_CONNECT; - else - return ap_pstrcat(cmd->pool, "SSLRandomSeed: " - "invalid context: `", arg1, "'"); - if (strlen(arg2) > 5 && strEQn(arg2, "file:", 5)) { - pRS->nSrc = SSL_RSSRC_FILE; - pRS->cpPath = ap_pstrdup(mc->pPool, ssl_util_server_root_relative(cmd->pool, "random", arg2+5)); - } - else if (strlen(arg2) > 5 && strEQn(arg2, "exec:", 5)) { - pRS->nSrc = SSL_RSSRC_EXEC; - pRS->cpPath = ap_pstrdup(mc->pPool, ssl_util_server_root_relative(cmd->pool, "random", arg2+5)); - } -#if SSL_LIBRARY_VERSION >= 0x00905100 - else if (strlen(arg2) > 4 && strEQn(arg2, "egd:", 4)) { - pRS->nSrc = SSL_RSSRC_EGD; - pRS->cpPath = ap_pstrdup(mc->pPool, ssl_util_server_root_relative(cmd->pool, "random", arg2+4)); - } -#endif - else if (strcEQ(arg2, "builtin")) { - pRS->nSrc = SSL_RSSRC_BUILTIN; - pRS->cpPath = NULL; - } - else { - pRS->nSrc = SSL_RSSRC_FILE; - pRS->cpPath = ap_pstrdup(mc->pPool, ssl_util_server_root_relative(cmd->pool, "random", arg2)); - } - if (pRS->nSrc != SSL_RSSRC_BUILTIN) - if (!ssl_util_path_check(SSL_PCM_EXISTS, pRS->cpPath)) - return ap_pstrcat(cmd->pool, "SSLRandomSeed: source path '", - pRS->cpPath, "' not exists", NULL); - if (arg3 == NULL) - pRS->nBytes = 0; /* read whole file */ - else { - if (pRS->nSrc == SSL_RSSRC_BUILTIN) - return "SSLRandomSeed: byte specification not " - "allowed for builtin seed source"; - pRS->nBytes = atoi(arg3); - if (pRS->nBytes < 0) - return "SSLRandomSeed: invalid number of bytes specified"; - } - return NULL; -} - -const char *ssl_cmd_SSLEngine( - cmd_parms *cmd, char *struct_ptr, int flag) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - - sc->bEnabled = (flag ? TRUE : FALSE); - return NULL; -} - -const char *ssl_cmd_SSLCipherSuite( - cmd_parms *cmd, SSLDirConfigRec *dc, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - - if (cmd->path == NULL || dc == NULL) - sc->szCipherSuite = arg; - else - dc->szCipherSuite = arg; - return NULL; -} - -const char *ssl_cmd_SSLCertificateFile( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - char *cpPath; - int i; - - cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg); - if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath)) - return ap_pstrcat(cmd->pool, "SSLCertificateFile: file '", - cpPath, "' not exists or empty", NULL); - for (i = 0; i < SSL_AIDX_MAX && sc->szPublicCertFile[i] != NULL; i++) - ; - if (i == SSL_AIDX_MAX) - return ap_psprintf(cmd->pool, "SSLCertificateFile: only up to %d " - "different certificates per virtual host allowed", - SSL_AIDX_MAX); - sc->szPublicCertFile[i] = cpPath; - return NULL; -} - -const char *ssl_cmd_SSLCertificateKeyFile( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - char *cpPath; - int i; - - cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg); - if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath)) - return ap_pstrcat(cmd->pool, "SSLCertificateKeyFile: file '", - cpPath, "' not exists or empty", NULL); - for (i = 0; i < SSL_AIDX_MAX && sc->szPrivateKeyFile[i] != NULL; i++) - ; - if (i == SSL_AIDX_MAX) - return ap_psprintf(cmd->pool, "SSLCertificateKeyFile: only up to %d " - "different private keys per virtual host allowed", - SSL_AIDX_MAX); - sc->szPrivateKeyFile[i] = cpPath; - return NULL; -} - -const char *ssl_cmd_SSLCertificateChainFile( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - char *cpPath; - - cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg); - if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath)) - return ap_pstrcat(cmd->pool, "SSLCertificateChainFile: file '", - cpPath, "' not exists or empty", NULL); - sc->szCertificateChain = cpPath; - return NULL; -} - -const char *ssl_cmd_SSLCACertificatePath( - cmd_parms *cmd, SSLDirConfigRec *dc, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - char *cpPath; - - cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg); - if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISDIR, cpPath)) - return ap_pstrcat(cmd->pool, "SSLCACertificatePath: directory '", - cpPath, "' not exists", NULL); -#ifdef SSL_EXPERIMENTAL_PERDIRCA - if (cmd->path == NULL || dc == NULL) - sc->szCACertificatePath = cpPath; - else - dc->szCACertificatePath = cpPath; -#else - sc->szCACertificatePath = cpPath; -#endif - return NULL; -} - -const char *ssl_cmd_SSLCACertificateFile( - cmd_parms *cmd, SSLDirConfigRec *dc, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - char *cpPath; - - cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg); - if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath)) - return ap_pstrcat(cmd->pool, "SSLCACertificateFile: file '", - cpPath, "' not exists or empty", NULL); -#ifdef SSL_EXPERIMENTAL_PERDIRCA - if (cmd->path == NULL || dc == NULL) - sc->szCACertificateFile = cpPath; - else - dc->szCACertificateFile = cpPath; -#else - sc->szCACertificateFile = cpPath; -#endif - return NULL; -} - -const char *ssl_cmd_SSLCARevocationPath( - cmd_parms *cmd, SSLDirConfigRec *dc, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - char *cpPath; - - cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg); - if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISDIR, cpPath)) - return ap_pstrcat(cmd->pool, "SSLCARecocationPath: directory '", - cpPath, "' not exists", NULL); - sc->szCARevocationPath = cpPath; - return NULL; -} - -const char *ssl_cmd_SSLCARevocationFile( - cmd_parms *cmd, SSLDirConfigRec *dc, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - char *cpPath; - - cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg); - if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath)) - return ap_pstrcat(cmd->pool, "SSLCARevocationFile: file '", - cpPath, "' not exists or empty", NULL); - sc->szCARevocationFile = cpPath; - return NULL; -} - -const char *ssl_cmd_SSLVerifyClient( - cmd_parms *cmd, SSLDirConfigRec *dc, char *level) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - ssl_verify_t id; - - if (strEQ(level, "0") || strcEQ(level, "none")) - id = SSL_CVERIFY_NONE; - else if (strEQ(level, "1") || strcEQ(level, "optional")) - id = SSL_CVERIFY_OPTIONAL; - else if (strEQ(level, "2") || strcEQ(level, "require")) - id = SSL_CVERIFY_REQUIRE; - else if (strEQ(level, "3") || strcEQ(level, "optional_no_ca")) - id = SSL_CVERIFY_OPTIONAL_NO_CA; - else - return "SSLVerifyClient: Invalid argument"; - if (cmd->path == NULL || dc == NULL) - sc->nVerifyClient = id; - else - dc->nVerifyClient = id; - return NULL; -} - -const char *ssl_cmd_SSLVerifyDepth( - cmd_parms *cmd, SSLDirConfigRec *dc, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - int d; - - d = atoi(arg); - if (d < 0) - return "SSLVerifyDepth: Invalid argument"; - if (cmd->path == NULL || dc == NULL) - sc->nVerifyDepth = d; - else - dc->nVerifyDepth = d; - return NULL; -} - -const char *ssl_cmd_SSLSessionCache( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - const char *err; - SSLModConfigRec *mc = myModConfig(); - char *cp, *cp2; - int maxsize; - - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY)) != NULL) - return err; - if (ssl_config_global_isfixed()) - return NULL; - if (strcEQ(arg, "none")) { - mc->nSessionCacheMode = SSL_SCMODE_NONE; - mc->szSessionCacheDataFile = NULL; - } - else if (strlen(arg) > 4 && strcEQn(arg, "dbm:", 4)) { - mc->nSessionCacheMode = SSL_SCMODE_DBM; - mc->szSessionCacheDataFile = ap_pstrdup(mc->pPool, - ssl_util_server_root_relative(cmd->pool, "scache", arg+4)); - } - else if ( (strlen(arg) > 4 && strcEQn(arg, "shm:", 4)) - || (strlen(arg) > 6 && strcEQn(arg, "shmht:", 6))) { - if (!ap_mm_useable()) - return "SSLSessionCache: shared memory cache not useable on this platform"; - mc->nSessionCacheMode = SSL_SCMODE_SHMHT; - cp = strchr(arg, ':'); - mc->szSessionCacheDataFile = ap_pstrdup(mc->pPool, - ssl_util_server_root_relative(cmd->pool, "scache", cp+1)); - mc->tSessionCacheDataTable = NULL; - mc->nSessionCacheDataSize = 1024*512; /* 512KB */ - if ((cp = strchr(mc->szSessionCacheDataFile, '(')) != NULL) { - *cp++ = NUL; - if ((cp2 = strchr(cp, ')')) == NULL) - return "SSLSessionCache: Invalid argument: no closing parenthesis"; - *cp2 = NUL; - mc->nSessionCacheDataSize = atoi(cp); - if (mc->nSessionCacheDataSize <= 8192) - return "SSLSessionCache: Invalid argument: size has to be >= 8192 bytes"; - maxsize = ap_mm_core_maxsegsize(); - if (mc->nSessionCacheDataSize >= maxsize) - return ap_psprintf(cmd->pool, "SSLSessionCache: Invalid argument: " - "size has to be < %d bytes on this platform", maxsize); - } - } - else if (strlen(arg) > 6 && strcEQn(arg, "shmcb:", 6)) { - if (!ap_mm_useable()) - return "SSLSessionCache: shared memory cache not useable on this platform"; - mc->nSessionCacheMode = SSL_SCMODE_SHMCB; - mc->szSessionCacheDataFile = ap_pstrdup(mc->pPool, - ap_server_root_relative(cmd->pool, arg+6)); - mc->tSessionCacheDataTable = NULL; - mc->nSessionCacheDataSize = 1024*512; /* 512KB */ - if ((cp = strchr(mc->szSessionCacheDataFile, '(')) != NULL) { - *cp++ = NUL; - if ((cp2 = strchr(cp, ')')) == NULL) - return "SSLSessionCache: Invalid argument: no closing parenthesis"; - *cp2 = NUL; - mc->nSessionCacheDataSize = atoi(cp); - if (mc->nSessionCacheDataSize <= 8192) - return "SSLSessionCache: Invalid argument: size has to be >= 8192 bytes"; - maxsize = ap_mm_core_maxsegsize(); - if (mc->nSessionCacheDataSize >= maxsize) - return ap_psprintf(cmd->pool, "SSLSessionCache: Invalid argument: " - "size has to be < %d bytes on this platform", maxsize); - } - } - else -#ifdef SSL_VENDOR - if (!ap_hook_use("ap::mod_ssl::vendor::cmd_sslsessioncache", - AP_HOOK_SIG4(void,ptr,ptr,ptr), AP_HOOK_MODE_ALL, - cmd, arg, mc)) -#endif - return "SSLSessionCache: Invalid argument"; - return NULL; -} - -const char *ssl_cmd_SSLSessionCacheTimeout( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - - sc->nSessionCacheTimeout = atoi(arg); - if (sc->nSessionCacheTimeout < 0) - return "SSLSessionCacheTimeout: Invalid argument"; - return NULL; -} - -const char *ssl_cmd_SSLLog( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - const char *err; - - if ((err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_DIRECTORY - |NOT_IN_LOCATION|NOT_IN_FILES )) != NULL) - return err; - sc->szLogFile = arg; - return NULL; -} - -const char *ssl_cmd_SSLLogLevel( - cmd_parms *cmd, char *struct_ptr, char *level) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - const char *err; - - if ((err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_DIRECTORY - |NOT_IN_LOCATION|NOT_IN_FILES )) != NULL) - return err; - if (strcEQ(level, "none")) - sc->nLogLevel = SSL_LOG_NONE; - else if (strcEQ(level, "error")) - sc->nLogLevel = SSL_LOG_ERROR; - else if (strcEQ(level, "warn")) - sc->nLogLevel = SSL_LOG_WARN; - else if (strcEQ(level, "info")) - sc->nLogLevel = SSL_LOG_INFO; - else if (strcEQ(level, "trace")) - sc->nLogLevel = SSL_LOG_TRACE; - else if (strcEQ(level, "debug")) - sc->nLogLevel = SSL_LOG_DEBUG; - else - return "SSLLogLevel: Invalid argument"; - return NULL; -} - -const char *ssl_cmd_SSLOptions( - cmd_parms *cmd, SSLDirConfigRec *dc, const char *cpLine) -{ - ssl_opt_t opt; - int first; - char action; - char *w; - - first = TRUE; - while (cpLine[0] != NUL) { - w = ap_getword_conf(cmd->pool, &cpLine); - action = NUL; - - if (*w == '+' || *w == '-') { - action = *(w++); - } - else if (first) { - dc->nOptions = SSL_OPT_NONE; - first = FALSE; - } - - if (strcEQ(w, "StdEnvVars")) - opt = SSL_OPT_STDENVVARS; - else if (strcEQ(w, "CompatEnvVars")) - opt = SSL_OPT_COMPATENVVARS; - else if (strcEQ(w, "ExportCertData")) - opt = SSL_OPT_EXPORTCERTDATA; - else if (strcEQ(w, "FakeBasicAuth")) - opt = SSL_OPT_FAKEBASICAUTH; - else if (strcEQ(w, "StrictRequire")) - opt = SSL_OPT_STRICTREQUIRE; - else if (strcEQ(w, "OptRenegotiate")) - opt = SSL_OPT_OPTRENEGOTIATE; - else - return ap_pstrcat(cmd->pool, "SSLOptions: Illegal option '", w, "'", NULL); - - if (action == '-') { - dc->nOptionsAdd &= ~opt; - dc->nOptionsDel |= opt; - dc->nOptions &= ~opt; - } - else if (action == '+') { - dc->nOptionsAdd |= opt; - dc->nOptionsDel &= ~opt; - dc->nOptions |= opt; - } - else { - dc->nOptions = opt; - dc->nOptionsAdd = opt; - dc->nOptionsDel = SSL_OPT_NONE; - } - } - return NULL; -} - -const char *ssl_cmd_SSLRequireSSL( - cmd_parms *cmd, SSLDirConfigRec *dc, char *cipher) -{ - dc->bSSLRequired = TRUE; - return NULL; -} - -const char *ssl_cmd_SSLRequire( - cmd_parms *cmd, SSLDirConfigRec *dc, char *cpExpr) -{ - ssl_expr *mpExpr; - ssl_require_t *pReqRec; - - if ((mpExpr = ssl_expr_comp(cmd->pool, cpExpr)) == NULL) - return ap_pstrcat(cmd->pool, "SSLRequire: ", ssl_expr_get_error(), NULL); - pReqRec = ap_push_array(dc->aRequirement); - pReqRec->cpExpr = ap_pstrdup(cmd->pool, cpExpr); - pReqRec->mpExpr = mpExpr; - return NULL; -} - -const char *ssl_cmd_SSLProtocol( - cmd_parms *cmd, char *struct_ptr, const char *opt) -{ - SSLSrvConfigRec *sc; - ssl_proto_t options, thisopt; - char action; - char *w; - - sc = mySrvConfig(cmd->server); - options = SSL_PROTOCOL_NONE; - while (opt[0] != NUL) { - w = ap_getword_conf(cmd->pool, &opt); - - action = NUL; - if (*w == '+' || *w == '-') - action = *(w++); - - if (strcEQ(w, "SSLv2")) - thisopt = SSL_PROTOCOL_SSLV2; - else if (strcEQ(w, "SSLv3")) - thisopt = SSL_PROTOCOL_SSLV3; - else if (strcEQ(w, "TLSv1")) - thisopt = SSL_PROTOCOL_TLSV1; - else if (strcEQ(w, "all")) - thisopt = SSL_PROTOCOL_ALL; - else - return ap_pstrcat(cmd->pool, "SSLProtocol: Illegal protocol '", w, "'", NULL); - - if (action == '-') - options &= ~thisopt; - else if (action == '+') - options |= thisopt; - else - options = thisopt; - } - sc->nProtocol = options; - return NULL; -} - -#ifdef SSL_EXPERIMENTAL_PROXY - -const char *ssl_cmd_SSLProxyProtocol( - cmd_parms *cmd, char *struct_ptr, const char *opt) -{ - SSLSrvConfigRec *sc; - ssl_proto_t options, thisopt; - char action; - char *w; - - sc = mySrvConfig(cmd->server); - options = SSL_PROTOCOL_NONE; - while (opt[0] != NUL) { - w = ap_getword_conf(cmd->pool, &opt); - - action = NUL; - if (*w == '+' || *w == '-') - action = *(w++); - - if (strcEQ(w, "SSLv2")) - thisopt = SSL_PROTOCOL_SSLV2; - else if (strcEQ(w, "SSLv3")) - thisopt = SSL_PROTOCOL_SSLV3; - else if (strcEQ(w, "TLSv1")) - thisopt = SSL_PROTOCOL_TLSV1; - else if (strcEQ(w, "all")) - thisopt = SSL_PROTOCOL_ALL; - else - return ap_pstrcat(cmd->pool, "SSLProxyProtocol: " - "Illegal protocol '", w, "'", NULL); - if (action == '-') - options &= ~thisopt; - else if (action == '+') - options |= thisopt; - else - options = thisopt; - } - sc->nProxyProtocol = options; - return NULL; -} - -const char *ssl_cmd_SSLProxyCipherSuite( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - - sc->szProxyCipherSuite = arg; - return NULL; -} - -const char *ssl_cmd_SSLProxyVerify( - cmd_parms *cmd, char *struct_ptr, int flag) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - - sc->bProxyVerify = (flag ? TRUE : FALSE); - return NULL; -} - -const char *ssl_cmd_SSLProxyVerifyDepth( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - int d; - - d = atoi(arg); - if (d < 0) - return "SSLProxyVerifyDepth: Invalid argument"; - sc->nProxyVerifyDepth = d; - return NULL; -} - -const char *ssl_cmd_SSLProxyCACertificateFile( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - char *cpPath; - - cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg); - if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath)) - return ap_pstrcat(cmd->pool, "SSLProxyCACertificateFile: file '", - cpPath, "' not exists or empty", NULL); - sc->szProxyCACertificateFile = cpPath; - return NULL; -} - -const char *ssl_cmd_SSLProxyCACertificatePath( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - char *cpPath; - - cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg); - if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISDIR, cpPath)) - return ap_pstrcat(cmd->pool, "SSLProxyCACertificatePath: directory '", - cpPath, "' does not exists", NULL); - sc->szProxyCACertificatePath = cpPath; - return NULL; -} - -const char *ssl_cmd_SSLProxyMachineCertificateFile( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - char *cpPath; - - cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg); - if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath)) - return ap_pstrcat(cmd->pool, "SSLProxyMachineCertFile: file '", - cpPath, "' not exists or empty", NULL); - sc->szProxyClientCertificateFile = cpPath; - return NULL; -} - -const char *ssl_cmd_SSLProxyMachineCertificatePath( - cmd_parms *cmd, char *struct_ptr, char *arg) -{ - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - char *cpPath; - - cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg); - if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISDIR, cpPath)) - return ap_pstrcat(cmd->pool, "SSLProxyMachineCertPath: directory '", - cpPath, "' does not exists", NULL); - sc->szProxyClientCertificatePath = cpPath; - return NULL; -} - -#endif /* SSL_EXPERIMENTAL_PROXY */ - diff --git a/modules/ssl/ssl_engine_dh.c b/modules/ssl/ssl_engine_dh.c deleted file mode 100644 index 84f49e6657..0000000000 --- a/modules/ssl/ssl_engine_dh.c +++ /dev/null @@ -1,255 +0,0 @@ -#if 0 -=pod -#endif -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_engine_dh.c -** Diffie-Hellman Built-in Temporary Parameters -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - -#include "mod_ssl.h" - -/* ----BEGIN GENERATED SECTION-------- */ - -/* -** Diffie-Hellman-Parameters: (512 bit) -** prime: -** 00:d4:bc:d5:24:06:f6:9b:35:99:4b:88:de:5d:b8: -** 96:82:c8:15:7f:62:d8:f3:36:33:ee:57:72:f1:1f: -** 05:ab:22:d6:b5:14:5b:9f:24:1e:5a:cc:31:ff:09: -** 0a:4b:c7:11:48:97:6f:76:79:50:94:e7:1e:79:03: -** 52:9f:5a:82:4b -** generator: 2 (0x2) -** Diffie-Hellman-Parameters: (1024 bit) -** prime: -** 00:e6:96:9d:3d:49:5b:e3:2c:7c:f1:80:c3:bd:d4: -** 79:8e:91:b7:81:82:51:bb:05:5e:2a:20:64:90:4a: -** 79:a7:70:fa:15:a2:59:cb:d5:23:a6:a6:ef:09:c4: -** 30:48:d5:a2:2f:97:1f:3c:20:12:9b:48:00:0e:6e: -** dd:06:1c:bc:05:3e:37:1d:79:4e:53:27:df:61:1e: -** bb:be:1b:ac:9b:5c:60:44:cf:02:3d:76:e0:5e:ea: -** 9b:ad:99:1b:13:a6:3c:97:4e:9e:f1:83:9e:b5:db: -** 12:51:36:f7:26:2e:56:a8:87:15:38:df:d8:23:c6: -** 50:50:85:e2:1f:0d:d5:c8:6b -** generator: 2 (0x2) -*/ - -static unsigned char dh512_p[] = -{ - 0xD4, 0xBC, 0xD5, 0x24, 0x06, 0xF6, 0x9B, 0x35, 0x99, 0x4B, 0x88, 0xDE, - 0x5D, 0xB8, 0x96, 0x82, 0xC8, 0x15, 0x7F, 0x62, 0xD8, 0xF3, 0x36, 0x33, - 0xEE, 0x57, 0x72, 0xF1, 0x1F, 0x05, 0xAB, 0x22, 0xD6, 0xB5, 0x14, 0x5B, - 0x9F, 0x24, 0x1E, 0x5A, 0xCC, 0x31, 0xFF, 0x09, 0x0A, 0x4B, 0xC7, 0x11, - 0x48, 0x97, 0x6F, 0x76, 0x79, 0x50, 0x94, 0xE7, 0x1E, 0x79, 0x03, 0x52, - 0x9F, 0x5A, 0x82, 0x4B, -}; -static unsigned char dh512_g[] = -{ - 0x02, -}; - -static DH *get_dh512() -{ - DH *dh; - - if ((dh = DH_new()) == NULL) - return (NULL); - dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL); - dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL); - if ((dh->p == NULL) || (dh->g == NULL)) - return (NULL); - return (dh); -} -static unsigned char dh1024_p[] = -{ - 0xE6, 0x96, 0x9D, 0x3D, 0x49, 0x5B, 0xE3, 0x2C, 0x7C, 0xF1, 0x80, 0xC3, - 0xBD, 0xD4, 0x79, 0x8E, 0x91, 0xB7, 0x81, 0x82, 0x51, 0xBB, 0x05, 0x5E, - 0x2A, 0x20, 0x64, 0x90, 0x4A, 0x79, 0xA7, 0x70, 0xFA, 0x15, 0xA2, 0x59, - 0xCB, 0xD5, 0x23, 0xA6, 0xA6, 0xEF, 0x09, 0xC4, 0x30, 0x48, 0xD5, 0xA2, - 0x2F, 0x97, 0x1F, 0x3C, 0x20, 0x12, 0x9B, 0x48, 0x00, 0x0E, 0x6E, 0xDD, - 0x06, 0x1C, 0xBC, 0x05, 0x3E, 0x37, 0x1D, 0x79, 0x4E, 0x53, 0x27, 0xDF, - 0x61, 0x1E, 0xBB, 0xBE, 0x1B, 0xAC, 0x9B, 0x5C, 0x60, 0x44, 0xCF, 0x02, - 0x3D, 0x76, 0xE0, 0x5E, 0xEA, 0x9B, 0xAD, 0x99, 0x1B, 0x13, 0xA6, 0x3C, - 0x97, 0x4E, 0x9E, 0xF1, 0x83, 0x9E, 0xB5, 0xDB, 0x12, 0x51, 0x36, 0xF7, - 0x26, 0x2E, 0x56, 0xA8, 0x87, 0x15, 0x38, 0xDF, 0xD8, 0x23, 0xC6, 0x50, - 0x50, 0x85, 0xE2, 0x1F, 0x0D, 0xD5, 0xC8, 0x6B, -}; -static unsigned char dh1024_g[] = -{ - 0x02, -}; - -static DH *get_dh1024() -{ - DH *dh; - - if ((dh = DH_new()) == NULL) - return (NULL); - dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); - dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); - if ((dh->p == NULL) || (dh->g == NULL)) - return (NULL); - return (dh); -} -/* ----END GENERATED SECTION---------- */ - -DH *ssl_dh_GetTmpParam(int nKeyLen) -{ - DH *dh; - - if (nKeyLen == 512) - dh = get_dh512(); - else if (nKeyLen == 1024) - dh = get_dh1024(); - else - dh = get_dh1024(); - return dh; -} - -DH *ssl_dh_GetParamFromFile(char *file) -{ - DH *dh = NULL; - BIO *bio; - - if ((bio = BIO_new_file(file, "r")) == NULL) - return NULL; -#if SSL_LIBRARY_VERSION < 0x00904000 - dh = PEM_read_bio_DHparams(bio, NULL, NULL); -#else - dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); -#endif - BIO_free(bio); - return (dh); -} - -/* -=cut -## -## Embedded Perl script for generating the temporary DH parameters -## - -require 5.003; -use strict; - -# configuration -my $file = $0; -my $begin = '----BEGIN GENERATED SECTION--------'; -my $end = '----END GENERATED SECTION----------'; - -# read ourself and keep a backup -open(FP, "<$file") || die; -my $source = ''; -$source .= $_ while (<FP>); -close(FP); -open(FP, ">$file.bak") || die; -print FP $source; -close(FP); - -# generate the DH parameters -print "1. Generate 512 and 1024 bit Diffie-Hellman parameters (p, g)\n"; -my $rand = ''; -foreach $file (qw(/var/log/messages /var/adm/messages - /kernel /vmunix /vmlinuz /etc/hosts /etc/resolv.conf)) { - if (-f $file) { - $rand = $file if ($rand eq ''); - $rand .= ":$file" if ($rand ne ''); - } -} -$rand = "-rand $rand" if ($rand ne ''); -system("openssl gendh $rand -out dh512.pem 512"); -system("openssl gendh $rand -out dh1024.pem 1024"); - -# generate DH param info -my $dhinfo = ''; -open(FP, "openssl dh -noout -text -in dh512.pem |") || die; -$dhinfo .= $_ while (<FP>); -close(FP); -open(FP, "openssl dh -noout -text -in dh1024.pem |") || die; -$dhinfo .= $_ while (<FP>); -close(FP); -$dhinfo =~ s|^|** |mg; -$dhinfo = "\n\/\*\n$dhinfo\*\/\n\n"; - -# generate C source from DH params -my $dhsource = ''; -open(FP, "openssl dh -noout -C -in dh512.pem | indent | expand -8 |") || die; -$dhsource .= $_ while (<FP>); -close(FP); -open(FP, "openssl dh -noout -C -in dh1024.pem | indent | expand -8 |") || die; -$dhsource .= $_ while (<FP>); -close(FP); -$dhsource =~ s|(DH\s+\*get_dh)|static $1|sg; - -# generate output -my $o = $dhinfo . $dhsource; - -# insert the generated code at the target location -$source =~ s|(\/\* $begin.+?\n).*\n(.*?\/\* $end)|$1$o$2|s; - -# and update the source on disk -print "Updating file `$file'\n"; -open(FP, ">$file") || die; -print FP $source; -close(FP); - -# cleanup -unlink("dh512.pem"); -unlink("dh1024.pem"); - -=pod -*/ diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c deleted file mode 100644 index 6a27c4af4d..0000000000 --- a/modules/ssl/ssl_engine_init.c +++ /dev/null @@ -1,1090 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_engine_init.c -** Initialization of Servers -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - -/* ==================================================================== - * Copyright (c) 1995-1999 Ben Laurie. 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 Ben Laurie - * for use in the Apache-SSL HTTP server project." - * - * 4. The name "Apache-SSL Server" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Ben Laurie - * for use in the Apache-SSL HTTP server project." - * - * THIS SOFTWARE IS PROVIDED BY BEN LAURIE ``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 BEN LAURIE OR - * HIS 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. - * ==================================================================== - */ - /* ``Recursive, adj.; - see Recursive.'' - -- Unknown */ -#include "mod_ssl.h" - - -/* _________________________________________________________________ -** -** Module Initialization -** _________________________________________________________________ -*/ - -/* - * Per-module initialization - */ -void ssl_init_Module(server_rec *s, pool *p) -{ - SSLModConfigRec *mc = myModConfig(); - SSLSrvConfigRec *sc; - server_rec *s2; - char *cp; - - mc->nInitCount++; - - /* - * Let us cleanup on restarts and exists - */ - ap_register_cleanup(p, s, ssl_init_ModuleKill, ssl_init_ChildKill); - - /* - * Any init round fixes the global config - */ - ssl_config_global_create(); /* just to avoid problems */ - ssl_config_global_fix(); - - /* - * try to fix the configuration and open the dedicated SSL - * logfile as early as possible - */ - for (s2 = s; s2 != NULL; s2 = s2->next) { - sc = mySrvConfig(s2); - - /* Fix up stuff that may not have been set */ - if (sc->bEnabled == UNSET) - sc->bEnabled = FALSE; - if (sc->nVerifyClient == SSL_CVERIFY_UNSET) - sc->nVerifyClient = SSL_CVERIFY_NONE; - if (sc->nVerifyDepth == UNSET) - sc->nVerifyDepth = 1; -#ifdef SSL_EXPERIMENTAL_PROXY - if (sc->nProxyVerifyDepth == UNSET) - sc->nProxyVerifyDepth = 1; -#endif - if (sc->nSessionCacheTimeout == UNSET) - sc->nSessionCacheTimeout = SSL_SESSION_CACHE_TIMEOUT; - if (sc->nPassPhraseDialogType == SSL_PPTYPE_UNSET) - sc->nPassPhraseDialogType = SSL_PPTYPE_BUILTIN; - - /* Open the dedicated SSL logfile */ - ssl_log_open(s, s2, p); - } - - /* - * Identification - */ - if (mc->nInitCount == 1) { - ssl_log(s, SSL_LOG_INFO, "Server: %s, Interface: %s, Library: %s", - SERVER_BASEVERSION, - ssl_var_lookup(p, NULL, NULL, NULL, "SSL_VERSION_INTERFACE"), - ssl_var_lookup(p, NULL, NULL, NULL, "SSL_VERSION_LIBRARY")); -#ifdef WIN32 - ssl_log(s, SSL_LOG_WARN, "You are using mod_ssl under Win32. " - "This combination is *NOT* officially supported. " - "Use it at your own risk!"); -#endif - } - - /* - * Initialization round information - */ - if (mc->nInitCount == 1) - ssl_log(s, SSL_LOG_INFO, "Init: 1st startup round (still not detached)"); - else if (mc->nInitCount == 2) - ssl_log(s, SSL_LOG_INFO, "Init: 2nd startup round (already detached)"); - else - ssl_log(s, SSL_LOG_INFO, "Init: %d%s restart round (already detached)", - mc->nInitCount-2, (mc->nInitCount-2) == 1 ? "st" : "nd"); - -#ifdef SSL_VENDOR - ap_hook_use("ap::mod_ssl::vendor::init_module", - AP_HOOK_SIG3(void,ptr,ptr), AP_HOOK_ALL, s, p); -#endif - - /* - * The initialization phase inside the Apache API is totally bogus. - * We actually have three non-trivial problems: - * - * 1. Under Unix the API does a 2-round initialization of modules while - * under Win32 it doesn't. This means we have to make sure that at - * least the pass phrase dialog doesn't occur twice. We overcome this - * problem by using a counter (mc->nInitCount) which has to - * survive the init rounds. - * - * 2. Between the first and the second round Apache detaches from - * the terminal under Unix. This means that our pass phrase dialog - * _has_ to be done in the first round and _cannot_ be done in the - * second round. - * - * 3. When Dynamic Shared Object (DSO) mechanism is used under Unix the - * module segment (code & data) gets unloaded and re-loaded between - * the first and the second round. This means no global data survives - * between first and the second init round. We overcome this by using - * an entry ("ssl_module") inside the ap_global_ctx. - * - * The situation as a table: - * - * Unix/static Unix/DSO Win32 Action Required - * (-DSHARED_MODULE) (-DWIN32) - * ----------- ----------------- --------- ----------------------------------- - * - load module - - - * init init init SSL library init, Pass Phrase Dialog - * detach detach - - - * - reload module - - - * init init - SSL library init, mod_ssl init - * - * Ok, now try to solve this totally ugly situation... - */ - -#ifdef SHARED_MODULE - ssl_log(s, SSL_LOG_INFO, "Init: %snitializing %s library", - mc->nInitCount == 1 ? "I" : "Rei", SSL_LIBRARY_NAME); - ssl_init_SSLLibrary(); -#else - if (mc->nInitCount <= 2) { - ssl_log(s, SSL_LOG_INFO, "Init: %snitializing %s library", - mc->nInitCount == 1 ? "I" : "Rei", SSL_LIBRARY_NAME); - ssl_init_SSLLibrary(); - } -#endif - if (mc->nInitCount == 1) { - ssl_pphrase_Handle(s, p); - ssl_init_TmpKeysHandle(SSL_TKP_GEN, s, p); -#ifndef WIN32 - return; -#endif - } - - /* - * SSL external crypto device ("engine") support - */ -#ifdef SSL_EXPERIMENTAL_ENGINE - ssl_init_Engine(s, p); -#endif - - /* - * Warn the user that he should use the session cache. - * But we can operate without it, of course. - */ - if (mc->nSessionCacheMode == SSL_SCMODE_UNSET) { - ssl_log(s, SSL_LOG_WARN, - "Init: Session Cache is not configured [hint: SSLSessionCache]"); - mc->nSessionCacheMode = SSL_SCMODE_NONE; - } - - /* - * initialize the mutex handling and session caching - */ - ssl_mutex_init(s, p); - ssl_scache_init(s, p); - - /* - * Seed the Pseudo Random Number Generator (PRNG) - */ - ssl_rand_seed(s, p, SSL_RSCTX_STARTUP, "Init: "); - - /* - * allocate the temporary RSA keys and DH params - */ - ssl_init_TmpKeysHandle(SSL_TKP_ALLOC, s, p); - - /* - * initialize servers - */ - ssl_log(s, SSL_LOG_INFO, "Init: Initializing (virtual) servers for SSL"); - for (s2 = s; s2 != NULL; s2 = s2->next) { - sc = mySrvConfig(s2); - /* - * Either now skip this server when SSL is disabled for - * it or give out some information about what we're - * configuring. - */ - if (!sc->bEnabled) - continue; - ssl_log(s2, SSL_LOG_INFO, - "Init: Configuring server %s for SSL protocol", - ssl_util_vhostid(p, s2)); - - /* - * Read the server certificate and key - */ - ssl_init_ConfigureServer(s2, p, sc); - } - - /* - * Configuration consistency checks - */ - ssl_init_CheckServers(s, p); - - /* - * Announce mod_ssl and SSL library in HTTP Server field - * as ``mod_ssl/X.X.X OpenSSL/X.X.X'' - */ - if ((cp = ssl_var_lookup(p, NULL, NULL, NULL, "SSL_VERSION_PRODUCT")) != NULL && cp[0] != NUL) - ap_add_version_component(cp); - ap_add_version_component(ssl_var_lookup(p, NULL, NULL, NULL, "SSL_VERSION_INTERFACE")); - ap_add_version_component(ssl_var_lookup(p, NULL, NULL, NULL, "SSL_VERSION_LIBRARY")); - - return; -} - -/* - * Initialize SSL library (also already needed for the pass phrase dialog) - */ -void ssl_init_SSLLibrary(void) -{ -#ifdef WIN32 - CRYPTO_malloc_init(); -#endif - SSL_load_error_strings(); - SSL_library_init(); - ssl_util_thread_setup(); - X509V3_add_standard_extensions(); - return; -} - -/* - * Support for external a Crypto Device ("engine"), usually - * a hardware accellerator card for crypto operations. - */ -#ifdef SSL_EXPERIMENTAL_ENGINE -void ssl_init_Engine(server_rec *s, pool *p) -{ - SSLModConfigRec *mc = myModConfig(); - ENGINE *e; - - if (mc->szCryptoDevice != NULL) { - if ((e = ENGINE_by_id(mc->szCryptoDevice)) == NULL) { - ssl_log(s, SSL_LOG_ERROR, "Init: Failed to load Crypto Device API `%s'", - mc->szCryptoDevice); - ssl_die(); - } - if (strEQ(mc->szCryptoDevice, "chil")) - ENGINE_ctrl(e, ENGINE_CTRL_CHIL_SET_FORKCHECK, 1, 0, 0); - if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { - ssl_log(s, SSL_LOG_ERROR, "Init: Failed to enable Crypto Device API `%s'", - mc->szCryptoDevice); - ssl_die(); - } - ENGINE_free(e); - } - return; -} -#endif - -/* - * Handle the Temporary RSA Keys and DH Params - */ -void ssl_init_TmpKeysHandle(int action, server_rec *s, pool *p) -{ - SSLModConfigRec *mc = myModConfig(); - ssl_asn1_t *asn1; - unsigned char *ucp; - RSA *rsa; - DH *dh; - - /* Generate Keys and Params */ - if (action == SSL_TKP_GEN) { - - /* seed PRNG */ - ssl_rand_seed(s, p, SSL_RSCTX_STARTUP, "Init: "); - - /* generate 512 bit RSA key */ - ssl_log(s, SSL_LOG_INFO, "Init: Generating temporary RSA private keys (512/1024 bits)"); - if ((rsa = RSA_generate_key(512, RSA_F4, NULL, NULL)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: Failed to generate temporary 512 bit RSA private key"); - ssl_die(); - } - asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tTmpKeys, "RSA:512"); - asn1->nData = i2d_RSAPrivateKey(rsa, NULL); - asn1->cpData = ap_palloc(mc->pPool, asn1->nData); - ucp = asn1->cpData; i2d_RSAPrivateKey(rsa, &ucp); /* 2nd arg increments */ - RSA_free(rsa); - - /* generate 1024 bit RSA key */ - if ((rsa = RSA_generate_key(1024, RSA_F4, NULL, NULL)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: Failed to generate temporary 1024 bit RSA private key"); - ssl_die(); - } - asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tTmpKeys, "RSA:1024"); - asn1->nData = i2d_RSAPrivateKey(rsa, NULL); - asn1->cpData = ap_palloc(mc->pPool, asn1->nData); - ucp = asn1->cpData; i2d_RSAPrivateKey(rsa, &ucp); /* 2nd arg increments */ - RSA_free(rsa); - - ssl_log(s, SSL_LOG_INFO, "Init: Configuring temporary DH parameters (512/1024 bits)"); - - /* import 512 bit DH param */ - if ((dh = ssl_dh_GetTmpParam(512)) == NULL) { - ssl_log(s, SSL_LOG_ERROR, "Init: Failed to import temporary 512 bit DH parameters"); - ssl_die(); - } - asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tTmpKeys, "DH:512"); - asn1->nData = i2d_DHparams(dh, NULL); - asn1->cpData = ap_palloc(mc->pPool, asn1->nData); - ucp = asn1->cpData; i2d_DHparams(dh, &ucp); /* 2nd arg increments */ - /* no need to free dh, it's static */ - - /* import 1024 bit DH param */ - if ((dh = ssl_dh_GetTmpParam(1024)) == NULL) { - ssl_log(s, SSL_LOG_ERROR, "Init: Failed to import temporary 1024 bit DH parameters"); - ssl_die(); - } - asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tTmpKeys, "DH:1024"); - asn1->nData = i2d_DHparams(dh, NULL); - asn1->cpData = ap_palloc(mc->pPool, asn1->nData); - ucp = asn1->cpData; i2d_DHparams(dh, &ucp); /* 2nd arg increments */ - /* no need to free dh, it's static */ - } - - /* Allocate Keys and Params */ - else if (action == SSL_TKP_ALLOC) { - - ssl_log(s, SSL_LOG_INFO, "Init: Configuring temporary RSA private keys (512/1024 bits)"); - - /* allocate 512 bit RSA key */ - if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tTmpKeys, "RSA:512")) != NULL) { - ucp = asn1->cpData; - if ((mc->pTmpKeys[SSL_TKPIDX_RSA512] = -#if SSL_LIBRARY_VERSION >= 0x00907000 - (void *)d2i_RSAPrivateKey(NULL, (const unsigned char **)&ucp, asn1->nData)) == NULL) { -#else - (void *)d2i_RSAPrivateKey(NULL, &ucp, asn1->nData)) == NULL) { -#endif - ssl_log(s, SSL_LOG_ERROR, "Init: Failed to load temporary 512 bit RSA private key"); - ssl_die(); - } - } - - /* allocate 1024 bit RSA key */ - if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tTmpKeys, "RSA:1024")) != NULL) { - ucp = asn1->cpData; - if ((mc->pTmpKeys[SSL_TKPIDX_RSA1024] = -#if SSL_LIBRARY_VERSION >= 0x00907000 - (void *)d2i_RSAPrivateKey(NULL, (const unsigned char **)&ucp, asn1->nData)) == NULL) { -#else - (void *)d2i_RSAPrivateKey(NULL, &ucp, asn1->nData)) == NULL) { -#endif - ssl_log(s, SSL_LOG_ERROR, "Init: Failed to load temporary 1024 bit RSA private key"); - ssl_die(); - } - } - - ssl_log(s, SSL_LOG_INFO, "Init: Configuring temporary DH parameters (512/1024 bits)"); - - /* allocate 512 bit DH param */ - if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tTmpKeys, "DH:512")) != NULL) { - ucp = asn1->cpData; - if ((mc->pTmpKeys[SSL_TKPIDX_DH512] = -#if SSL_LIBRARY_VERSION >= 0x00907000 - (void *)d2i_DHparams(NULL, (const unsigned char **)&ucp, asn1->nData)) == NULL) { -#else - (void *)d2i_DHparams(NULL, &ucp, asn1->nData)) == NULL) { -#endif - ssl_log(s, SSL_LOG_ERROR, "Init: Failed to load temporary 512 bit DH parameters"); - ssl_die(); - } - } - - /* allocate 1024 bit DH param */ - if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tTmpKeys, "DH:1024")) != NULL) { - ucp = asn1->cpData; - if ((mc->pTmpKeys[SSL_TKPIDX_DH1024] = -#if SSL_LIBRARY_VERSION >= 0x00907000 - (void *)d2i_DHparams(NULL, (const unsigned char **)&ucp, asn1->nData)) == NULL) { -#else - (void *)d2i_DHparams(NULL, &ucp, asn1->nData)) == NULL) { -#endif - ssl_log(s, SSL_LOG_ERROR, "Init: Failed to load temporary 1024 bit DH parameters"); - ssl_die(); - } - } - } - - /* Free Keys and Params */ - else if (action == SSL_TKP_FREE) { - if (mc->pTmpKeys[SSL_TKPIDX_RSA512] != NULL) { - RSA_free((RSA *)mc->pTmpKeys[SSL_TKPIDX_RSA512]); - mc->pTmpKeys[SSL_TKPIDX_RSA512] = NULL; - } - if (mc->pTmpKeys[SSL_TKPIDX_RSA1024] != NULL) { - RSA_free((RSA *)mc->pTmpKeys[SSL_TKPIDX_RSA1024]); - mc->pTmpKeys[SSL_TKPIDX_RSA1024] = NULL; - } - if (mc->pTmpKeys[SSL_TKPIDX_DH512] != NULL) { - DH_free((DH *)mc->pTmpKeys[SSL_TKPIDX_DH512]); - mc->pTmpKeys[SSL_TKPIDX_DH512] = NULL; - } - if (mc->pTmpKeys[SSL_TKPIDX_DH1024] != NULL) { - DH_free((DH *)mc->pTmpKeys[SSL_TKPIDX_DH1024]); - mc->pTmpKeys[SSL_TKPIDX_DH1024] = NULL; - } - } - return; -} - -/* - * Configure a particular server - */ -void ssl_init_ConfigureServer(server_rec *s, pool *p, SSLSrvConfigRec *sc) -{ - SSLModConfigRec *mc = myModConfig(); - int nVerify; - char *cpVHostID; - EVP_PKEY *pKey; - SSL_CTX *ctx; - STACK_OF(X509_NAME) *skCAList; - ssl_asn1_t *asn1; - unsigned char *ucp; - char *cp; - BOOL ok; - BOOL bSkipFirst; - int isca, pathlen; - int i, n; - - /* - * Create the server host:port string because we need it a lot - */ - cpVHostID = ssl_util_vhostid(p, s); - - /* - * Now check for important parameters and the - * possibility that the user forgot to set them. - */ - if (sc->szPublicCertFile[0] == NULL) { - ssl_log(s, SSL_LOG_ERROR, - "Init: (%s) No SSL Certificate set [hint: SSLCertificateFile]", - cpVHostID); - ssl_die(); - } - - /* - * Check for problematic re-initializations - */ - if (sc->pPublicCert[SSL_AIDX_RSA] != NULL || - sc->pPublicCert[SSL_AIDX_DSA] != NULL ) { - ssl_log(s, SSL_LOG_ERROR, - "Init: (%s) Illegal attempt to re-initialise SSL for server " - "(theoretically shouldn't happen!)", cpVHostID); - ssl_die(); - } - - /* - * Create the new per-server SSL context - */ - if (sc->nProtocol == SSL_PROTOCOL_NONE) { - ssl_log(s, SSL_LOG_ERROR, - "Init: (%s) No SSL protocols available [hint: SSLProtocol]", - cpVHostID); - ssl_die(); - } - cp = ap_pstrcat(p, (sc->nProtocol & SSL_PROTOCOL_SSLV2 ? "SSLv2, " : ""), - (sc->nProtocol & SSL_PROTOCOL_SSLV3 ? "SSLv3, " : ""), - (sc->nProtocol & SSL_PROTOCOL_TLSV1 ? "TLSv1, " : ""), NULL); - cp[strlen(cp)-2] = NUL; - ssl_log(s, SSL_LOG_TRACE, - "Init: (%s) Creating new SSL context (protocols: %s)", cpVHostID, cp); - if (sc->nProtocol == SSL_PROTOCOL_SSLV2) - ctx = SSL_CTX_new(SSLv2_server_method()); /* only SSLv2 is left */ - else - ctx = SSL_CTX_new(SSLv23_server_method()); /* be more flexible */ - SSL_CTX_set_options(ctx, SSL_OP_ALL); - if (!(sc->nProtocol & SSL_PROTOCOL_SSLV2)) - SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); - if (!(sc->nProtocol & SSL_PROTOCOL_SSLV3)) - SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3); - if (!(sc->nProtocol & SSL_PROTOCOL_TLSV1)) - SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1); - SSL_CTX_set_app_data(ctx, s); - sc->pSSLCtx = ctx; - - /* - * Configure additional context ingredients - */ - SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); - if (mc->nSessionCacheMode == SSL_SCMODE_NONE) - SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); - else - SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); - - /* - * Configure callbacks for SSL context - */ - nVerify = SSL_VERIFY_NONE; - if (sc->nVerifyClient == SSL_CVERIFY_REQUIRE) - nVerify |= SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT; - if ( (sc->nVerifyClient == SSL_CVERIFY_OPTIONAL) - || (sc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA) ) - nVerify |= SSL_VERIFY_PEER; - SSL_CTX_set_verify(ctx, nVerify, ssl_callback_SSLVerify); - SSL_CTX_sess_set_new_cb(ctx, ssl_callback_NewSessionCacheEntry); - SSL_CTX_sess_set_get_cb(ctx, ssl_callback_GetSessionCacheEntry); - SSL_CTX_sess_set_remove_cb(ctx, ssl_callback_DelSessionCacheEntry); - SSL_CTX_set_tmp_rsa_callback(ctx, ssl_callback_TmpRSA); - SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH); - SSL_CTX_set_info_callback(ctx, ssl_callback_LogTracingState); - - /* - * Configure SSL Cipher Suite - */ - if (sc->szCipherSuite != NULL) { - ssl_log(s, SSL_LOG_TRACE, - "Init: (%s) Configuring permitted SSL ciphers [%s]", - cpVHostID, sc->szCipherSuite); - if (!SSL_CTX_set_cipher_list(ctx, sc->szCipherSuite)) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: (%s) Unable to configure permitted SSL ciphers", - cpVHostID); - ssl_die(); - } - } - - /* - * Configure Client Authentication details - */ - if (sc->szCACertificateFile != NULL || sc->szCACertificatePath != NULL) { - ssl_log(s, SSL_LOG_TRACE, - "Init: (%s) Configuring client authentication", cpVHostID); - if (!SSL_CTX_load_verify_locations(ctx, - sc->szCACertificateFile, - sc->szCACertificatePath)) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: (%s) Unable to configure verify locations " - "for client authentication", cpVHostID); - ssl_die(); - } - if ((skCAList = ssl_init_FindCAList(s, p, sc->szCACertificateFile, - sc->szCACertificatePath)) == NULL) { - ssl_log(s, SSL_LOG_ERROR, - "Init: (%s) Unable to determine list of available " - "CA certificates for client authentication", cpVHostID); - ssl_die(); - } - SSL_CTX_set_client_CA_list(sc->pSSLCtx, skCAList); - } - - /* - * Configure Certificate Revocation List (CRL) Details - */ - if (sc->szCARevocationFile != NULL || sc->szCARevocationPath != NULL) { - ssl_log(s, SSL_LOG_TRACE, - "Init: (%s) Configuring certificate revocation facility", cpVHostID); - if ((sc->pRevocationStore = - SSL_X509_STORE_create(sc->szCARevocationFile, - sc->szCARevocationPath)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: (%s) Unable to configure X.509 CRL storage " - "for certificate revocation", cpVHostID); - ssl_die(); - } - } - - /* - * Give a warning when no CAs were configured but client authentication - * should take place. This cannot work. - */ - if (sc->nVerifyClient == SSL_CVERIFY_REQUIRE) { - skCAList = SSL_CTX_get_client_CA_list(ctx); - if (sk_X509_NAME_num(skCAList) == 0) - ssl_log(s, SSL_LOG_WARN, - "Init: Ops, you want to request client authentication, " - "but no CAs are known for verification!? " - "[Hint: SSLCACertificate*]"); - } - - /* - * Configure server certificate(s) - */ - ok = FALSE; - cp = ap_psprintf(p, "%s:RSA", cpVHostID); - if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tPublicCert, cp)) != NULL) { - ssl_log(s, SSL_LOG_TRACE, - "Init: (%s) Configuring RSA server certificate", cpVHostID); - ucp = asn1->cpData; - if ((sc->pPublicCert[SSL_AIDX_RSA] = d2i_X509(NULL, &ucp, asn1->nData)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: (%s) Unable to import RSA server certificate", - cpVHostID); - ssl_die(); - } - if (SSL_CTX_use_certificate(ctx, sc->pPublicCert[SSL_AIDX_RSA]) <= 0) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: (%s) Unable to configure RSA server certificate", - cpVHostID); - ssl_die(); - } - ok = TRUE; - } - cp = ap_psprintf(p, "%s:DSA", cpVHostID); - if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tPublicCert, cp)) != NULL) { - ssl_log(s, SSL_LOG_TRACE, - "Init: (%s) Configuring DSA server certificate", cpVHostID); - ucp = asn1->cpData; - if ((sc->pPublicCert[SSL_AIDX_DSA] = d2i_X509(NULL, &ucp, asn1->nData)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: (%s) Unable to import DSA server certificate", - cpVHostID); - ssl_die(); - } - if (SSL_CTX_use_certificate(ctx, sc->pPublicCert[SSL_AIDX_DSA]) <= 0) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: (%s) Unable to configure DSA server certificate", - cpVHostID); - ssl_die(); - } - ok = TRUE; - } - if (!ok) { - ssl_log(s, SSL_LOG_ERROR, - "Init: (%s) Ops, no RSA or DSA server certificate found?!", cpVHostID); - ssl_log(s, SSL_LOG_ERROR, - "Init: (%s) You have to perform a *full* server restart when you added or removed a certificate and/or key file", cpVHostID); - ssl_die(); - } - - /* - * Some information about the certificate(s) - */ - for (i = 0; i < SSL_AIDX_MAX; i++) { - if (sc->pPublicCert[i] != NULL) { - if (SSL_X509_isSGC(sc->pPublicCert[i])) { - ssl_log(s, SSL_LOG_INFO, - "Init: (%s) %s server certificate enables " - "Server Gated Cryptography (SGC)", - cpVHostID, (i == SSL_AIDX_RSA ? "RSA" : "DSA")); - } - if (SSL_X509_getBC(sc->pPublicCert[i], &isca, &pathlen)) { - if (isca) - ssl_log(s, SSL_LOG_WARN, - "Init: (%s) %s server certificate is a CA certificate " - "(BasicConstraints: CA == TRUE !?)", - cpVHostID, (i == SSL_AIDX_RSA ? "RSA" : "DSA")); - if (pathlen > 0) - ssl_log(s, SSL_LOG_WARN, - "Init: (%s) %s server certificate is not a leaf certificate " - "(BasicConstraints: pathlen == %d > 0 !?)", - cpVHostID, (i == SSL_AIDX_RSA ? "RSA" : "DSA"), pathlen); - } - if (SSL_X509_getCN(p, sc->pPublicCert[i], &cp)) { - if (ap_is_fnmatch(cp) && - !ap_fnmatch(cp, s->server_hostname, FNM_PERIOD|FNM_CASE_BLIND)) { - ssl_log(s, SSL_LOG_WARN, - "Init: (%s) %s server certificate wildcard CommonName (CN) `%s' " - "does NOT match server name!?", cpVHostID, - (i == SSL_AIDX_RSA ? "RSA" : "DSA"), cp); - } - else if (strNE(s->server_hostname, cp)) { - ssl_log(s, SSL_LOG_WARN, - "Init: (%s) %s server certificate CommonName (CN) `%s' " - "does NOT match server name!?", cpVHostID, - (i == SSL_AIDX_RSA ? "RSA" : "DSA"), cp); - } - } - } - } - - /* - * Configure server private key(s) - */ - ok = FALSE; - cp = ap_psprintf(p, "%s:RSA", cpVHostID); - if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tPrivateKey, cp)) != NULL) { - ssl_log(s, SSL_LOG_TRACE, - "Init: (%s) Configuring RSA server private key", cpVHostID); - ucp = asn1->cpData; - if ((sc->pPrivateKey[SSL_AIDX_RSA] = - d2i_PrivateKey(EVP_PKEY_RSA, NULL, &ucp, asn1->nData)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: (%s) Unable to import RSA server private key", - cpVHostID); - ssl_die(); - } - if (SSL_CTX_use_PrivateKey(ctx, sc->pPrivateKey[SSL_AIDX_RSA]) <= 0) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: (%s) Unable to configure RSA server private key", - cpVHostID); - ssl_die(); - } - ok = TRUE; - } - cp = ap_psprintf(p, "%s:DSA", cpVHostID); - if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tPrivateKey, cp)) != NULL) { - ssl_log(s, SSL_LOG_TRACE, - "Init: (%s) Configuring DSA server private key", cpVHostID); - ucp = asn1->cpData; - if ((sc->pPrivateKey[SSL_AIDX_DSA] = - d2i_PrivateKey(EVP_PKEY_DSA, NULL, &ucp, asn1->nData)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: (%s) Unable to import DSA server private key", - cpVHostID); - ssl_die(); - } - if (SSL_CTX_use_PrivateKey(ctx, sc->pPrivateKey[SSL_AIDX_DSA]) <= 0) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: (%s) Unable to configure DSA server private key", - cpVHostID); - ssl_die(); - } - ok = TRUE; - } - if (!ok) { - ssl_log(s, SSL_LOG_ERROR, - "Init: (%s) Ops, no RSA or DSA server private key found?!", cpVHostID); - ssl_die(); - } - - /* - * Optionally copy DSA parameters for certificate from private key - * (see http://www.psy.uq.edu.au/~ftp/Crypto/ssleay/TODO.html) - */ - if ( sc->pPublicCert[SSL_AIDX_DSA] != NULL - && sc->pPrivateKey[SSL_AIDX_DSA] != NULL) { - pKey = X509_get_pubkey(sc->pPublicCert[SSL_AIDX_DSA]); - if ( pKey != NULL - && EVP_PKEY_type(pKey->type) == EVP_PKEY_DSA - && EVP_PKEY_missing_parameters(pKey)) - EVP_PKEY_copy_parameters(pKey, sc->pPrivateKey[SSL_AIDX_DSA]); - } - - /* - * Optionally configure extra server certificate chain certificates. - * This is usually done by OpenSSL automatically when one of the - * server cert issuers are found under SSLCACertificatePath or in - * SSLCACertificateFile. But because these are intended for client - * authentication it can conflict. For instance when you use a - * Global ID server certificate you've to send out the intermediate - * CA certificate, too. When you would just configure this with - * SSLCACertificateFile and also use client authentication mod_ssl - * would accept all clients also issued by this CA. Obviously this - * isn't what we want in this situation. So this feature here exists - * to allow one to explicity configure CA certificates which are - * used only for the server certificate chain. - */ - if (sc->szCertificateChain != NULL) { - bSkipFirst = FALSE; - for (i = 0; i < SSL_AIDX_MAX && sc->szPublicCertFile[i] != NULL; i++) { - if (strEQ(sc->szPublicCertFile[i], sc->szCertificateChain)) { - bSkipFirst = TRUE; - break; - } - } - if ((n = SSL_CTX_use_certificate_chain(ctx, sc->szCertificateChain, - bSkipFirst, NULL)) < 0) { - ssl_log(s, SSL_LOG_ERROR, - "Init: (%s) Failed to configure CA certificate chain!", cpVHostID); - ssl_die(); - } - ssl_log(s, SSL_LOG_TRACE, "Init: (%s) Configuring " - "server certificate chain (%d CA certificate%s)", cpVHostID, - n, n == 1 ? "" : "s"); - } - -#ifdef SSL_VENDOR - ap_hook_use("ap::mod_ssl::vendor::configure_server", - AP_HOOK_SIG4(void,ptr,ptr,ptr), AP_HOOK_ALL, - s, p, sc); -#endif - - return; -} - -void ssl_init_CheckServers(server_rec *sm, pool *p) -{ - server_rec *s; - server_rec **ps; - SSLSrvConfigRec *sc; - ssl_ds_table *t; - pool *sp; - char *key; - BOOL bConflict; - - /* - * Give out warnings when a server has HTTPS configured - * for the HTTP port or vice versa - */ - for (s = sm; s != NULL; s = s->next) { - sc = mySrvConfig(s); - if (sc->bEnabled && s->port == DEFAULT_HTTP_PORT) - ssl_log(sm, SSL_LOG_WARN, - "Init: (%s) You configured HTTPS(%d) on the standard HTTP(%d) port!", - ssl_util_vhostid(p, s), DEFAULT_HTTPS_PORT, DEFAULT_HTTP_PORT); - if (!sc->bEnabled && s->port == DEFAULT_HTTPS_PORT) - ssl_log(sm, SSL_LOG_WARN, - "Init: (%s) You configured HTTP(%d) on the standard HTTPS(%d) port!", - ssl_util_vhostid(p, s), DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT); - } - - /* - * Give out warnings when more than one SSL-aware virtual server uses the - * same IP:port. This doesn't work because mod_ssl then will always use - * just the certificate/keys of one virtual host (which one cannot be said - * easily - but that doesn't matter here). - */ - sp = ap_make_sub_pool(p); - t = ssl_ds_table_make(sp, sizeof(server_rec *)); - bConflict = FALSE; - for (s = sm; s != NULL; s = s->next) { - sc = mySrvConfig(s); - if (!sc->bEnabled) - continue; - key = ap_psprintf(sp, "%pA:%u", &s->addrs->host_addr, s->addrs->host_port); - ps = ssl_ds_table_get(t, key); - if (ps != NULL) { - ssl_log(sm, SSL_LOG_WARN, - "Init: SSL server IP/port conflict: %s (%s:%d) vs. %s (%s:%d)", - ssl_util_vhostid(p, s), - (s->defn_name != NULL ? s->defn_name : "unknown"), - s->defn_line_number, - ssl_util_vhostid(p, *ps), - ((*ps)->defn_name != NULL ? (*ps)->defn_name : "unknown"), - (*ps)->defn_line_number); - bConflict = TRUE; - continue; - } - ps = ssl_ds_table_push(t, key); - *ps = s; - } - ssl_ds_table_kill(t); - ap_destroy_pool(sp); - if (bConflict) - ssl_log(sm, SSL_LOG_WARN, - "Init: You should not use name-based virtual hosts in conjunction with SSL!!"); - - return; -} - -static int ssl_init_FindCAList_X509NameCmp(X509_NAME **a, X509_NAME **b) -{ - return(X509_NAME_cmp(*a, *b)); -} - -STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s, pool *pp, char *cpCAfile, char *cpCApath) -{ - STACK_OF(X509_NAME) *skCAList; - STACK_OF(X509_NAME) *sk; - DIR *dir; - struct DIR_TYPE *direntry; - char *cp; - pool *p; - int n; - - /* - * Use a subpool so we don't bloat up the server pool which - * is remains in memory for the complete operation time of - * the server. - */ - p = ap_make_sub_pool(pp); - - /* - * Start with a empty stack/list where new - * entries get added in sorted order. - */ - skCAList = sk_X509_NAME_new(ssl_init_FindCAList_X509NameCmp); - - /* - * Process CA certificate bundle file - */ - if (cpCAfile != NULL) { - sk = SSL_load_client_CA_file(cpCAfile); - for(n = 0; sk != NULL && n < sk_X509_NAME_num(sk); n++) { - ssl_log(s, SSL_LOG_TRACE, - "CA certificate: %s", - X509_NAME_oneline(sk_X509_NAME_value(sk, n), NULL, 0)); - if (sk_X509_NAME_find(skCAList, sk_X509_NAME_value(sk, n)) < 0) - sk_X509_NAME_push(skCAList, sk_X509_NAME_value(sk, n)); - } - } - - /* - * Process CA certificate path files - */ - if (cpCApath != NULL) { - dir = ap_popendir(p, cpCApath); - while ((direntry = readdir(dir)) != NULL) { - cp = ap_pstrcat(p, cpCApath, "/", direntry->d_name, NULL); - sk = SSL_load_client_CA_file(cp); - for(n = 0; sk != NULL && n < sk_X509_NAME_num(sk); n++) { - ssl_log(s, SSL_LOG_TRACE, - "CA certificate: %s", - X509_NAME_oneline(sk_X509_NAME_value(sk, n), NULL, 0)); - if (sk_X509_NAME_find(skCAList, sk_X509_NAME_value(sk, n)) < 0) - sk_X509_NAME_push(skCAList, sk_X509_NAME_value(sk, n)); - } - } - ap_pclosedir(p, dir); - } - - /* - * Cleanup - */ - sk_X509_NAME_set_cmp_func(skCAList, NULL); - ap_destroy_pool(p); - - return skCAList; -} - -void ssl_init_Child(server_rec *s, pool *p) -{ - /* open the mutex lockfile */ - ssl_mutex_reinit(s, p); - return; -} - -void ssl_init_ChildKill(void *data) -{ - /* currently nothing to do */ - return; -} - -void ssl_init_ModuleKill(void *data) -{ - SSLSrvConfigRec *sc; - server_rec *s = (server_rec *)data; - - /* - * Drop the session cache and mutex - */ - ssl_scache_kill(s); - ssl_mutex_kill(s); - - /* - * Destroy the temporary keys and params - */ - ssl_init_TmpKeysHandle(SSL_TKP_FREE, s, NULL); - - /* - * Free the non-pool allocated structures - * in the per-server configurations - */ - for (; s != NULL; s = s->next) { - sc = mySrvConfig(s); - if (sc->pPublicCert[SSL_AIDX_RSA] != NULL) { - X509_free(sc->pPublicCert[SSL_AIDX_RSA]); - sc->pPublicCert[SSL_AIDX_RSA] = NULL; - } - if (sc->pPublicCert[SSL_AIDX_DSA] != NULL) { - X509_free(sc->pPublicCert[SSL_AIDX_DSA]); - sc->pPublicCert[SSL_AIDX_DSA] = NULL; - } - if (sc->pPrivateKey[SSL_AIDX_RSA] != NULL) { - EVP_PKEY_free(sc->pPrivateKey[SSL_AIDX_RSA]); - sc->pPrivateKey[SSL_AIDX_RSA] = NULL; - } - if (sc->pPrivateKey[SSL_AIDX_DSA] != NULL) { - EVP_PKEY_free(sc->pPrivateKey[SSL_AIDX_DSA]); - sc->pPrivateKey[SSL_AIDX_DSA] = NULL; - } - if (sc->pSSLCtx != NULL) { - SSL_CTX_free(sc->pSSLCtx); - sc->pSSLCtx = NULL; - } - } - - /* - * Try to kill the internals of the SSL library. - */ -#ifdef SHARED_MODULE - ERR_free_strings(); - ERR_remove_state(0); - EVP_cleanup(); -#endif - - return; -} - diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c deleted file mode 100644 index 4ba1574ca8..0000000000 --- a/modules/ssl/ssl_engine_io.c +++ /dev/null @@ -1,728 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_engine_io.c -** I/O Functions -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - /* ``MY HACK: This universe. - Just one little problem: - core keeps dumping.'' - -- Unknown */ -#include "mod_ssl.h" - -/* _________________________________________________________________ -** -** I/O Request Body Sucking and Re-Injection -** _________________________________________________________________ -*/ - -#ifndef SSL_CONSERVATIVE - -/* - * Background: - * - * 1. When the client sends a HTTP/HTTPS request, Apache's core code - * reads only the request line ("METHOD /path HTTP/x.y") and the - * attached MIME headers ("Foo: bar") up to the terminating line ("CR - * LF"). An attached request body (for instance the data of a POST - * method) is _NOT_ read. Instead it is read by mod_cgi's content - * handler and directly passed to the CGI script. - * - * 2. mod_ssl supports per-directory re-configuration of SSL parameters. - * This is implemented by performing an SSL renegotiation of the - * re-configured parameters after the request is read, but before the - * response is sent. In more detail: the renegotiation happens after the - * request line and MIME headers were read, but _before_ the attached - * request body is read. The reason simply is that in the HTTP protocol - * usually there is no acknowledgment step between the headers and the - * body (there is the 100-continue feature and the chunking facility - * only), so Apache has no API hook for this step. - * - * 3. the problem now occurs when the client sends a POST request for - * URL /foo via HTTPS the server and the server has SSL parameters - * re-configured on a per-URL basis for /foo. Then mod_ssl has to - * perform an SSL renegotiation after the request was read and before - * the response is sent. But the problem is the pending POST body data - * in the receive buffer of SSL (which Apache still has not read - it's - * pending until mod_cgi sucks it in). When mod_ssl now tries to perform - * the renegotiation the pending data leads to an I/O error. - * - * Solution Idea: - * - * There are only two solutions: Either to simply state that POST - * requests to URLs with SSL re-configurations are not allowed, or to - * renegotiate really after the _complete_ request (i.e. including - * the POST body) was read. Obviously the latter would be preferred, - * but it cannot be done easily inside Apache, because as already - * mentioned, there is no API step between the body reading and the body - * processing. And even when we mod_ssl would hook directly into the - * loop of mod_cgi, we wouldn't solve the problem for other handlers, of - * course. So the only general solution is to suck in the pending data - * of the request body from the OpenSSL BIO into the Apache BUFF. Then - * the renegotiation can be done and after this step Apache can proceed - * processing the request as before. - * - * Solution Implementation: - * - * We cannot simply suck in the data via an SSL_read-based loop because of - * HTTP chunking. Instead we _have_ to use the Apache API for this step which - * is aware of HTTP chunking. So the trick is to suck in the pending request - * data via the Apache API (which uses Apache's BUFF code and in the - * background mod_ssl's I/O glue code) and re-inject it later into the Apache - * BUFF code again. This way the data flows twice through the Apache BUFF, of - * course. But this way the solution doesn't depend on any Apache specifics - * and is fully transparent to Apache modules. - */ - -struct ssl_io_suck_st { - BOOL active; - char *bufptr; - int buflen; - char *pendptr; - int pendlen; -}; - -/* prepare request_rec structure for input sucking */ -static void ssl_io_suck_start(request_rec *r) -{ - struct ssl_io_suck_st *ss; - - ss = ap_ctx_get(r->ctx, "ssl::io::suck"); - if (ss == NULL) { - ss = ap_palloc(r->pool, sizeof(struct ssl_io_suck_st)); - ap_ctx_set(r->ctx, "ssl::io::suck", ss); - ss->buflen = 8192; - ss->bufptr = ap_palloc(r->pool, ss->buflen); - } - ss->pendptr = ss->bufptr; - ss->pendlen = 0; - ss->active = FALSE; - return; -} - -/* record a sucked input chunk */ -static void ssl_io_suck_record(request_rec *r, char *buf, int len) -{ - struct ssl_io_suck_st *ss; - - if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL) - return; - if (((ss->bufptr + ss->buflen) - (ss->pendptr + ss->pendlen)) < len) { - /* "expand" buffer: actually we cannot really expand the buffer - here, because Apache's pool system doesn't support expanding chunks - of memory. Instead we have to either reuse processed data or - allocate a new chunk of memory in advance if we really need more - memory. */ - int newlen; - char *newptr; - - if (( (ss->pendptr - ss->bufptr) - + ((ss->bufptr + ss->buflen) - (ss->pendptr + ss->pendlen)) ) >= len) { - /* make memory available by reusing already processed data */ - memmove(ss->bufptr, ss->pendptr, ss->pendlen); - ss->pendptr = ss->bufptr; - } - else { - /* too bad, we have to allocate a new larger buffer */ - newlen = (ss->buflen * 2) + len; - newptr = ap_palloc(r->pool, newlen); - ss->bufptr = newptr; - ss->buflen = newlen; - memcpy(ss->bufptr, ss->pendptr, ss->pendlen); - ss->pendptr = ss->bufptr; - } - } - memcpy(ss->pendptr+ss->pendlen, buf, len); - ss->pendlen += len; - return; -} - -/* finish request_rec after input sucking */ -static void ssl_io_suck_end(request_rec *r) -{ - struct ssl_io_suck_st *ss; - - if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL) - return; - ss->active = TRUE; - r->read_body = REQUEST_NO_BODY; - r->read_length = 0; - r->read_chunked = 0; - r->remaining = 0; - ap_bsetflag(r->connection->client, B_CHUNK, 0); - return; -} - -void ssl_io_suck(request_rec *r, SSL *ssl) -{ - int rc; - int len; - char *buf; - int buflen; - char c; - int sucked; - - if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) == OK) { - if (ap_should_client_block(r)) { - - /* read client request block through Apache API */ - buflen = HUGE_STRING_LEN; - buf = ap_palloc(r->pool, buflen); - ap_hard_timeout("SSL I/O request body pre-sucking", r); - sucked = 0; - ssl_io_suck_start(r); - while ((len = ap_get_client_block(r, buf, buflen)) > 0) { - ssl_io_suck_record(r, buf, len); - sucked += len; - } - ssl_io_suck_end(r); - ap_kill_timeout(r); - - /* suck trailing data (usually CR LF) which - is still in the Apache BUFF layer */ - while (ap_bpeekc(r->connection->client) != EOF) { - c = ap_bgetc(r->connection->client); - ssl_io_suck_record(r, &c, 1); - sucked++; - } - - ssl_log(r->server, SSL_LOG_TRACE, - "I/O: sucked %d bytes of input data from SSL/TLS I/O layer " - "for delayed injection into Apache I/O layer", sucked); - } - } - return; -} - -/* the SSL_read replacement routine which knows about the suck buffer */ -static int ssl_io_suck_read(SSL *ssl, char *buf, int len) -{ - ap_ctx *actx; - struct ssl_io_suck_st *ss; - request_rec *r = NULL; - int rv; - - actx = (ap_ctx *)SSL_get_app_data2(ssl); - if (actx != NULL) - r = (request_rec *)ap_ctx_get(actx, "ssl::request_rec"); - - rv = -1; - if (r != NULL) { - ss = ap_ctx_get(r->ctx, "ssl::io::suck"); - if (ss != NULL) { - if (ss->active && ss->pendlen > 0) { - /* ok, there is pre-sucked data */ - len = (ss->pendlen > len ? len : ss->pendlen); - memcpy(buf, ss->pendptr, len); - ss->pendptr += len; - ss->pendlen -= len; - ssl_log(r->server, SSL_LOG_TRACE, - "I/O: injecting %d bytes of pre-sucked data " - "into Apache I/O layer", len); - rv = len; - } - } - } - if (rv == -1) - rv = SSL_read(ssl, buf, len); - return rv; -} - -/* override SSL_read in the following code... */ -#define SSL_read ssl_io_suck_read - -#endif /* !SSL_CONSERVATIVE */ - -/* _________________________________________________________________ -** -** I/O Hooks -** _________________________________________________________________ -*/ - -#ifndef NO_WRITEV -#include <sys/types.h> -#include <sys/uio.h> -#endif - -static int ssl_io_hook_read(BUFF *fb, char *buf, int len); -static int ssl_io_hook_write(BUFF *fb, char *buf, int len); -#ifndef NO_WRITEV -static int ssl_io_hook_writev(BUFF *fb, const struct iovec *iov, int iovcnt); -#endif -#ifdef WIN32 -static int ssl_io_hook_recvwithtimeout(BUFF *fb, char *buf, int len); -static int ssl_io_hook_sendwithtimeout(BUFF *fb, const char *buf, int len); -#endif /* WIN32 */ - -void ssl_io_register(void) -{ - ap_hook_register("ap::buff::read", ssl_io_hook_read, AP_HOOK_NOCTX); - ap_hook_register("ap::buff::write", ssl_io_hook_write, AP_HOOK_NOCTX); -#ifndef NO_WRITEV - ap_hook_register("ap::buff::writev", ssl_io_hook_writev, AP_HOOK_NOCTX); -#endif -#ifdef WIN32 - ap_hook_register("ap::buff::recvwithtimeout", - ssl_io_hook_recvwithtimeout, AP_HOOK_NOCTX); - ap_hook_register("ap::buff::sendwithtimeout", - ssl_io_hook_sendwithtimeout, AP_HOOK_NOCTX); -#endif - return; -} - -void ssl_io_unregister(void) -{ - ap_hook_unregister("ap::buff::read", ssl_io_hook_read); - ap_hook_unregister("ap::buff::write", ssl_io_hook_write); -#ifndef NO_WRITEV - ap_hook_unregister("ap::buff::writev", ssl_io_hook_writev); -#endif -#ifdef WIN32 - ap_hook_unregister("ap::buff::recvwithtimeout", ssl_io_hook_recvwithtimeout); - ap_hook_unregister("ap::buff::sendwithtimeout", ssl_io_hook_sendwithtimeout); -#endif - return; -} - -static int ssl_io_hook_read(BUFF *fb, char *buf, int len) -{ - SSL *ssl; - conn_rec *c; - int rc; - - if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) { - rc = SSL_read(ssl, buf, len); - /* - * Simulate an EINTR in case OpenSSL wants to read more. - * (This is usually the case when the client forces an SSL - * renegotation which is handled implicitly by OpenSSL.) - */ - if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_READ) - errno = EINTR; - /* - * Log SSL errors - */ - if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_SSL) { - c = (conn_rec *)SSL_get_app_data(ssl); - ssl_log(c->server, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "SSL error on reading data"); - } - /* - * read(2) returns only the generic error number -1 - */ - if (rc < 0) - rc = -1; - } - else - rc = read(fb->fd_in, buf, len); - return rc; -} - -static int ssl_io_hook_write(BUFF *fb, char *buf, int len) -{ - SSL *ssl; - conn_rec *c; - int rc; - - if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) { - rc = SSL_write(ssl, buf, len); - /* - * Simulate an EINTR in case OpenSSL wants to write more. - */ - if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE) - errno = EINTR; - /* - * Log SSL errors - */ - if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_SSL) { - c = (conn_rec *)SSL_get_app_data(ssl); - ssl_log(c->server, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "SSL error on writing data"); - } - /* - * write(2) returns only the generic error number -1 - */ - if (rc < 0) - rc = -1; - } - else - rc = write(fb->fd, buf, len); - return rc; -} - -#ifndef NO_WRITEV -/* the prototype for our own SSL_writev() */ -static int SSL_writev(SSL *, const struct iovec *, int); - -static int ssl_io_hook_writev(BUFF *fb, const struct iovec *iov, int iovcnt) -{ - SSL *ssl; - conn_rec *c; - int rc; - - if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) { - rc = SSL_writev(ssl, iov, iovcnt); - /* - * Simulate an EINTR in case OpenSSL wants to write more. - */ - if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE) - errno = EINTR; - /* - * Log SSL errors - */ - if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_SSL) { - c = (conn_rec *)SSL_get_app_data(ssl); - ssl_log(c->server, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "SSL error on writing data"); - } - /* - * writev(2) returns only the generic error number -1 - */ - if (rc < 0) - rc = -1; - } - else - rc = writev(fb->fd, iov, iovcnt); - return rc; -} -#endif - -#ifdef WIN32 - -/* these two functions are exported from buff.c under WIN32 */ -API_EXPORT(int) sendwithtimeout(int sock, const char *buf, int len, int flags); -API_EXPORT(int) recvwithtimeout(int sock, char *buf, int len, int flags); - -/* and the prototypes for our SSL_xxx variants */ -static int SSL_sendwithtimeout(BUFF *fb, const char *buf, int len); -static int SSL_recvwithtimeout(BUFF *fb, char *buf, int len); - -static int ssl_io_hook_recvwithtimeout(BUFF *fb, char *buf, int len) -{ - SSL *ssl; - int rc; - - if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) - rc = SSL_recvwithtimeout(fb, buf, len); - else - rc = recvwithtimeout(fb->fd, buf, len, 0); - return rc; -} - -static int ssl_io_hook_sendwithtimeout(BUFF *fb, const char *buf, int len) -{ - SSL *ssl; - int rc; - - if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) - rc = SSL_sendwithtimeout(fb, buf, len); - else - rc = sendwithtimeout(fb->fd, buf, len, 0); - return rc; -} - -#endif /* WIN32 */ - -/* _________________________________________________________________ -** -** Special Functions for OpenSSL -** _________________________________________________________________ -*/ - -#ifdef WIN32 - -static int SSL_sendwithtimeout(BUFF *fb, const char *buf, int len) -{ - int iostate = 1; - fd_set fdset; - struct timeval tv; - int err = WSAEWOULDBLOCK; - int rv; - int retry; - int sock = fb->fd; - SSL *ssl; - - ssl = ap_ctx_get(fb->ctx, "ssl"); - - if (!(tv.tv_sec = ap_check_alarm())) - return (SSL_write(ssl, (char*)buf, len)); - - rv = ioctlsocket(sock, FIONBIO, &iostate); - iostate = 0; - if (rv) { - err = WSAGetLastError(); - ap_assert(0); - } - rv = SSL_write(ssl, (char*)buf, len); - if (rv <= 0) { - if (BIO_sock_should_retry(rv)) { - do { - retry = 0; - FD_ZERO(&fdset); - FD_SET((unsigned int)sock, &fdset); - tv.tv_usec = 0; - rv = select(FD_SETSIZE, NULL, &fdset, NULL, &tv); - if (rv == SOCKET_ERROR) - err = WSAGetLastError(); - else if (rv == 0) { - ioctlsocket(sock, FIONBIO, &iostate); - if(ap_check_alarm() < 0) { - WSASetLastError(EINTR); /* Simulate an alarm() */ - return (SOCKET_ERROR); - } - } - else { - rv = SSL_write(ssl, (char*)buf, len); - if (BIO_sock_should_retry(rv)) { - ap_log_error(APLOG_MARK,APLOG_DEBUG, NULL, - "select claimed we could write, " - "but in fact we couldn't. " - "This is a bug in Windows."); - retry = 1; - Sleep(100); - } - } - } while(retry); - } - } - ioctlsocket(sock, FIONBIO, &iostate); - if (rv == SOCKET_ERROR) - WSASetLastError(err); - return (rv); -} - -static int SSL_recvwithtimeout(BUFF *fb, char *buf, int len) -{ - int iostate = 1; - fd_set fdset; - struct timeval tv; - int err = WSAEWOULDBLOCK; - int rv; - int sock = fb->fd_in; - SSL *ssl; - int retry; - - ssl = ap_ctx_get(fb->ctx, "ssl"); - - if (!(tv.tv_sec = ap_check_alarm())) - return (SSL_read(ssl, buf, len)); - - rv = ioctlsocket(sock, FIONBIO, &iostate); - iostate = 0; - ap_assert(!rv); - rv = SSL_read(ssl, buf, len); - if (rv <= 0) { - if (BIO_sock_should_retry(rv)) { - do { - retry = 0; - FD_ZERO(&fdset); - FD_SET((unsigned int)sock, &fdset); - tv.tv_usec = 0; - rv = select(FD_SETSIZE, &fdset, NULL, NULL, &tv); - if (rv == SOCKET_ERROR) - err = WSAGetLastError(); - else if (rv == 0) { - ioctlsocket(sock, FIONBIO, &iostate); - ap_check_alarm(); - WSASetLastError(WSAEWOULDBLOCK); - return (SOCKET_ERROR); - } - else { - rv = SSL_read(ssl, buf, len); - if (rv == SOCKET_ERROR) { - if (BIO_sock_should_retry(rv)) { - ap_log_error(APLOG_MARK,APLOG_DEBUG, NULL, - "select claimed we could read, " - "but in fact we couldn't. " - "This is a bug in Windows."); - retry = 1; - Sleep(100); - } - else { - err = WSAGetLastError(); - } - } - } - } while(retry); - } - } - ioctlsocket(sock, FIONBIO, &iostate); - if (rv == SOCKET_ERROR) - WSASetLastError(err); - return (rv); -} - -#endif /*WIN32*/ - -/* - * There is no SSL_writev() provided by OpenSSL. The reason is mainly because - * OpenSSL has to fragment the data itself again for the SSL record layer, so a - * writev() like interface makes not much sense. What we do is to emulate it - * to at least being able to use the write() like interface. But keep in mind - * that the network I/O performance is not write() like, of course. - */ -#ifndef NO_WRITEV -static int SSL_writev(SSL *ssl, const struct iovec *iov, int iovcnt) -{ - int i; - int n; - int rc; - - rc = 0; - for (i = 0; i < iovcnt; i++) { - if ((n = SSL_write(ssl, iov[i].iov_base, iov[i].iov_len)) == -1) { - rc = -1; - break; - } - rc += n; - } - return rc; -} -#endif - -/* _________________________________________________________________ -** -** I/O Data Debugging -** _________________________________________________________________ -*/ - -#define DUMP_WIDTH 16 - -static void ssl_io_data_dump(server_rec *srvr, const char *s, long len) -{ - char buf[256]; - char tmp[64]; - int i, j, rows, trunc; - unsigned char ch; - - trunc = 0; - for(; (len > 0) && ((s[len-1] == ' ') || (s[len-1] == '\0')); len--) - trunc++; - rows = (len / DUMP_WIDTH); - if ((rows * DUMP_WIDTH) < len) - rows++; - ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID, - "+-------------------------------------------------------------------------+"); - for(i = 0 ; i< rows; i++) { - ap_snprintf(tmp, sizeof(tmp), "| %04x: ", i * DUMP_WIDTH); - ap_cpystrn(buf, tmp, sizeof(buf)); - for (j = 0; j < DUMP_WIDTH; j++) { - if (((i * DUMP_WIDTH) + j) >= len) - ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf)); - else { - ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff; - ap_snprintf(tmp, sizeof(tmp), "%02x%c", ch , j==7 ? '-' : ' '); - ap_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf)); - } - } - ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf)); - for (j = 0; j < DUMP_WIDTH; j++) { - if (((i * DUMP_WIDTH) + j) >= len) - ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf)); - else { - ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff; - ap_snprintf(tmp, sizeof(tmp), "%c", ((ch >= ' ') && (ch <= '~')) ? ch : '.'); - ap_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf)); - } - } - ap_cpystrn(buf+strlen(buf), " |", sizeof(buf)-strlen(buf)); - ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID, "%s", buf); - } - if (trunc > 0) - ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID, - "| %04x - <SPACES/NULS>", len + trunc); - ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID, - "+-------------------------------------------------------------------------+"); - return; -} - -long ssl_io_data_cb(BIO *bio, int cmd, const char *argp, int argi, long argl, long rc) -{ - SSL *ssl; - conn_rec *c; - server_rec *s; - - if ((ssl = (SSL *)BIO_get_callback_arg(bio)) == NULL) - return rc; - if ((c = (conn_rec *)SSL_get_app_data(ssl)) == NULL) - return rc; - s = c->server; - - if ( cmd == (BIO_CB_WRITE|BIO_CB_RETURN) - || cmd == (BIO_CB_READ |BIO_CB_RETURN) ) { - if (rc >= 0) { - ssl_log(s, SSL_LOG_DEBUG, - "%s: %s %ld/%d bytes %s BIO#%08X [mem: %08lX] %s", - SSL_LIBRARY_NAME, - (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"), - rc, argi, (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "to" : "from"), - bio, argp, - (argp != NULL ? "(BIO dump follows)" : "(Ops, no memory buffer?)")); - if (argp != NULL) - ssl_io_data_dump(s, argp, rc); - } - else { - ssl_log(s, SSL_LOG_DEBUG, - "%s: I/O error, %d bytes expected to %s on BIO#%08X [mem: %08lX]", - SSL_LIBRARY_NAME, argi, - (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"), - bio, argp); - } - } - return rc; -} - diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c deleted file mode 100644 index ca1b3f0a55..0000000000 --- a/modules/ssl/ssl_engine_kernel.c +++ /dev/null @@ -1,1905 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_engine_kernel.c -** The SSL engine kernel -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - -/* ==================================================================== - * Copyright (c) 1995-1999 Ben Laurie. 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 Ben Laurie - * for use in the Apache-SSL HTTP server project." - * - * 4. The name "Apache-SSL Server" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Ben Laurie - * for use in the Apache-SSL HTTP server project." - * - * THIS SOFTWARE IS PROVIDED BY BEN LAURIE ``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 BEN LAURIE OR - * HIS 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. - * ==================================================================== - */ - /* ``It took me fifteen years to discover - I had no talent for programming, but - I couldn't give it up because by that - time I was too famous.'' - -- Unknown */ -#include "mod_ssl.h" - - -/* _________________________________________________________________ -** -** SSL Engine Kernel -** _________________________________________________________________ -*/ - -/* - * Connect Handler: - * Connect SSL to the accepted socket - * - * Usually we would need an Apache API hook which is triggered right after - * the socket is accepted for handling a new request. But Apache 1.3 doesn't - * provide such a hook, so we have to patch http_main.c and call this - * function directly. - */ -void ssl_hook_NewConnection(conn_rec *conn) -{ - server_rec *srvr; - BUFF *fb; - SSLSrvConfigRec *sc; - ap_ctx *apctx; - SSL *ssl; - char *cp; - char *cpVHostID; - char *cpVHostMD5; - X509 *xs; - int rc; - - /* - * Get context - */ - srvr = conn->server; - fb = conn->client; - sc = mySrvConfig(srvr); - - /* - * Create SSL context - */ - ap_ctx_set(fb->ctx, "ssl", NULL); - - /* - * Immediately stop processing if SSL - * is disabled for this connection - */ - if (sc == NULL || !sc->bEnabled) - return; - - /* - * Remember the connection information for - * later access inside callback functions - */ - cpVHostID = ssl_util_vhostid(conn->pool, srvr); - ssl_log(srvr, SSL_LOG_INFO, "Connection to child %d established " - "(server %s, client %s)", conn->child_num, cpVHostID, - conn->remote_ip != NULL ? conn->remote_ip : "unknown"); - - /* - * Seed the Pseudo Random Number Generator (PRNG) - */ - ssl_rand_seed(srvr, conn->pool, SSL_RSCTX_CONNECT, ""); - - /* - * Create a new SSL connection with the configured server SSL context and - * attach this to the socket. Additionally we register this attachment - * so we can detach later. - */ - if ((ssl = SSL_new(sc->pSSLCtx)) == NULL) { - ssl_log(conn->server, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Unable to create a new SSL connection from the SSL context"); - ap_ctx_set(fb->ctx, "ssl", NULL); - ap_bsetflag(fb, B_EOF|B_EOUT, 1); - conn->aborted = 1; - return; - } - SSL_clear(ssl); - cpVHostMD5 = ap_md5(conn->pool, (unsigned char *)cpVHostID); - if (!SSL_set_session_id_context(ssl, (unsigned char *)cpVHostMD5, strlen(cpVHostMD5))) { - ssl_log(conn->server, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Unable to set session id context to `%s'", cpVHostMD5); - ap_ctx_set(fb->ctx, "ssl", NULL); - ap_bsetflag(fb, B_EOF|B_EOUT, 1); - conn->aborted = 1; - return; - } - SSL_set_app_data(ssl, conn); - apctx = ap_ctx_new(conn->pool); - ap_ctx_set(apctx, "ssl::request_rec", NULL); - ap_ctx_set(apctx, "ssl::verify::depth", AP_CTX_NUM2PTR(0)); - SSL_set_app_data2(ssl, apctx); - SSL_set_fd(ssl, fb->fd); - ap_ctx_set(fb->ctx, "ssl", ssl); - - /* - * Configure callbacks for SSL connection - */ - SSL_set_tmp_rsa_callback(ssl, ssl_callback_TmpRSA); - SSL_set_tmp_dh_callback(ssl, ssl_callback_TmpDH); - if (sc->nLogLevel >= SSL_LOG_DEBUG) { - BIO_set_callback(SSL_get_rbio(ssl), ssl_io_data_cb); - BIO_set_callback_arg(SSL_get_rbio(ssl), ssl); - } - - /* - * Predefine some client verification results - */ - ap_ctx_set(fb->ctx, "ssl::client::dn", NULL); - ap_ctx_set(fb->ctx, "ssl::verify::error", NULL); - ap_ctx_set(fb->ctx, "ssl::verify::info", NULL); - SSL_set_verify_result(ssl, X509_V_OK); - - /* - * We have to manage a I/O timeout ourself, because Apache - * does it the first time when reading the request, but we're - * working some time before this happens. - */ - ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)FALSE); - ap_set_callback_and_alarm(ssl_hook_TimeoutConnection, srvr->timeout); - - /* - * Now enter the SSL Handshake Phase - */ - while (!SSL_is_init_finished(ssl)) { - - if ((rc = SSL_accept(ssl)) <= 0) { - - if (SSL_get_error(ssl, rc) == SSL_ERROR_ZERO_RETURN) { - /* - * The case where the connection was closed before any data - * was transferred. That's not a real error and can occur - * sporadically with some clients. - */ - ssl_log(srvr, SSL_LOG_INFO, - "SSL handshake stopped: connection was closed"); - SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); - SSL_smart_shutdown(ssl); - SSL_free(ssl); - ap_ctx_set(fb->ctx, "ssl", NULL); - ap_bsetflag(fb, B_EOF|B_EOUT, 1); - conn->aborted = 1; - return; - } - else if (ERR_GET_REASON(ERR_peek_error()) == SSL_R_HTTP_REQUEST) { - /* - * The case where OpenSSL has recognized a HTTP request: - * This means the client speaks plain HTTP on our HTTPS - * port. Hmmmm... At least for this error we can be more friendly - * and try to provide him with a HTML error page. We have only one - * problem: OpenSSL has already read some bytes from the HTTP - * request. So we have to skip the request line manually and - * instead provide a faked one in order to continue the internal - * Apache processing. - * - */ - char ca[2]; - int rv; - - /* log the situation */ - ssl_log(srvr, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "SSL handshake failed: HTTP spoken on HTTPS port; " - "trying to send HTML error page"); - - /* first: skip the remaining bytes of the request line */ - do { - do { - rv = read(fb->fd, ca, 1); - } while (rv == -1 && errno == EINTR); - } while (rv > 0 && ca[0] != '\012' /*LF*/); - - /* second: fake the request line */ - fb->inbase = ap_palloc(fb->pool, fb->bufsiz); - ap_cpystrn((char *)fb->inbase, "GET /mod_ssl:error:HTTP-request HTTP/1.0\r\n", - fb->bufsiz); - fb->inptr = fb->inbase; - fb->incnt = strlen((char *)fb->inptr); - - /* third: kick away the SSL stuff */ - SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); - SSL_smart_shutdown(ssl); - SSL_free(ssl); - ap_ctx_set(fb->ctx, "ssl", NULL); - - /* finally: let Apache go on with processing */ - return; - } - else if (ap_ctx_get(ap_global_ctx, "ssl::handshake::timeout") == (void *)TRUE) { - ssl_log(srvr, SSL_LOG_ERROR, - "SSL handshake timed out (client %s, server %s)", - conn->remote_ip != NULL ? conn->remote_ip : "unknown", cpVHostID); - SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); - SSL_smart_shutdown(ssl); - SSL_free(ssl); - ap_ctx_set(fb->ctx, "ssl", NULL); - ap_bsetflag(fb, B_EOF|B_EOUT, 1); - conn->aborted = 1; - return; - } - else if (SSL_get_error(ssl, rc) == SSL_ERROR_SYSCALL) { - if (errno == EINTR) - continue; - if (errno > 0) - ssl_log(srvr, SSL_LOG_ERROR|SSL_ADD_SSLERR|SSL_ADD_ERRNO, - "SSL handshake interrupted by system " - "[Hint: Stop button pressed in browser?!]"); - else - ssl_log(srvr, SSL_LOG_INFO|SSL_ADD_SSLERR|SSL_ADD_ERRNO, - "Spurious SSL handshake interrupt" - "[Hint: Usually just one of those OpenSSL confusions!?]"); - SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); - SSL_smart_shutdown(ssl); - SSL_free(ssl); - ap_ctx_set(fb->ctx, "ssl", NULL); - ap_bsetflag(fb, B_EOF|B_EOUT, 1); - conn->aborted = 1; - return; - } - else { - /* - * Ok, anything else is a fatal error - */ - ssl_log(srvr, SSL_LOG_ERROR|SSL_ADD_SSLERR|SSL_ADD_ERRNO, - "SSL handshake failed (server %s, client %s)", cpVHostID, - conn->remote_ip != NULL ? conn->remote_ip : "unknown"); - - /* - * try to gracefully shutdown the connection: - * - send an own shutdown message (be gracefully) - * - don't wait for peer's shutdown message (deadloop) - * - kick away the SSL stuff immediately - * - block the socket, so Apache cannot operate any more - */ - SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); - SSL_smart_shutdown(ssl); - SSL_free(ssl); - ap_ctx_set(fb->ctx, "ssl", NULL); - ap_bsetflag(fb, B_EOF|B_EOUT, 1); - conn->aborted = 1; - return; - } - } - - /* - * Check for failed client authentication - */ - if ( SSL_get_verify_result(ssl) != X509_V_OK - || ap_ctx_get(fb->ctx, "ssl::verify::error") != NULL) { - cp = (char *)ap_ctx_get(fb->ctx, "ssl::verify::error"); - ssl_log(srvr, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "SSL client authentication failed: %s", - cp != NULL ? cp : "unknown reason"); - SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); - SSL_smart_shutdown(ssl); - SSL_free(ssl); - ap_ctx_set(fb->ctx, "ssl", NULL); - ap_bsetflag(fb, B_EOF|B_EOUT, 1); - conn->aborted = 1; - return; - } - - /* - * Remember the peer certificate's DN - */ - if ((xs = SSL_get_peer_certificate(ssl)) != NULL) { - cp = X509_NAME_oneline(X509_get_subject_name(xs), NULL, 0); - ap_ctx_set(fb->ctx, "ssl::client::dn", ap_pstrdup(conn->pool, cp)); - free(cp); - } - - /* - * Make really sure that when a peer certificate - * is required we really got one... (be paranoid) - */ - if ( sc->nVerifyClient == SSL_CVERIFY_REQUIRE - && ap_ctx_get(fb->ctx, "ssl::client::dn") == NULL) { - ssl_log(srvr, SSL_LOG_ERROR, - "No acceptable peer certificate available"); - SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); - SSL_smart_shutdown(ssl); - SSL_free(ssl); - ap_ctx_set(fb->ctx, "ssl", NULL); - ap_bsetflag(fb, B_EOF|B_EOUT, 1); - conn->aborted = 1; - return; - } - } - - /* - * Remove the timeout handling - */ - ap_set_callback_and_alarm(NULL, 0); - ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)FALSE); - - /* - * Improve I/O throughput by using - * OpenSSL's read-ahead functionality - * (don't used under Win32, because - * there we use select()) - */ -#ifndef WIN32 - SSL_set_read_ahead(ssl, TRUE); -#endif - -#ifdef SSL_VENDOR - /* Allow vendors to do more things on connection time... */ - ap_hook_use("ap::mod_ssl::vendor::new_connection", - AP_HOOK_SIG2(void,ptr), AP_HOOK_ALL, conn); -#endif - - return; -} - -/* - * Signal handler function for the SSL handshake phase - */ -void ssl_hook_TimeoutConnection(int sig) -{ - /* we just set a flag for the handshake processing loop */ - ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)TRUE); - return; -} - -/* - * Close the SSL part of the socket connection - * (called immediately _before_ the socket is closed) - */ -void ssl_hook_CloseConnection(conn_rec *conn) -{ - SSL *ssl; - char *cpType; - - ssl = ap_ctx_get(conn->client->ctx, "ssl"); - if (ssl == NULL) - return; - - /* - * First make sure that no more data is pending in Apache's BUFF, - * because when it's (implicitly) flushed later by the ap_bclose() - * calls of Apache it would lead to an I/O error in the browser due - * to the fact that the SSL layer was already removed by us. - */ - ap_bflush(conn->client); - - /* - * Now close the SSL layer of the connection. We've to take - * the TLSv1 standard into account here: - * - * | 7.2.1. Closure alerts - * | - * | The client and the server must share knowledge that the connection is - * | ending in order to avoid a truncation attack. Either party may - * | initiate the exchange of closing messages. - * | - * | close_notify - * | This message notifies the recipient that the sender will not send - * | any more messages on this connection. The session becomes - * | unresumable if any connection is terminated without proper - * | close_notify messages with level equal to warning. - * | - * | Either party may initiate a close by sending a close_notify alert. - * | Any data received after a closure alert is ignored. - * | - * | Each party is required to send a close_notify alert before closing - * | the write side of the connection. It is required that the other party - * | respond with a close_notify alert of its own and close down the - * | connection immediately, discarding any pending writes. It is not - * | required for the initiator of the close to wait for the responding - * | close_notify alert before closing the read side of the connection. - * - * This means we've to send a close notify message, but haven't to wait - * for the close notify of the client. Actually we cannot wait for the - * close notify of the client because some clients (including Netscape - * 4.x) don't send one, so we would hang. - */ - - /* - * exchange close notify messages, but allow the user - * to force the type of handshake via SetEnvIf directive - */ - if (ap_ctx_get(conn->client->ctx, "ssl::flag::unclean-shutdown") == PTRUE) { - /* perform no close notify handshake at all - (violates the SSL/TLS standard!) */ - SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); - cpType = "unclean"; - } - else if (ap_ctx_get(conn->client->ctx, "ssl::flag::accurate-shutdown") == PTRUE) { - /* send close notify and wait for clients close notify - (standard compliant, but usually causes connection hangs) */ - SSL_set_shutdown(ssl, 0); - cpType = "accurate"; - } - else { - /* send close notify, but don't wait for clients close notify - (standard compliant and safe, so it's the DEFAULT!) */ - SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); - cpType = "standard"; - } - SSL_smart_shutdown(ssl); - - /* deallocate the SSL connection */ - SSL_free(ssl); - ap_ctx_set(conn->client->ctx, "ssl", NULL); - - /* and finally log the fact that we've closed the connection */ - ssl_log(conn->server, SSL_LOG_INFO, - "Connection to child %d closed with %s shutdown (server %s, client %s)", - conn->child_num, cpType, ssl_util_vhostid(conn->pool, conn->server), - conn->remote_ip != NULL ? conn->remote_ip : "unknown"); - return; -} - -/* - * Post Read Request Handler - */ -int ssl_hook_ReadReq(request_rec *r) -{ - SSL *ssl; - ap_ctx *apctx; - - /* - * Get the SSL connection structure and perform the - * delayed interlinking from SSL back to request_rec - */ - ssl = ap_ctx_get(r->connection->client->ctx, "ssl"); - if (ssl != NULL) { - apctx = SSL_get_app_data2(ssl); - ap_ctx_set(apctx, "ssl::request_rec", r); - } - - /* - * Force the mod_ssl content handler when URL indicates this - */ - if (strEQn(r->uri, "/mod_ssl:", 9)) - r->handler = "mod_ssl:content-handler"; - if (ssl != NULL) { - ap_ctx_set(r->ctx, "ap::http::method", "https"); - ap_ctx_set(r->ctx, "ap::default::port", "443"); - } - else { - ap_ctx_set(r->ctx, "ap::http::method", NULL); - ap_ctx_set(r->ctx, "ap::default::port", NULL); - } - return DECLINED; -} - -/* - * URL Translation Handler - */ -int ssl_hook_Translate(request_rec *r) -{ - if (ap_ctx_get(r->connection->client->ctx, "ssl") == NULL) - return DECLINED; - - /* - * Log information about incoming HTTPS requests - */ - if (ap_is_initial_req(r)) - ssl_log(r->server, SSL_LOG_INFO, - "%s HTTPS request received for child %d (server %s)", - r->connection->keepalives <= 0 ? - "Initial (No.1)" : - ap_psprintf(r->pool, "Subsequent (No.%d)", - r->connection->keepalives+1), - r->connection->child_num, - ssl_util_vhostid(r->pool, r->server)); - - /* - * Move SetEnvIf information from request_rec to conn_rec/BUFF - * to allow the close connection handler to use them. - */ - if (ap_table_get(r->subprocess_env, "ssl-unclean-shutdown") != NULL) - ap_ctx_set(r->connection->client->ctx, "ssl::flag::unclean-shutdown", PTRUE); - else - ap_ctx_set(r->connection->client->ctx, "ssl::flag::unclean-shutdown", PFALSE); - if (ap_table_get(r->subprocess_env, "ssl-accurate-shutdown") != NULL) - ap_ctx_set(r->connection->client->ctx, "ssl::flag::accurate-shutdown", PTRUE); - else - ap_ctx_set(r->connection->client->ctx, "ssl::flag::accurate-shutdown", PFALSE); - - return DECLINED; -} - -/* - * Content Handler - */ -int ssl_hook_Handler(request_rec *r) -{ - int port; - char *thisport; - char *thisurl; - - if (strNEn(r->uri, "/mod_ssl:", 9)) - return DECLINED; - - if (strEQ(r->uri, "/mod_ssl:error:HTTP-request")) { - thisport = ""; - port = ap_get_server_port(r); - if (!ap_is_default_port(port, r)) - thisport = ap_psprintf(r->pool, ":%u", port); - thisurl = ap_psprintf(r->pool, "https://%s%s/", - ap_get_server_name(r), thisport); - - ap_table_setn(r->notes, "error-notes", ap_psprintf(r->pool, - "Reason: You're speaking plain HTTP to an SSL-enabled server port.<BR>\n" - "Instead use the HTTPS scheme to access this URL, please.<BR>\n" - "<BLOCKQUOTE>Hint: <A HREF=\"%s\"><B>%s</B></A></BLOCKQUOTE>", - thisurl, thisurl)); - } - - return HTTP_BAD_REQUEST; -} - -/* - * Access Handler - */ -int ssl_hook_Access(request_rec *r) -{ - SSLDirConfigRec *dc; - SSLSrvConfigRec *sc; - SSL *ssl; - SSL_CTX *ctx = NULL; - array_header *apRequirement; - ssl_require_t *pRequirements; - ssl_require_t *pRequirement; - char *cp; - int ok; - int i; - BOOL renegotiate; - BOOL renegotiate_quick; -#ifdef SSL_EXPERIMENTAL_PERDIRCA - BOOL reconfigured_locations; - STACK_OF(X509_NAME) *skCAList; - char *cpCAPath; - char *cpCAFile; -#endif - X509 *cert; - STACK_OF(X509) *certstack; - X509_STORE *certstore; - X509_STORE_CTX certstorectx; - int depth; - STACK_OF(SSL_CIPHER) *skCipherOld; - STACK_OF(SSL_CIPHER) *skCipher; - SSL_CIPHER *pCipher; - ap_ctx *apctx; - int nVerifyOld; - int nVerify; - int n; - void *vp; - int rc; - - dc = myDirConfig(r); - sc = mySrvConfig(r->server); - ssl = ap_ctx_get(r->connection->client->ctx, "ssl"); - if (ssl != NULL) - ctx = SSL_get_SSL_CTX(ssl); - - /* - * Support for SSLRequireSSL directive - */ - if (dc->bSSLRequired && ssl == NULL) { - ap_log_reason("SSL connection required", r->filename, r); - /* remember forbidden access for strict require option */ - ap_table_setn(r->notes, "ssl-access-forbidden", (void *)1); - return FORBIDDEN; - } - - /* - * Check to see if SSL protocol is on - */ - if (!sc->bEnabled) - return DECLINED; - if (ssl == NULL) - return DECLINED; - - /* - * Support for per-directory reconfigured SSL connection parameters. - * - * This is implemented by forcing an SSL renegotiation with the - * reconfigured parameter suite. But Apache's internal API processing - * makes our life very hard here, because when internal sub-requests occur - * we nevertheless should avoid multiple unnecessary SSL handshakes (they - * require extra network I/O and especially time to perform). - * - * But the optimization for filtering out the unnecessary handshakes isn't - * obvious and trivial. Especially because while Apache is in its - * sub-request processing the client could force additional handshakes, - * too. And these take place perhaps without our notice. So the only - * possibility is to explicitly _ask_ OpenSSL whether the renegotiation - * has to be performed or not. It has to performed when some parameters - * which were previously known (by us) are not those we've now - * reconfigured (as known by OpenSSL) or (in optimized way) at least when - * the reconfigured parameter suite is stronger (more restrictions) than - * the currently active one. - */ - renegotiate = FALSE; - renegotiate_quick = FALSE; -#ifdef SSL_EXPERIMENTAL_PERDIRCA - reconfigured_locations = FALSE; -#endif - - /* - * Override of SSLCipherSuite - * - * We provide two options here: - * - * o The paranoid and default approach where we force a renegotiation when - * the cipher suite changed in _any_ way (which is straight-forward but - * often forces renegotiations too often and is perhaps not what the - * user actually wanted). - * - * o The optimized and still secure way where we force a renegotiation - * only if the currently active cipher is no longer contained in the - * reconfigured/new cipher suite. Any other changes are not important - * because it's the servers choice to select a cipher from the ones the - * client supports. So as long as the current cipher is still in the new - * cipher suite we're happy. Because we can assume we would have - * selected it again even when other (better) ciphers exists now in the - * new cipher suite. This approach is fine because the user explicitly - * has to enable this via ``SSLOptions +OptRenegotiate''. So we do no - * implicit optimizations. - */ - if (dc->szCipherSuite != NULL) { - /* remember old state */ - pCipher = NULL; - skCipherOld = NULL; - if (dc->nOptions & SSL_OPT_OPTRENEGOTIATE) - pCipher = SSL_get_current_cipher(ssl); - else { - skCipherOld = SSL_get_ciphers(ssl); - if (skCipherOld != NULL) - skCipherOld = sk_SSL_CIPHER_dup(skCipherOld); - } - /* configure new state */ - if (!SSL_set_cipher_list(ssl, dc->szCipherSuite)) { - ssl_log(r->server, SSL_LOG_WARN|SSL_ADD_SSLERR, - "Unable to reconfigure (per-directory) permitted SSL ciphers"); - if (skCipherOld != NULL) - sk_SSL_CIPHER_free(skCipherOld); - return FORBIDDEN; - } - /* determine whether a renegotiation has to be forced */ - skCipher = SSL_get_ciphers(ssl); - if (dc->nOptions & SSL_OPT_OPTRENEGOTIATE) { - /* optimized way */ - if ((pCipher == NULL && skCipher != NULL) || - (pCipher != NULL && skCipher == NULL) ) - renegotiate = TRUE; - else if (pCipher != NULL && skCipher != NULL - && sk_SSL_CIPHER_find(skCipher, pCipher) < 0) { - renegotiate = TRUE; - } - } - else { - /* paranoid way */ - if ((skCipherOld == NULL && skCipher != NULL) || - (skCipherOld != NULL && skCipher == NULL) ) - renegotiate = TRUE; - else if (skCipherOld != NULL && skCipher != NULL) { - for (n = 0; !renegotiate && n < sk_SSL_CIPHER_num(skCipher); n++) { - if (sk_SSL_CIPHER_find(skCipherOld, sk_SSL_CIPHER_value(skCipher, n)) < 0) - renegotiate = TRUE; - } - for (n = 0; !renegotiate && n < sk_SSL_CIPHER_num(skCipherOld); n++) { - if (sk_SSL_CIPHER_find(skCipher, sk_SSL_CIPHER_value(skCipherOld, n)) < 0) - renegotiate = TRUE; - } - } - } - /* cleanup */ - if (skCipherOld != NULL) - sk_SSL_CIPHER_free(skCipherOld); - /* tracing */ - if (renegotiate) - ssl_log(r->server, SSL_LOG_TRACE, - "Reconfigured cipher suite will force renegotiation"); - } - - /* - * override of SSLVerifyDepth - * - * The depth checks are handled by us manually inside the verify callback - * function and not by OpenSSL internally (and our function is aware of - * both the per-server and per-directory contexts). So we cannot ask - * OpenSSL about the currently verify depth. Instead we remember it in our - * ap_ctx attached to the SSL* of OpenSSL. We've to force the - * renegotiation if the reconfigured/new verify depth is less than the - * currently active/remembered verify depth (because this means more - * restriction on the certificate chain). - */ - if (dc->nVerifyDepth != UNSET) { - apctx = SSL_get_app_data2(ssl); - if ((vp = ap_ctx_get(apctx, "ssl::verify::depth")) != NULL) - n = (int)AP_CTX_PTR2NUM(vp); - else - n = sc->nVerifyDepth; - ap_ctx_set(apctx, "ssl::verify::depth", - AP_CTX_NUM2PTR(dc->nVerifyDepth)); - /* determine whether a renegotiation has to be forced */ - if (dc->nVerifyDepth < n) { - renegotiate = TRUE; - ssl_log(r->server, SSL_LOG_TRACE, - "Reduced client verification depth will force renegotiation"); - } - } - - /* - * override of SSLVerifyClient - * - * We force a renegotiation if the reconfigured/new verify type is - * stronger than the currently active verify type. - * - * The order is: none << optional_no_ca << optional << require - * - * Additionally the following optimization is possible here: When the - * currently active verify type is "none" but a client certificate is - * already known/present, it's enough to manually force a client - * verification but at least skip the I/O-intensive renegotation - * handshake. - */ - if (dc->nVerifyClient != SSL_CVERIFY_UNSET) { - /* remember old state */ - nVerifyOld = SSL_get_verify_mode(ssl); - /* configure new state */ - nVerify = SSL_VERIFY_NONE; - if (dc->nVerifyClient == SSL_CVERIFY_REQUIRE) - nVerify |= SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT; - if ( (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL) - || (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA) ) - nVerify |= SSL_VERIFY_PEER; - SSL_set_verify(ssl, nVerify, ssl_callback_SSLVerify); - SSL_set_verify_result(ssl, X509_V_OK); - /* determine whether we've to force a renegotiation */ - if (nVerify != nVerifyOld) { - if ( ( (nVerifyOld == SSL_VERIFY_NONE) - && (nVerify != SSL_VERIFY_NONE)) - || ( !(nVerifyOld & SSL_VERIFY_PEER) - && (nVerify & SSL_VERIFY_PEER)) - || ( !(nVerifyOld & (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) - && (nVerify & (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT)))) { - renegotiate = TRUE; - /* optimization */ - if ( dc->nOptions & SSL_OPT_OPTRENEGOTIATE - && nVerifyOld == SSL_VERIFY_NONE - && SSL_get_peer_certificate(ssl) != NULL) - renegotiate_quick = TRUE; - ssl_log(r->server, SSL_LOG_TRACE, - "Changed client verification type will force %srenegotiation", - renegotiate_quick ? "quick " : ""); - } - } - } - - /* - * override SSLCACertificateFile & SSLCACertificatePath - * This is tagged experimental because it has to use an ugly kludge: We - * have to change the locations inside the SSL_CTX* (per-server global) - * instead inside SSL* (per-connection local) and reconfigure it to the - * old values later. That's problematic at least for the threaded process - * model of Apache under Win32 or when an error occurs. But unless - * OpenSSL provides a SSL_load_verify_locations() function we've no other - * chance to provide this functionality... - */ -#ifdef SSL_EXPERIMENTAL_PERDIRCA - if ( ( dc->szCACertificateFile != NULL - && ( sc->szCACertificateFile == NULL - || ( sc->szCACertificateFile != NULL - && strNE(dc->szCACertificateFile, sc->szCACertificateFile)))) - || ( dc->szCACertificatePath != NULL - && ( sc->szCACertificatePath == NULL - || ( sc->szCACertificatePath != NULL - && strNE(dc->szCACertificatePath, sc->szCACertificatePath)))) ) { - cpCAFile = dc->szCACertificateFile != NULL ? - dc->szCACertificateFile : sc->szCACertificateFile; - cpCAPath = dc->szCACertificatePath != NULL ? - dc->szCACertificatePath : sc->szCACertificatePath; - /* - FIXME: This should be... - if (!SSL_load_verify_locations(ssl, cpCAFile, cpCAPath)) { - ...but OpenSSL still doesn't provide this! - */ - if (!SSL_CTX_load_verify_locations(ctx, cpCAFile, cpCAPath)) { - ssl_log(r->server, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Unable to reconfigure verify locations " - "for client authentication"); - return FORBIDDEN; - } - if ((skCAList = ssl_init_FindCAList(r->server, r->pool, - cpCAFile, cpCAPath)) == NULL) { - ssl_log(r->server, SSL_LOG_ERROR, - "Unable to determine list of available " - "CA certificates for client authentication"); - return FORBIDDEN; - } - SSL_set_client_CA_list(ssl, skCAList); - renegotiate = TRUE; - reconfigured_locations = TRUE; - ssl_log(r->server, SSL_LOG_TRACE, - "Changed client verification locations will force renegotiation"); - } -#endif /* SSL_EXPERIMENTAL_PERDIRCA */ - -#ifdef SSL_CONSERVATIVE - /* - * SSL renegotiations in conjunction with HTTP - * requests using the POST method are not supported. - */ - if (renegotiate && r->method_number == M_POST) { - ssl_log(r->server, SSL_LOG_ERROR, - "SSL Re-negotiation in conjunction with POST method not supported!"); - ssl_log(r->server, SSL_LOG_INFO, - "You have to compile without -DSSL_CONSERVATIVE to enabled support for this."); - return METHOD_NOT_ALLOWED; - } -#endif /* SSL_CONSERVATIVE */ - - /* - * now do the renegotiation if anything was actually reconfigured - */ - if (renegotiate) { - /* - * Now we force the SSL renegotation by sending the Hello Request - * message to the client. Here we have to do a workaround: Actually - * OpenSSL returns immediately after sending the Hello Request (the - * intent AFAIK is because the SSL/TLS protocol says it's not a must - * that the client replies to a Hello Request). But because we insist - * on a reply (anything else is an error for us) we have to go to the - * ACCEPT state manually. Using SSL_set_accept_state() doesn't work - * here because it resets too much of the connection. So we set the - * state explicitly and continue the handshake manually. - */ - ssl_log(r->server, SSL_LOG_INFO, "Requesting connection re-negotiation"); - if (renegotiate_quick) { - /* perform just a manual re-verification of the peer */ - ssl_log(r->server, SSL_LOG_TRACE, - "Performing quick renegotiation: just re-verifying the peer"); - certstore = SSL_CTX_get_cert_store(ctx); - if (certstore == NULL) { - ssl_log(r->server, SSL_LOG_ERROR, "Cannot find certificate storage"); - return FORBIDDEN; - } - certstack = SSL_get_peer_cert_chain(ssl); - if (certstack == NULL || sk_X509_num(certstack) == 0) { - ssl_log(r->server, SSL_LOG_ERROR, "Cannot find peer certificate chain"); - return FORBIDDEN; - } - cert = sk_X509_value(certstack, 0); - X509_STORE_CTX_init(&certstorectx, certstore, cert, certstack); - depth = SSL_get_verify_depth(ssl); - if (depth >= 0) - X509_STORE_CTX_set_depth(&certstorectx, depth); - X509_STORE_CTX_set_ex_data(&certstorectx, - SSL_get_ex_data_X509_STORE_CTX_idx(), (char *)ssl); - if (!X509_verify_cert(&certstorectx)) - ssl_log(r->server, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Re-negotiation verification step failed"); - SSL_set_verify_result(ssl, certstorectx.error); - X509_STORE_CTX_cleanup(&certstorectx); - } - else { - /* do a full renegotiation */ - ssl_log(r->server, SSL_LOG_TRACE, - "Performing full renegotiation: complete handshake protocol"); - if (r->main != NULL) - SSL_set_session_id_context(ssl, (unsigned char *)&(r->main), sizeof(r->main)); - else - SSL_set_session_id_context(ssl, (unsigned char *)&r, sizeof(r)); -#ifndef SSL_CONSERVATIVE - ssl_io_suck(r, ssl); -#endif - SSL_renegotiate(ssl); - SSL_do_handshake(ssl); - if (SSL_get_state(ssl) != SSL_ST_OK) { - ssl_log(r->server, SSL_LOG_ERROR, "Re-negotiation request failed"); - return FORBIDDEN; - } - ssl_log(r->server, SSL_LOG_INFO, "Awaiting re-negotiation handshake"); - SSL_set_state(ssl, SSL_ST_ACCEPT); - SSL_do_handshake(ssl); - if (SSL_get_state(ssl) != SSL_ST_OK) { - ssl_log(r->server, SSL_LOG_ERROR, - "Re-negotiation handshake failed: Not accepted by client!?"); - return FORBIDDEN; - } - } - - /* - * Remember the peer certificate's DN - */ - if ((cert = SSL_get_peer_certificate(ssl)) != NULL) { - cp = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); - ap_ctx_set(r->connection->client->ctx, "ssl::client::dn", - ap_pstrdup(r->connection->pool, cp)); - free(cp); - } - - /* - * Finally check for acceptable renegotiation results - */ - if (dc->nVerifyClient != SSL_CVERIFY_NONE) { - if ( dc->nVerifyClient == SSL_CVERIFY_REQUIRE - && SSL_get_verify_result(ssl) != X509_V_OK ) { - ssl_log(r->server, SSL_LOG_ERROR, - "Re-negotiation handshake failed: Client verification failed"); - return FORBIDDEN; - } - if ( dc->nVerifyClient == SSL_CVERIFY_REQUIRE - && SSL_get_peer_certificate(ssl) == NULL ) { - ssl_log(r->server, SSL_LOG_ERROR, - "Re-negotiation handshake failed: Client certificate missing"); - return FORBIDDEN; - } - } - } - - /* - * Under old OpenSSL we had to change the X509_STORE inside the - * SSL_CTX instead inside the SSL structure, so we have to reconfigure it - * to the old values. This should be changed with forthcoming OpenSSL - * versions when better functionality is avaiable. - */ -#ifdef SSL_EXPERIMENTAL_PERDIRCA - if (renegotiate && reconfigured_locations) { - if (!SSL_CTX_load_verify_locations(ctx, - sc->szCACertificateFile, sc->szCACertificatePath)) { - ssl_log(r->server, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Unable to reconfigure verify locations " - "to per-server configuration parameters"); - return FORBIDDEN; - } - } -#endif /* SSL_EXPERIMENTAL_PERDIRCA */ - - /* - * Check SSLRequire boolean expressions - */ - apRequirement = dc->aRequirement; - pRequirements = (ssl_require_t *)apRequirement->elts; - for (i = 0; i < apRequirement->nelts; i++) { - pRequirement = &pRequirements[i]; - ok = ssl_expr_exec(r, pRequirement->mpExpr); - if (ok < 0) { - cp = ap_psprintf(r->pool, "Failed to execute SSL requirement expression: %s", - ssl_expr_get_error()); - ap_log_reason(cp, r->filename, r); - /* remember forbidden access for strict require option */ - ap_table_setn(r->notes, "ssl-access-forbidden", (void *)1); - return FORBIDDEN; - } - if (ok != 1) { - ssl_log(r->server, SSL_LOG_INFO, - "Access to %s denied for %s (requirement expression not fulfilled)", - r->filename, r->connection->remote_ip); - ssl_log(r->server, SSL_LOG_INFO, - "Failed expression: %s", pRequirement->cpExpr); - ap_log_reason("SSL requirement expression not fulfilled " - "(see SSL logfile for more details)", r->filename, r); - /* remember forbidden access for strict require option */ - ap_table_setn(r->notes, "ssl-access-forbidden", (void *)1); - return FORBIDDEN; - } - } - - /* - * Else access is granted from our point of view (except vendor - * handlers override). But we have to return DECLINED here instead - * of OK, because mod_auth and other modules still might want to - * deny access. - */ - rc = DECLINED; -#ifdef SSL_VENDOR - ap_hook_use("ap::mod_ssl::vendor::access_handler", - AP_HOOK_SIG2(int,ptr), AP_HOOK_DECLINE(DECLINED), - &rc, r); -#endif - return rc; -} - -/* - * Auth Handler: - * Fake a Basic authentication from the X509 client certificate. - * - * This must be run fairly early on to prevent a real authentication from - * occuring, in particular it must be run before anything else that - * authenticates a user. This means that the Module statement for this - * module should be LAST in the Configuration file. - */ -int ssl_hook_Auth(request_rec *r) -{ - SSLSrvConfigRec *sc = mySrvConfig(r->server); - SSLDirConfigRec *dc = myDirConfig(r); - char b1[MAX_STRING_LEN], b2[MAX_STRING_LEN]; - char *clientdn; - const char *cpAL; - const char *cpUN; - const char *cpPW; - - /* - * Additionally forbid access (again) - * when strict require option is used. - */ - if ( (dc->nOptions & SSL_OPT_STRICTREQUIRE) - && (ap_table_get(r->notes, "ssl-access-forbidden") != NULL)) - return FORBIDDEN; - - /* - * Make sure the user is not able to fake the client certificate - * based authentication by just entering an X.509 Subject DN - * ("/XX=YYY/XX=YYY/..") as the username and "password" as the - * password. - */ - if ((cpAL = ap_table_get(r->headers_in, "Authorization")) != NULL) { - if (strcEQ(ap_getword(r->pool, &cpAL, ' '), "Basic")) { - while (*cpAL == ' ' || *cpAL == '\t') - cpAL++; - cpAL = ap_pbase64decode(r->pool, cpAL); - cpUN = ap_getword_nulls(r->pool, &cpAL, ':'); - cpPW = cpAL; - if (cpUN[0] == '/' && strEQ(cpPW, "password")) - return FORBIDDEN; - } - } - - /* - * We decline operation in various situations... - */ - if (!sc->bEnabled) - return DECLINED; - if (ap_ctx_get(r->connection->client->ctx, "ssl") == NULL) - return DECLINED; - if (!(dc->nOptions & SSL_OPT_FAKEBASICAUTH)) - return DECLINED; - if (r->connection->user) - return DECLINED; - if ((clientdn = (char *)ap_ctx_get(r->connection->client->ctx, "ssl::client::dn")) == NULL) - return DECLINED; - - /* - * Fake a password - which one would be immaterial, as, it seems, an empty - * password in the users file would match ALL incoming passwords, if only - * we were using the standard crypt library routine. Unfortunately, OpenSSL - * "fixes" a "bug" in crypt and thus prevents blank passwords from - * working. (IMHO what they really fix is a bug in the users of the code - * - failing to program correctly for shadow passwords). We need, - * therefore, to provide a password. This password can be matched by - * adding the string "xxj31ZMTZzkVA" as the password in the user file. - * This is just the crypted variant of the word "password" ;-) - */ - ap_snprintf(b1, sizeof(b1), "%s:password", clientdn); - ssl_util_uuencode(b2, b1, FALSE); - ap_snprintf(b1, sizeof(b1), "Basic %s", b2); - ap_table_set(r->headers_in, "Authorization", b1); - ssl_log(r->server, SSL_LOG_INFO, - "Faking HTTP Basic Auth header: \"Authorization: %s\"", b1); - - return DECLINED; -} - -int ssl_hook_UserCheck(request_rec *r) -{ - SSLDirConfigRec *dc = myDirConfig(r); - - /* - * Additionally forbid access (again) - * when strict require option is used. - */ - if ( (dc->nOptions & SSL_OPT_STRICTREQUIRE) - && (ap_table_get(r->notes, "ssl-access-forbidden") != NULL)) - return FORBIDDEN; - - return DECLINED; -} - -/* - * Fixup Handler - */ - -static const char *ssl_hook_Fixup_vars[] = { - "SSL_VERSION_INTERFACE", - "SSL_VERSION_LIBRARY", - "SSL_PROTOCOL", - "SSL_CIPHER", - "SSL_CIPHER_EXPORT", - "SSL_CIPHER_USEKEYSIZE", - "SSL_CIPHER_ALGKEYSIZE", - "SSL_CLIENT_VERIFY", - "SSL_CLIENT_M_VERSION", - "SSL_CLIENT_M_SERIAL", - "SSL_CLIENT_V_START", - "SSL_CLIENT_V_END", - "SSL_CLIENT_S_DN", - "SSL_CLIENT_S_DN_C", - "SSL_CLIENT_S_DN_ST", - "SSL_CLIENT_S_DN_L", - "SSL_CLIENT_S_DN_O", - "SSL_CLIENT_S_DN_OU", - "SSL_CLIENT_S_DN_CN", - "SSL_CLIENT_S_DN_T", - "SSL_CLIENT_S_DN_I", - "SSL_CLIENT_S_DN_G", - "SSL_CLIENT_S_DN_S", - "SSL_CLIENT_S_DN_D", - "SSL_CLIENT_S_DN_UID", - "SSL_CLIENT_S_DN_Email", - "SSL_CLIENT_I_DN", - "SSL_CLIENT_I_DN_C", - "SSL_CLIENT_I_DN_ST", - "SSL_CLIENT_I_DN_L", - "SSL_CLIENT_I_DN_O", - "SSL_CLIENT_I_DN_OU", - "SSL_CLIENT_I_DN_CN", - "SSL_CLIENT_I_DN_T", - "SSL_CLIENT_I_DN_I", - "SSL_CLIENT_I_DN_G", - "SSL_CLIENT_I_DN_S", - "SSL_CLIENT_I_DN_D", - "SSL_CLIENT_I_DN_UID", - "SSL_CLIENT_I_DN_Email", - "SSL_CLIENT_A_KEY", - "SSL_CLIENT_A_SIG", - "SSL_SERVER_M_VERSION", - "SSL_SERVER_M_SERIAL", - "SSL_SERVER_V_START", - "SSL_SERVER_V_END", - "SSL_SERVER_S_DN", - "SSL_SERVER_S_DN_C", - "SSL_SERVER_S_DN_ST", - "SSL_SERVER_S_DN_L", - "SSL_SERVER_S_DN_O", - "SSL_SERVER_S_DN_OU", - "SSL_SERVER_S_DN_CN", - "SSL_SERVER_S_DN_T", - "SSL_SERVER_S_DN_I", - "SSL_SERVER_S_DN_G", - "SSL_SERVER_S_DN_S", - "SSL_SERVER_S_DN_D", - "SSL_SERVER_S_DN_UID", - "SSL_SERVER_S_DN_Email", - "SSL_SERVER_I_DN", - "SSL_SERVER_I_DN_C", - "SSL_SERVER_I_DN_ST", - "SSL_SERVER_I_DN_L", - "SSL_SERVER_I_DN_O", - "SSL_SERVER_I_DN_OU", - "SSL_SERVER_I_DN_CN", - "SSL_SERVER_I_DN_T", - "SSL_SERVER_I_DN_I", - "SSL_SERVER_I_DN_G", - "SSL_SERVER_I_DN_S", - "SSL_SERVER_I_DN_D", - "SSL_SERVER_I_DN_UID", - "SSL_SERVER_I_DN_Email", - "SSL_SERVER_A_KEY", - "SSL_SERVER_A_SIG", - "SSL_SESSION_ID", - NULL -}; - -int ssl_hook_Fixup(request_rec *r) -{ - SSLSrvConfigRec *sc = mySrvConfig(r->server); - SSLDirConfigRec *dc = myDirConfig(r); - table *e = r->subprocess_env; - char *var; - char *val; - STACK_OF(X509) *sk; - SSL *ssl; - int i; - - /* - * Check to see if SSL is on - */ - if (!sc->bEnabled) - return DECLINED; - if ((ssl = ap_ctx_get(r->connection->client->ctx, "ssl")) == NULL) - return DECLINED; - - /* - * Annotate the SSI/CGI environment with standard SSL information - */ - /* the always present HTTPS (=HTTP over SSL) flag! */ - ap_table_set(e, "HTTPS", "on"); - /* standard SSL environment variables */ - if (dc->nOptions & SSL_OPT_STDENVVARS) { - for (i = 0; ssl_hook_Fixup_vars[i] != NULL; i++) { - var = (char *)ssl_hook_Fixup_vars[i]; - val = ssl_var_lookup(r->pool, r->server, r->connection, r, var); - if (!strIsEmpty(val)) - ap_table_set(e, var, val); - } - } - - /* - * On-demand bloat up the SSI/CGI environment with certificate data - */ - if (dc->nOptions & SSL_OPT_EXPORTCERTDATA) { - val = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_SERVER_CERT"); - ap_table_set(e, "SSL_SERVER_CERT", val); - val = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_CERT"); - ap_table_set(e, "SSL_CLIENT_CERT", val); - if ((sk = SSL_get_peer_cert_chain(ssl)) != NULL) { - for (i = 0; i < sk_X509_num(sk); i++) { - var = ap_psprintf(r->pool, "SSL_CLIENT_CERT_CHAIN_%d", i); - val = ssl_var_lookup(r->pool, r->server, r->connection, r, var); - if (val != NULL) - ap_table_set(e, var, val); - } - } - } - - /* - * On-demand bloat up the SSI/CGI environment with compat variables - */ -#ifdef SSL_COMPAT - if (dc->nOptions & SSL_OPT_COMPATENVVARS) - ssl_compat_variables(r); -#endif - - return DECLINED; -} - -/* _________________________________________________________________ -** -** OpenSSL Callback Functions -** _________________________________________________________________ -*/ - -/* - * Handle out temporary RSA private keys on demand - * - * The background of this as the TLSv1 standard explains it: - * - * | D.1. Temporary RSA keys - * | - * | US Export restrictions limit RSA keys used for encryption to 512 - * | bits, but do not place any limit on lengths of RSA keys used for - * | signing operations. Certificates often need to be larger than 512 - * | bits, since 512-bit RSA keys are not secure enough for high-value - * | transactions or for applications requiring long-term security. Some - * | certificates are also designated signing-only, in which case they - * | cannot be used for key exchange. - * | - * | When the public key in the certificate cannot be used for encryption, - * | the server signs a temporary RSA key, which is then exchanged. In - * | exportable applications, the temporary RSA key should be the maximum - * | allowable length (i.e., 512 bits). Because 512-bit RSA keys are - * | relatively insecure, they should be changed often. For typical - * | electronic commerce applications, it is suggested that keys be - * | changed daily or every 500 transactions, and more often if possible. - * | Note that while it is acceptable to use the same temporary key for - * | multiple transactions, it must be signed each time it is used. - * | - * | RSA key generation is a time-consuming process. In many cases, a - * | low-priority process can be assigned the task of key generation. - * | Whenever a new key is completed, the existing temporary key can be - * | replaced with the new one. - * - * So we generated 512 and 1024 bit temporary keys on startup - * which we now just handle out on demand.... - */ -RSA *ssl_callback_TmpRSA(SSL *pSSL, int nExport, int nKeyLen) -{ - SSLModConfigRec *mc = myModConfig(); - RSA *rsa; - - rsa = NULL; - if (nExport) { - /* It's because an export cipher is used */ - if (nKeyLen == 512) - rsa = (RSA *)mc->pTmpKeys[SSL_TKPIDX_RSA512]; - else if (nKeyLen == 1024) - rsa = (RSA *)mc->pTmpKeys[SSL_TKPIDX_RSA1024]; - else - /* it's too expensive to generate on-the-fly, so keep 1024bit */ - rsa = (RSA *)mc->pTmpKeys[SSL_TKPIDX_RSA1024]; - } - else { - /* It's because a sign-only certificate situation exists */ - rsa = (RSA *)mc->pTmpKeys[SSL_TKPIDX_RSA1024]; - } - return rsa; -} - -/* - * Handle out the already generated DH parameters... - */ -DH *ssl_callback_TmpDH(SSL *pSSL, int nExport, int nKeyLen) -{ - SSLModConfigRec *mc = myModConfig(); - DH *dh; - - dh = NULL; - if (nExport) { - /* It's because an export cipher is used */ - if (nKeyLen == 512) - dh = (DH *)mc->pTmpKeys[SSL_TKPIDX_DH512]; - else if (nKeyLen == 1024) - dh = (DH *)mc->pTmpKeys[SSL_TKPIDX_DH1024]; - else - /* it's too expensive to generate on-the-fly, so keep 1024bit */ - dh = (DH *)mc->pTmpKeys[SSL_TKPIDX_DH1024]; - } - else { - /* It's because a sign-only certificate situation exists */ - dh = (DH *)mc->pTmpKeys[SSL_TKPIDX_DH1024]; - } - return dh; -} - -/* - * This OpenSSL callback function is called when OpenSSL - * does client authentication and verifies the certificate chain. - */ -int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx) -{ - SSL *ssl; - conn_rec *conn; - server_rec *s; - request_rec *r; - SSLSrvConfigRec *sc; - SSLDirConfigRec *dc; - ap_ctx *actx; - X509 *xs; - int errnum; - int errdepth; - char *cp; - char *cp2; - int depth; - int verify; - - /* - * Get Apache context back through OpenSSL context - */ - ssl = (SSL *)X509_STORE_CTX_get_app_data(ctx); - conn = (conn_rec *)SSL_get_app_data(ssl); - actx = (ap_ctx *)SSL_get_app_data2(ssl); - r = (request_rec *)ap_ctx_get(actx, "ssl::request_rec"); - s = conn->server; - sc = mySrvConfig(s); - dc = (r != NULL ? myDirConfig(r) : NULL); - - /* - * Get verify ingredients - */ - xs = X509_STORE_CTX_get_current_cert(ctx); - errnum = X509_STORE_CTX_get_error(ctx); - errdepth = X509_STORE_CTX_get_error_depth(ctx); - - /* - * Log verification information - */ - cp = X509_NAME_oneline(X509_get_subject_name(xs), NULL, 0); - cp2 = X509_NAME_oneline(X509_get_issuer_name(xs), NULL, 0); - ssl_log(s, SSL_LOG_TRACE, - "Certificate Verification: depth: %d, subject: %s, issuer: %s", - errdepth, cp != NULL ? cp : "-unknown-", - cp2 != NULL ? cp2 : "-unknown"); - if (cp) - free(cp); - if (cp2) - free(cp2); - - /* - * Check for optionally acceptable non-verifiable issuer situation - */ - if (dc != NULL && dc->nVerifyClient != SSL_CVERIFY_UNSET) - verify = dc->nVerifyClient; - else - verify = sc->nVerifyClient; - if ( ( errnum == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT - || errnum == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN - || errnum == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY -#if SSL_LIBRARY_VERSION >= 0x00905000 - || errnum == X509_V_ERR_CERT_UNTRUSTED -#endif - || errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ) - && verify == SSL_CVERIFY_OPTIONAL_NO_CA ) { - ssl_log(s, SSL_LOG_TRACE, - "Certificate Verification: Verifiable Issuer is configured as " - "optional, therefore we're accepting the certificate"); - ap_ctx_set(conn->client->ctx, "ssl::verify::info", "GENEROUS"); - ok = TRUE; - } - - /* - * Additionally perform CRL-based revocation checks - */ - if (ok) { - ok = ssl_callback_SSLVerify_CRL(ok, ctx, s); - if (!ok) - errnum = X509_STORE_CTX_get_error(ctx); - } - - /* - * If we already know it's not ok, log the real reason - */ - if (!ok) { - ssl_log(s, SSL_LOG_ERROR, "Certificate Verification: Error (%d): %s", - errnum, X509_verify_cert_error_string(errnum)); - ap_ctx_set(conn->client->ctx, "ssl::client::dn", NULL); - ap_ctx_set(conn->client->ctx, "ssl::verify::error", - (void *)X509_verify_cert_error_string(errnum)); - } - - /* - * Finally check the depth of the certificate verification - */ - if (dc != NULL && dc->nVerifyDepth != UNSET) - depth = dc->nVerifyDepth; - else - depth = sc->nVerifyDepth; - if (errdepth > depth) { - ssl_log(s, SSL_LOG_ERROR, - "Certificate Verification: Certificate Chain too long " - "(chain has %d certificates, but maximum allowed are only %d)", - errdepth, depth); - ap_ctx_set(conn->client->ctx, "ssl::verify::error", - (void *)X509_verify_cert_error_string(X509_V_ERR_CERT_CHAIN_TOO_LONG)); - ok = FALSE; - } - - /* - * And finally signal OpenSSL the (perhaps changed) state - */ - return (ok); -} - -int ssl_callback_SSLVerify_CRL( - int ok, X509_STORE_CTX *ctx, server_rec *s) -{ - SSLSrvConfigRec *sc; - X509_OBJECT obj; - X509_NAME *subject; - X509_NAME *issuer; - X509 *xs; - X509_CRL *crl; - X509_REVOKED *revoked; - long serial; - BIO *bio; - int i, n, rc; - char *cp; - char *cp2; - - /* - * Unless a revocation store for CRLs was created we - * cannot do any CRL-based verification, of course. - */ - sc = mySrvConfig(s); - if (sc->pRevocationStore == NULL) - return ok; - - /* - * Determine certificate ingredients in advance - */ - xs = X509_STORE_CTX_get_current_cert(ctx); - subject = X509_get_subject_name(xs); - issuer = X509_get_issuer_name(xs); - - /* - * OpenSSL provides the general mechanism to deal with CRLs but does not - * use them automatically when verifying certificates, so we do it - * explicitly here. We will check the CRL for the currently checked - * certificate, if there is such a CRL in the store. - * - * We come through this procedure for each certificate in the certificate - * chain, starting with the root-CA's certificate. At each step we've to - * both verify the signature on the CRL (to make sure it's a valid CRL) - * and it's revocation list (to make sure the current certificate isn't - * revoked). But because to check the signature on the CRL we need the - * public key of the issuing CA certificate (which was already processed - * one round before), we've a little problem. But we can both solve it and - * at the same time optimize the processing by using the following - * verification scheme (idea and code snippets borrowed from the GLOBUS - * project): - * - * 1. We'll check the signature of a CRL in each step when we find a CRL - * through the _subject_ name of the current certificate. This CRL - * itself will be needed the first time in the next round, of course. - * But we do the signature processing one round before this where the - * public key of the CA is available. - * - * 2. We'll check the revocation list of a CRL in each step when - * we find a CRL through the _issuer_ name of the current certificate. - * This CRLs signature was then already verified one round before. - * - * This verification scheme allows a CA to revoke its own certificate as - * well, of course. - */ - - /* - * Try to retrieve a CRL corresponding to the _subject_ of - * the current certificate in order to verify it's integrity. - */ - memset((char *)&obj, 0, sizeof(obj)); - rc = SSL_X509_STORE_lookup(sc->pRevocationStore, X509_LU_CRL, subject, &obj); - crl = obj.data.crl; - if (rc > 0 && crl != NULL) { - /* - * Log information about CRL - * (A little bit complicated because of ASN.1 and BIOs...) - */ - if (ssl_log_applies(s, SSL_LOG_TRACE)) { - bio = BIO_new(BIO_s_mem()); - BIO_printf(bio, "lastUpdate: "); - ASN1_UTCTIME_print(bio, X509_CRL_get_lastUpdate(crl)); - BIO_printf(bio, ", nextUpdate: "); - ASN1_UTCTIME_print(bio, X509_CRL_get_nextUpdate(crl)); - n = BIO_pending(bio); - cp = malloc(n+1); - n = BIO_read(bio, cp, n); - cp[n] = NUL; - BIO_free(bio); - cp2 = X509_NAME_oneline(subject, NULL, 0); - ssl_log(s, SSL_LOG_TRACE, "CA CRL: Issuer: %s, %s", cp2, cp); - free(cp2); - free(cp); - } - - /* - * Verify the signature on this CRL - */ - if (X509_CRL_verify(crl, X509_get_pubkey(xs)) <= 0) { - ssl_log(s, SSL_LOG_WARN, "Invalid signature on CRL"); - X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); - X509_OBJECT_free_contents(&obj); - return FALSE; - } - - /* - * Check date of CRL to make sure it's not expired - */ - i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl)); - if (i == 0) { - ssl_log(s, SSL_LOG_WARN, "Found CRL has invalid nextUpdate field"); - X509_STORE_CTX_set_error(ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); - X509_OBJECT_free_contents(&obj); - return FALSE; - } - if (i < 0) { - ssl_log(s, SSL_LOG_WARN, - "Found CRL is expired - " - "revoking all certificates until you get updated CRL"); - X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED); - X509_OBJECT_free_contents(&obj); - return FALSE; - } - X509_OBJECT_free_contents(&obj); - } - - /* - * Try to retrieve a CRL corresponding to the _issuer_ of - * the current certificate in order to check for revocation. - */ - memset((char *)&obj, 0, sizeof(obj)); - rc = SSL_X509_STORE_lookup(sc->pRevocationStore, X509_LU_CRL, issuer, &obj); - crl = obj.data.crl; - if (rc > 0 && crl != NULL) { - /* - * Check if the current certificate is revoked by this CRL - */ -#if SSL_LIBRARY_VERSION < 0x00904000 - n = sk_num(X509_CRL_get_REVOKED(crl)); -#else - n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); -#endif - for (i = 0; i < n; i++) { -#if SSL_LIBRARY_VERSION < 0x00904000 - revoked = (X509_REVOKED *)sk_value(X509_CRL_get_REVOKED(crl), i); -#else - revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); -#endif - if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(xs)) == 0) { - - serial = ASN1_INTEGER_get(revoked->serialNumber); - cp = X509_NAME_oneline(issuer, NULL, 0); - ssl_log(s, SSL_LOG_INFO, - "Certificate with serial %ld (0x%lX) " - "revoked per CRL from issuer %s", - serial, serial, cp); - free(cp); - - X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED); - X509_OBJECT_free_contents(&obj); - return FALSE; - } - } - X509_OBJECT_free_contents(&obj); - } - return ok; -} - -/* - * This callback function is executed by OpenSSL whenever a new SSL_SESSION is - * added to the internal OpenSSL session cache. We use this hook to spread the - * SSL_SESSION also to the inter-process disk-cache to make share it with our - * other Apache pre-forked server processes. - */ -int ssl_callback_NewSessionCacheEntry(SSL *ssl, SSL_SESSION *pNew) -{ - conn_rec *conn; - server_rec *s; - SSLSrvConfigRec *sc; - long t; - BOOL rc; - - /* - * Get Apache context back through OpenSSL context - */ - conn = (conn_rec *)SSL_get_app_data(ssl); - s = conn->server; - sc = mySrvConfig(s); - - /* - * Set the timeout also for the internal OpenSSL cache, because this way - * our inter-process cache is consulted only when it's really necessary. - */ - t = sc->nSessionCacheTimeout; - SSL_set_timeout(pNew, t); - - /* - * Store the SSL_SESSION in the inter-process cache with the - * same expire time, so it expires automatically there, too. - */ - t = (SSL_get_time(pNew) + sc->nSessionCacheTimeout); - rc = ssl_scache_store(s, pNew->session_id, pNew->session_id_length, t, pNew); - - /* - * Log this cache operation - */ - ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache: " - "request=SET status=%s id=%s timeout=%ds (session caching)", - rc == TRUE ? "OK" : "BAD", - SSL_SESSION_id2sz(pNew->session_id, pNew->session_id_length), - t-time(NULL)); - - /* - * return 0 which means to OpenSSL that the pNew is still - * valid and was not freed by us with SSL_SESSION_free(). - */ - return 0; -} - -/* - * This callback function is executed by OpenSSL whenever a - * SSL_SESSION is looked up in the internal OpenSSL cache and it - * was not found. We use this to lookup the SSL_SESSION in the - * inter-process disk-cache where it was perhaps stored by one - * of our other Apache pre-forked server processes. - */ -SSL_SESSION *ssl_callback_GetSessionCacheEntry( - SSL *ssl, unsigned char *id, int idlen, int *pCopy) -{ - conn_rec *conn; - server_rec *s; - SSL_SESSION *pSession; - - /* - * Get Apache context back through OpenSSL context - */ - conn = (conn_rec *)SSL_get_app_data(ssl); - s = conn->server; - - /* - * Try to retrieve the SSL_SESSION from the inter-process cache - */ - pSession = ssl_scache_retrieve(s, id, idlen); - - /* - * Log this cache operation - */ - if (pSession != NULL) - ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache: " - "request=GET status=FOUND id=%s (session reuse)", - SSL_SESSION_id2sz(id, idlen)); - else - ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache: " - "request=GET status=MISSED id=%s (session renewal)", - SSL_SESSION_id2sz(id, idlen)); - - /* - * Return NULL or the retrieved SSL_SESSION. But indicate (by - * setting pCopy to 0) that the reference count on the - * SSL_SESSION should not be incremented by the SSL library, - * because we will no longer hold a reference to it ourself. - */ - *pCopy = 0; - return pSession; -} - -/* - * This callback function is executed by OpenSSL whenever a - * SSL_SESSION is removed from the the internal OpenSSL cache. - * We use this to remove the SSL_SESSION in the inter-process - * disk-cache, too. - */ -void ssl_callback_DelSessionCacheEntry( - SSL_CTX *ctx, SSL_SESSION *pSession) -{ - server_rec *s; - - /* - * Get Apache context back through OpenSSL context - */ - s = (server_rec *)SSL_CTX_get_app_data(ctx); - if (s == NULL) /* on server shutdown Apache is already gone */ - return; - - /* - * Remove the SSL_SESSION from the inter-process cache - */ - ssl_scache_remove(s, pSession->session_id, pSession->session_id_length); - - /* - * Log this cache operation - */ - ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache: " - "request=REM status=OK id=%s (session dead)", - SSL_SESSION_id2sz(pSession->session_id, - pSession->session_id_length)); - - return; -} - -/* - * This callback function is executed while OpenSSL processes the - * SSL handshake and does SSL record layer stuff. We use it to - * trace OpenSSL's processing in out SSL logfile. - */ -void ssl_callback_LogTracingState(SSL *ssl, int where, int rc) -{ - conn_rec *c; - server_rec *s; - SSLSrvConfigRec *sc; - char *str; - - /* - * find corresponding server - */ - if ((c = (conn_rec *)SSL_get_app_data(ssl)) == NULL) - return; - s = c->server; - if ((sc = mySrvConfig(s)) == NULL) - return; - - /* - * create the various trace messages - */ - if (sc->nLogLevel >= SSL_LOG_TRACE) { - if (where & SSL_CB_HANDSHAKE_START) - ssl_log(s, SSL_LOG_TRACE, "%s: Handshake: start", SSL_LIBRARY_NAME); - else if (where & SSL_CB_HANDSHAKE_DONE) - ssl_log(s, SSL_LOG_TRACE, "%s: Handshake: done", SSL_LIBRARY_NAME); - else if (where & SSL_CB_LOOP) - ssl_log(s, SSL_LOG_TRACE, "%s: Loop: %s", - SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); - else if (where & SSL_CB_READ) - ssl_log(s, SSL_LOG_TRACE, "%s: Read: %s", - SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); - else if (where & SSL_CB_WRITE) - ssl_log(s, SSL_LOG_TRACE, "%s: Write: %s", - SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); - else if (where & SSL_CB_ALERT) { - str = (where & SSL_CB_READ) ? "read" : "write"; - ssl_log(s, SSL_LOG_TRACE, "%s: Alert: %s:%s:%s\n", - SSL_LIBRARY_NAME, str, - SSL_alert_type_string_long(rc), - SSL_alert_desc_string_long(rc)); - } - else if (where & SSL_CB_EXIT) { - if (rc == 0) - ssl_log(s, SSL_LOG_TRACE, "%s: Exit: failed in %s", - SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); - else if (rc < 0) - ssl_log(s, SSL_LOG_TRACE, "%s: Exit: error in %s", - SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); - } - } - - /* - * Because SSL renegotations can happen at any time (not only after - * SSL_accept()), the best way to log the current connection details is - * right after a finished handshake. - */ - if (where & SSL_CB_HANDSHAKE_DONE) { - ssl_log(s, SSL_LOG_INFO, - "Connection: Client IP: %s, Protocol: %s, Cipher: %s (%s/%s bits)", - ssl_var_lookup(NULL, s, c, NULL, "REMOTE_ADDR"), - ssl_var_lookup(NULL, s, c, NULL, "SSL_PROTOCOL"), - ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER"), - ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER_USEKEYSIZE"), - ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER_ALGKEYSIZE")); - } - - return; -} - diff --git a/modules/ssl/ssl_engine_log.c b/modules/ssl/ssl_engine_log.c deleted file mode 100644 index 0e1c53a852..0000000000 --- a/modules/ssl/ssl_engine_log.c +++ /dev/null @@ -1,326 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_engine_log.c -** Logging Facility -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - /* ``The difference between a computer - industry job and open-source software - hacking is about 30 hours a week.'' - -- Ralf S. Engelschall */ -#include "mod_ssl.h" - - -/* _________________________________________________________________ -** -** Logfile Support -** _________________________________________________________________ -*/ - -/* - * Open the SSL logfile - */ -void ssl_log_open(server_rec *s_main, server_rec *s, pool *p) -{ - char *szLogFile; - SSLSrvConfigRec *sc_main = mySrvConfig(s_main); - SSLSrvConfigRec *sc = mySrvConfig(s); - piped_log *pl; - - /* - * Short-circuit for inherited logfiles in order to save - * filedescriptors in mass-vhost situation. Be careful, this works - * fine because the close happens implicitly by the pool facility. - */ - if ( s != s_main - && sc_main->fileLogFile != NULL - && ( (sc->szLogFile == NULL) - || ( sc->szLogFile != NULL - && sc_main->szLogFile != NULL - && strEQ(sc->szLogFile, sc_main->szLogFile)))) { - sc->fileLogFile = sc_main->fileLogFile; - } - else if (sc->szLogFile != NULL) { - if (strEQ(sc->szLogFile, "/dev/null")) - return; - else if (sc->szLogFile[0] == '|') { - szLogFile = ssl_util_server_root_relative(p, "log", sc->szLogFile+1); - if ((pl = ap_open_piped_log(p, szLogFile)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Cannot open reliable pipe to SSL logfile filter %s", szLogFile); - ssl_die(); - } - sc->fileLogFile = ap_pfdopen(p, ap_piped_log_write_fd(pl), "a"); - setbuf(sc->fileLogFile, NULL); - } - else { - szLogFile = ssl_util_server_root_relative(p, "log", sc->szLogFile); - if ((sc->fileLogFile = ap_pfopen(p, szLogFile, "a")) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Cannot open SSL logfile %s", szLogFile); - ssl_die(); - } - setbuf(sc->fileLogFile, NULL); - } - } - return; -} - -static struct { - int nLevel; - char *szLevel; -} ssl_log_level2string[] = { - { SSL_LOG_ERROR, "error" }, - { SSL_LOG_WARN, "warn" }, - { SSL_LOG_INFO, "info" }, - { SSL_LOG_TRACE, "trace" }, - { SSL_LOG_DEBUG, "debug" }, - { 0, NULL } -}; - -static struct { - char *cpPattern; - char *cpAnnotation; -} ssl_log_annotate[] = { - { "*envelope*bad*decrypt*", "wrong pass phrase!?" }, - { "*CLIENT_HELLO*unknown*protocol*", "speaking not SSL to HTTPS port!?" }, - { "*CLIENT_HELLO*http*request*", "speaking HTTP to HTTPS port!?" }, - { "*SSL3_READ_BYTES:sslv3*alert*bad*certificate*", "Subject CN in certificate not server name or identical to CA!?" }, - { "*self signed certificate in certificate chain*", "Client certificate signed by CA not known to server?" }, - { "*peer did not return a certificate*", "No CAs known to server for verification?" }, - { "*no shared cipher*", "Too restrictive SSLCipherSuite or using DSA server certificate?" }, - { "*no start line*", "Bad file contents or format - or even just a forgotten SSLCertificateKeyFile?" }, - { "*bad password read*", "You entered an incorrect pass phrase!?" }, - { "*bad mac decode*", "Browser still remembered details of a re-created server certificate?" }, - { NULL, NULL } -}; - -static char *ssl_log_annotation(char *error) -{ - char *errstr; - int i; - - errstr = NULL; - for (i = 0; ssl_log_annotate[i].cpPattern != NULL; i++) { - if (ap_strcmp_match(error, ssl_log_annotate[i].cpPattern) == 0) { - errstr = ssl_log_annotate[i].cpAnnotation; - break; - } - } - return errstr; -} - -BOOL ssl_log_applies(server_rec *s, int level) -{ - SSLSrvConfigRec *sc; - - sc = mySrvConfig(s); - if ( sc->fileLogFile == NULL - && !(level & SSL_LOG_ERROR)) - return FALSE; - if ( level > sc->nLogLevel - && !(level & SSL_LOG_ERROR)) - return FALSE; - return TRUE; -} - -void ssl_log(server_rec *s, int level, const char *msg, ...) -{ - char tstr[80]; - char lstr[20]; - char vstr[1024]; - char str[1024]; - char nstr[2]; - int timz; - struct tm *t; - va_list ap; - int add; - int i; - char *astr; - int safe_errno; - unsigned long e; - SSLSrvConfigRec *sc; - char *cpE; - char *cpA; - - /* initialization */ - va_start(ap, msg); - safe_errno = errno; - sc = mySrvConfig(s); - - /* strip out additional flags */ - add = (level & ~SSL_LOG_MASK); - level = (level & SSL_LOG_MASK); - - /* reduce flags when not reasonable in context */ - if (add & SSL_ADD_ERRNO && errno == 0) - add &= ~SSL_ADD_ERRNO; - if (add & SSL_ADD_SSLERR && ERR_peek_error() == 0) - add &= ~SSL_ADD_SSLERR; - - /* we log only levels below, except for errors */ - if ( sc->fileLogFile == NULL - && !(level & SSL_LOG_ERROR)) - return; - if ( level > sc->nLogLevel - && !(level & SSL_LOG_ERROR)) - return; - - /* determine the time entry string */ - if (add & SSL_NO_TIMESTAMP) - tstr[0] = NUL; - else { - t = ap_get_gmtoff(&timz); - strftime(tstr, 80, "[%d/%b/%Y %H:%M:%S", t); - i = strlen(tstr); - ap_snprintf(tstr+i, 80-i, " %05d] ", (unsigned int)getpid()); - } - - /* determine whether newline should be written */ - if (add & SSL_NO_NEWLINE) - nstr[0] = NUL; - else { - nstr[0] = '\n'; - nstr[1] = NUL; - } - - /* determine level name */ - lstr[0] = NUL; - if (!(add & SSL_NO_LEVELID)) { - for (i = 0; ssl_log_level2string[i].nLevel != 0; i++) { - if (ssl_log_level2string[i].nLevel == level) { - ap_snprintf(lstr, sizeof(lstr), "[%s]", ssl_log_level2string[i].szLevel); - break; - } - } - for (i = strlen(lstr); i <= 7; i++) - lstr[i] = ' '; - lstr[i] = NUL; - } - - /* create custom message */ - ap_vsnprintf(vstr, sizeof(vstr), msg, ap); - - /* write out SSLog message */ - if ((add & SSL_ADD_ERRNO) && (add & SSL_ADD_SSLERR)) - astr = " (System and " SSL_LIBRARY_NAME " library errors follow)"; - else if (add & SSL_ADD_ERRNO) - astr = " (System error follows)"; - else if (add & SSL_ADD_SSLERR) - astr = " (" SSL_LIBRARY_NAME " library error follows)"; - else - astr = ""; - if (level <= sc->nLogLevel && sc->fileLogFile != NULL) { - ap_snprintf(str, sizeof(str), "%s%s%s%s%s", tstr, lstr, vstr, astr, nstr); - fprintf(sc->fileLogFile, "%s", str); - } - if (level & SSL_LOG_ERROR) - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s, - "mod_ssl: %s%s", vstr, astr); - - /* write out additional attachment messages */ - if (add & SSL_ADD_ERRNO) { - if (level <= sc->nLogLevel && sc->fileLogFile != NULL) { - ap_snprintf(str, sizeof(str), "%s%sSystem: %s (errno: %d)%s", - tstr, lstr, strerror(safe_errno), safe_errno, nstr); - fprintf(sc->fileLogFile, "%s", str); - } - if (level & SSL_LOG_ERROR) - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s, - "System: %s (errno: %d)", - strerror(safe_errno), safe_errno); - } - if (add & SSL_ADD_SSLERR) { - while ((e = ERR_get_error())) { - cpE = ERR_error_string(e, NULL); - cpA = ssl_log_annotation(cpE); - if (level <= sc->nLogLevel && sc->fileLogFile != NULL) { - ap_snprintf(str, sizeof(str), "%s%s%s: %s%s%s%s%s", - tstr, lstr, SSL_LIBRARY_NAME, cpE, - cpA != NULL ? " [Hint: " : "", - cpA != NULL ? cpA : "", cpA != NULL ? "]" : "", - nstr); - fprintf(sc->fileLogFile, "%s", str); - } - if (level & SSL_LOG_ERROR) - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s, - "%s: %s%s%s%s", SSL_LIBRARY_NAME, cpE, - cpA != NULL ? " [Hint: " : "", - cpA != NULL ? cpA : "", cpA != NULL ? "]" : ""); - } - } - /* make sure the next log starts from a clean base */ - /* ERR_clear_error(); */ - - /* cleanup and return */ - if (sc->fileLogFile != NULL) - fflush(sc->fileLogFile); - errno = safe_errno; - va_end(ap); - return; -} - -void ssl_die(void) -{ - /* - * This is used for fatal errors and here - * it is common module practice to really - * exit from the complete program. - */ - exit(1); -} - diff --git a/modules/ssl/ssl_engine_mutex.c b/modules/ssl/ssl_engine_mutex.c deleted file mode 100644 index 146f9ce4d9..0000000000 --- a/modules/ssl/ssl_engine_mutex.c +++ /dev/null @@ -1,397 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_engine_mutex.c -** Semaphore for Mutual Exclusion -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - /* ``Real programmers confuse - Christmas and Halloween - because DEC 25 = OCT 31.'' - -- Unknown */ -#include "mod_ssl.h" - - -/* _________________________________________________________________ -** -** Mutex Support (Common) -** _________________________________________________________________ -*/ - -void ssl_mutex_init(server_rec *s, pool *p) -{ - SSLModConfigRec *mc = myModConfig(); - - if (mc->nMutexMode == SSL_MUTEXMODE_FILE) - ssl_mutex_file_create(s, p); - else if (mc->nMutexMode == SSL_MUTEXMODE_SEM) - ssl_mutex_sem_create(s, p); - return; -} - -void ssl_mutex_reinit(server_rec *s, pool *p) -{ - SSLModConfigRec *mc = myModConfig(); - - if (mc->nMutexMode == SSL_MUTEXMODE_FILE) - ssl_mutex_file_open(s, p); - else if (mc->nMutexMode == SSL_MUTEXMODE_SEM) - ssl_mutex_sem_open(s, p); - return; -} - -void ssl_mutex_on(server_rec *s) -{ - SSLModConfigRec *mc = myModConfig(); - BOOL ok = TRUE; - - if (mc->nMutexMode == SSL_MUTEXMODE_FILE) - ok = ssl_mutex_file_acquire(); - else if (mc->nMutexMode == SSL_MUTEXMODE_SEM) - ok = ssl_mutex_sem_acquire(); - if (!ok) - ssl_log(s, SSL_LOG_WARN, "Failed to acquire global mutex lock"); - return; -} - -void ssl_mutex_off(server_rec *s) -{ - SSLModConfigRec *mc = myModConfig(); - BOOL ok = TRUE; - - if (mc->nMutexMode == SSL_MUTEXMODE_FILE) - ok = ssl_mutex_file_release(); - else if (mc->nMutexMode == SSL_MUTEXMODE_SEM) - ok = ssl_mutex_sem_release(); - if (!ok) - ssl_log(s, SSL_LOG_WARN, "Failed to release global mutex lock"); - return; -} - -void ssl_mutex_kill(server_rec *s) -{ - SSLModConfigRec *mc = myModConfig(); - - if (mc->nMutexMode == SSL_MUTEXMODE_FILE) - ssl_mutex_file_remove(s); - else if (mc->nMutexMode == SSL_MUTEXMODE_SEM) - ssl_mutex_sem_remove(s); - return; -} - - -/* _________________________________________________________________ -** -** Mutex Support (Lockfile) -** _________________________________________________________________ -*/ - -void ssl_mutex_file_create(server_rec *s, pool *p) -{ -#ifndef WIN32 - SSLModConfigRec *mc = myModConfig(); - - /* create the lockfile */ - unlink(mc->szMutexFile); - if ((mc->nMutexFD = ap_popenf(p, mc->szMutexFile, - O_WRONLY|O_CREAT, SSL_MUTEX_LOCK_MODE)) < 0) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Parent process could not create SSLMutex lockfile %s", - mc->szMutexFile); - ssl_die(); - } - ap_pclosef(p, mc->nMutexFD); - - /* make sure the childs have access to this file */ -#ifndef OS2 - if (geteuid() == 0 /* is superuser */) - chown(mc->szMutexFile, ap_user_id, -1 /* no gid change */); -#endif - - /* open the lockfile for real */ - if ((mc->nMutexFD = ap_popenf(p, mc->szMutexFile, - O_WRONLY, SSL_MUTEX_LOCK_MODE)) < 0) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Parent could not open SSLMutex lockfile %s", - mc->szMutexFile); - ssl_die(); - } -#endif - return; -} - -void ssl_mutex_file_open(server_rec *s, pool *p) -{ -#ifndef WIN32 - SSLModConfigRec *mc = myModConfig(); - - /* open the lockfile (once per child) to get a unique fd */ - if ((mc->nMutexFD = ap_popenf(p, mc->szMutexFile, - O_WRONLY, SSL_MUTEX_LOCK_MODE)) < 0) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Child could not open SSLMutex lockfile %s", - mc->szMutexFile); - ssl_die(); - } -#endif - return; -} - -void ssl_mutex_file_remove(void *data) -{ -#ifndef WIN32 - SSLModConfigRec *mc = myModConfig(); - - /* remove the mutex lockfile */ - unlink(mc->szMutexFile); -#endif - return; -} - -#ifndef WIN32 -#ifdef SSL_USE_FCNTL -static struct flock lock_it; -static struct flock unlock_it; -#endif -#endif - -BOOL ssl_mutex_file_acquire(void) -{ - int rc = -1; -#ifndef WIN32 - SSLModConfigRec *mc = myModConfig(); - -#ifdef SSL_USE_FCNTL - lock_it.l_whence = SEEK_SET; /* from current point */ - lock_it.l_start = 0; /* -"- */ - lock_it.l_len = 0; /* until end of file */ - lock_it.l_type = F_WRLCK; /* set exclusive/write lock */ - lock_it.l_pid = 0; /* pid not actually interesting */ - - while ( ((rc = fcntl(mc->nMutexFD, F_SETLKW, &lock_it)) < 0) - && (errno == EINTR) ) - ; -#endif -#ifdef SSL_USE_FLOCK - while ( ((rc = flock(mc->nMutexFD, LOCK_EX)) < 0) - && (errno == EINTR) ) - ; -#endif -#endif - - if (rc < 0) - return FALSE; - else - return TRUE; -} - -BOOL ssl_mutex_file_release(void) -{ - int rc = -1; -#ifndef WIN32 - SSLModConfigRec *mc = myModConfig(); - -#ifdef SSL_USE_FCNTL - unlock_it.l_whence = SEEK_SET; /* from current point */ - unlock_it.l_start = 0; /* -"- */ - unlock_it.l_len = 0; /* until end of file */ - unlock_it.l_type = F_UNLCK; /* unlock */ - unlock_it.l_pid = 0; /* pid not actually interesting */ - - while ( (rc = fcntl(mc->nMutexFD, F_SETLKW, &unlock_it)) < 0 - && (errno == EINTR) ) - ; -#endif -#ifdef SSL_USE_FLOCK - while ( (rc = flock(mc->nMutexFD, LOCK_UN)) < 0 - && (errno == EINTR) ) - ; -#endif -#endif - - if (rc < 0) - return FALSE; - else - return TRUE; -} - -/* _________________________________________________________________ -** -** Mutex Support (Process Semaphore) -** _________________________________________________________________ -*/ - -void ssl_mutex_sem_create(server_rec *s, pool *p) -{ -#ifdef SSL_CAN_USE_SEM - int semid; - SSLModConfigRec *mc = myModConfig(); -#ifdef SSL_HAVE_IPCSEM - union ssl_ipc_semun semctlarg; - struct semid_ds semctlbuf; -#endif - -#ifdef SSL_HAVE_IPCSEM - semid = semget(IPC_PRIVATE, 1, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR); - if (semid == -1 && errno == EEXIST) - semid = semget(IPC_PRIVATE, 1, IPC_EXCL|S_IRUSR|S_IWUSR); - if (semid == -1) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Parent process could not create private SSLMutex semaphore"); - ssl_die(); - } - semctlarg.val = 0; - if (semctl(semid, 0, SETVAL, semctlarg) < 0) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Parent process could not initialize SSLMutex semaphore value"); - ssl_die(); - } - semctlbuf.sem_perm.uid = ap_user_id; - semctlbuf.sem_perm.gid = ap_group_id; - semctlbuf.sem_perm.mode = 0660; - semctlarg.buf = &semctlbuf; - if (semctl(semid, 0, IPC_SET, semctlarg) < 0) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Parent process could not set permissions for SSLMutex semaphore"); - ssl_die(); - } -#endif -#ifdef SSL_HAVE_W32SEM - semid = (int)ap_create_mutex("mod_ssl_mutex"); -#endif - mc->nMutexSEMID = semid; -#endif - return; -} - -void ssl_mutex_sem_open(server_rec *s, pool *p) -{ -#ifdef SSL_CAN_USE_SEM -#ifdef SSL_HAVE_W32SEM - SSLModConfigRec *mc = myModConfig(); - - mc->nMutexSEMID = (int)ap_open_mutex("mod_ssl_mutex"); -#endif -#endif - return; -} - -void ssl_mutex_sem_remove(void *data) -{ -#ifdef SSL_CAN_USE_SEM - SSLModConfigRec *mc = myModConfig(); - -#ifdef SSL_HAVE_IPCSEM - semctl(mc->nMutexSEMID, 0, IPC_RMID, 0); -#endif -#ifdef SSL_HAVE_W32SEM - ap_destroy_mutex((mutex *)mc->nMutexSEMID); -#endif -#endif - return; -} - -BOOL ssl_mutex_sem_acquire(void) -{ - int rc = 0; -#ifdef SSL_CAN_USE_SEM - SSLModConfigRec *mc = myModConfig(); - -#ifdef SSL_HAVE_IPCSEM - struct sembuf sb[] = { - { 0, 0, 0 }, /* wait for semaphore */ - { 0, 1, SEM_UNDO } /* increment semaphore */ - }; - - while ( (rc = semop(mc->nMutexSEMID, sb, 2)) < 0 - && (errno == EINTR) ) - ; -#endif -#ifdef SSL_HAVE_W32SEM - rc = ap_acquire_mutex((mutex *)mc->nMutexSEMID); -#endif -#endif - if (rc != 0) - return FALSE; - else - return TRUE; -} - -BOOL ssl_mutex_sem_release(void) -{ - int rc = 0; -#ifdef SSL_CAN_USE_SEM - SSLModConfigRec *mc = myModConfig(); - -#ifdef SSL_HAVE_IPCSEM - struct sembuf sb[] = { - { 0, -1, SEM_UNDO } /* decrements semaphore */ - }; - - while ( (rc = semop(mc->nMutexSEMID, sb, 1)) < 0 - && (errno == EINTR) ) - ; -#endif -#ifdef SSL_HAVE_W32SEM - rc = ap_release_mutex((mutex *)mc->nMutexSEMID); -#endif -#endif - if (rc != 0) - return FALSE; - else - return TRUE; -} - diff --git a/modules/ssl/ssl_engine_pphrase.c b/modules/ssl/ssl_engine_pphrase.c deleted file mode 100644 index 2cef4e309e..0000000000 --- a/modules/ssl/ssl_engine_pphrase.c +++ /dev/null @@ -1,545 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_engine_pphrase.c -** Pass Phrase Dialog -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - /* ``Treat your password like your - toothbrush. Don't let anybody - else use it, and get a new one - every six months.'' - -- Clifford Stoll */ -#include "mod_ssl.h" - - -/* _________________________________________________________________ -** -** Pass Phrase and Private Key Handling -** _________________________________________________________________ -*/ - -#define STDERR_FILENO_STORE 50 -#define BUILTIN_DIALOG_BACKOFF 2 -#define BUILTIN_DIALOG_RETRIES 5 - -void ssl_pphrase_Handle(server_rec *s, pool *p) -{ - SSLModConfigRec *mc = myModConfig(); - SSLSrvConfigRec *sc; - server_rec *pServ; - char *cpVHostID; - char szPath[MAX_STRING_LEN]; - EVP_PKEY *pPrivateKey; - ssl_asn1_t *asn1; - unsigned char *ucp; - X509 *pX509Cert; - FILE *fp; - BOOL bReadable; - ssl_ds_array *aPassPhrase; - int nPassPhrase; - int nPassPhraseCur; - char *cpPassPhraseCur; - int nPassPhraseRetry; - int nPassPhraseDialog; - int nPassPhraseDialogCur; - BOOL bPassPhraseDialogOnce; - char **cpp; - int i, j; - ssl_algo_t algoCert, algoKey, at; - char *an; - char *cp; - - /* - * Start with a fresh pass phrase array - */ - aPassPhrase = ssl_ds_array_make(p, sizeof(char *)); - nPassPhrase = 0; - nPassPhraseDialog = 0; - - /* - * Walk through all configured servers - */ - for (pServ = s; pServ != NULL; pServ = pServ->next) { - sc = mySrvConfig(pServ); - - if (!sc->bEnabled) - continue; - - cpVHostID = ssl_util_vhostid(p, pServ); - ssl_log(pServ, SSL_LOG_INFO, - "Init: Loading certificate & private key of SSL-aware server %s", - cpVHostID); - - /* - * Read in server certificate(s): This is the easy part - * because this file isn't encrypted in any way. - */ - if (sc->szPublicCertFile[0] == NULL) { - ssl_log(pServ, SSL_LOG_ERROR, - "Init: Server %s should be SSL-aware but has no certificate configured " - "[Hint: SSLCertificateFile]", cpVHostID); - ssl_die(); - } - algoCert = SSL_ALGO_UNKNOWN; - algoKey = SSL_ALGO_UNKNOWN; - for (i = 0, j = 0; i < SSL_AIDX_MAX && sc->szPublicCertFile[i] != NULL; i++) { - - ap_cpystrn(szPath, sc->szPublicCertFile[i], sizeof(szPath)); - if ((fp = ap_pfopen(p, szPath, "r")) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Init: Can't open server certificate file %s", szPath); - ssl_die(); - } - if ((pX509Cert = SSL_read_X509(fp, NULL, NULL)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: Unable to read server certificate from file %s", szPath); - ssl_die(); - } - ap_pfclose(p, fp); - - /* - * check algorithm type of certificate and make - * sure only one certificate per type is used. - */ - at = ssl_util_algotypeof(pX509Cert, NULL); - an = ssl_util_algotypestr(at); - if (algoCert & at) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: Multiple %s server certificates not allowed", an); - ssl_die(); - } - algoCert |= at; - - /* - * Insert the certificate into global module configuration to let it - * survive the processing between the 1st Apache API init round (where - * we operate here) and the 2nd Apache init round (where the - * certificate is actually used to configure mod_ssl's per-server - * configuration structures). - */ - cp = ap_psprintf(mc->pPool, "%s:%s", cpVHostID, an); - asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tPublicCert, cp); - asn1->nData = i2d_X509(pX509Cert, NULL); - asn1->cpData = ap_palloc(mc->pPool, asn1->nData); - ucp = asn1->cpData; i2d_X509(pX509Cert, &ucp); /* 2nd arg increments */ - - /* - * Free the X509 structure - */ - X509_free(pX509Cert); - - /* - * Read in the private key: This is the non-trivial part, because the - * key is typically encrypted, so a pass phrase dialog has to be used - * to request it from the user (or it has to be alternatively gathered - * from a dialog program). The important point here is that ISPs - * usually have hundrets of virtual servers configured and a lot of - * them use SSL, so really we have to minimize the pass phrase - * dialogs. - * - * The idea is this: When N virtual hosts are configured and all of - * them use encrypted private keys with different pass phrases, we - * have no chance and have to pop up N pass phrase dialogs. But - * usually the admin is clever enough and uses the same pass phrase - * for more private key files (typically he even uses one single pass - * phrase for all). When this is the case we can minimize the dialogs - * by trying to re-use already known/entered pass phrases. - */ - if (sc->szPrivateKeyFile[j] != NULL) - ap_cpystrn(szPath, sc->szPrivateKeyFile[j++], sizeof(szPath)); - - /* - * Try to read the private key file with the help of - * the callback function which serves the pass - * phrases to OpenSSL - */ - myCtxVarSet(mc, 1, pServ); - myCtxVarSet(mc, 2, p); - myCtxVarSet(mc, 3, aPassPhrase); - myCtxVarSet(mc, 4, &nPassPhraseCur); - myCtxVarSet(mc, 5, &cpPassPhraseCur); - myCtxVarSet(mc, 6, cpVHostID); - myCtxVarSet(mc, 7, an); - myCtxVarSet(mc, 8, &nPassPhraseDialog); - myCtxVarSet(mc, 9, &nPassPhraseDialogCur); - myCtxVarSet(mc, 10, &bPassPhraseDialogOnce); - - nPassPhraseCur = 0; - nPassPhraseRetry = 0; - nPassPhraseDialogCur = 0; - bPassPhraseDialogOnce = TRUE; - - pPrivateKey = NULL; - - for (;;) { - /* - * Try to read the private key file with the help of - * the callback function which serves the pass - * phrases to OpenSSL - */ - if ((fp = ap_pfopen(p, szPath, "r")) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Init: Can't open server private key file %s", szPath); - ssl_die(); - } - cpPassPhraseCur = NULL; - bReadable = ((pPrivateKey = SSL_read_PrivateKey(fp, NULL, - ssl_pphrase_Handle_CB)) != NULL ? TRUE : FALSE); - ap_pfclose(p, fp); - - /* - * when the private key file now was readable, - * it's fine and we go out of the loop - */ - if (bReadable) - break; - - /* - * when we have more remembered pass phrases - * try to reuse these first. - */ - if (nPassPhraseCur < nPassPhrase) { - nPassPhraseCur++; - continue; - } - - /* - * else it's not readable and we have no more - * remembered pass phrases. Then this has to mean - * that the callback function popped up the dialog - * but a wrong pass phrase was entered. We give the - * user (but not the dialog program) a few more - * chances... - */ - if ( sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN - && cpPassPhraseCur != NULL - && nPassPhraseRetry < BUILTIN_DIALOG_RETRIES ) { - fprintf(stdout, "Apache:mod_ssl:Error: Pass phrase incorrect " - "(%d more retr%s permitted).\n", - (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry), - (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry) == 1 ? "y" : "ies"); - nPassPhraseRetry++; - if (nPassPhraseRetry > BUILTIN_DIALOG_BACKOFF) - sleep((nPassPhraseRetry-BUILTIN_DIALOG_BACKOFF)*5); - continue; - } - - /* - * Ok, anything else now means a fatal error. - */ - if (cpPassPhraseCur == NULL) - ssl_log(pServ, SSL_LOG_ERROR|SSL_ADD_SSLERR, "Init: Private key not found"); - if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) { - fprintf(stdout, "Apache:mod_ssl:Error: Private key not found.\n"); - fprintf(stdout, "**Stopped\n"); - } - else { - ssl_log(pServ, SSL_LOG_ERROR|SSL_ADD_SSLERR, "Init: Pass phrase incorrect"); - if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) { - fprintf(stdout, "Apache:mod_ssl:Error: Pass phrase incorrect.\n"); - fprintf(stdout, "**Stopped\n"); - } - } - ssl_die(); - } - - if (pPrivateKey == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: Unable to read server private key from file %s", szPath); - ssl_die(); - } - - /* - * check algorithm type of private key and make - * sure only one private key per type is used. - */ - at = ssl_util_algotypeof(NULL, pPrivateKey); - an = ssl_util_algotypestr(at); - if (algoKey & at) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR, - "Init: Multiple %s server private keys not allowed", an); - ssl_die(); - } - algoKey |= at; - - /* - * Log the type of reading - */ - if (nPassPhraseDialogCur == 0) - ssl_log(pServ, SSL_LOG_TRACE, - "Init: (%s) unencrypted %s private key - pass phrase not required", - cpVHostID, an); - else { - if (cpPassPhraseCur != NULL) - ssl_log(pServ, SSL_LOG_TRACE, - "Init: (%s) encrypted %s private key - pass phrase requested", - cpVHostID, an); - else - ssl_log(pServ, SSL_LOG_TRACE, - "Init: (%s) encrypted %s private key - pass phrase reused", - cpVHostID, an); - } - - /* - * Ok, when we have one more pass phrase store it - */ - if (cpPassPhraseCur != NULL) { - cpp = (char **)ssl_ds_array_push(aPassPhrase); - *cpp = cpPassPhraseCur; - nPassPhrase++; - } - - /* - * Insert private key into the global module configuration - * (we convert it to a stand-alone DER byte sequence - * because the SSL library uses static variables inside a - * RSA structure which do not survive DSO reloads!) - */ - cp = ap_psprintf(mc->pPool, "%s:%s", cpVHostID, an); - asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tPrivateKey, cp); - asn1->nData = i2d_PrivateKey(pPrivateKey, NULL); - asn1->cpData = ap_palloc(mc->pPool, asn1->nData); - ucp = asn1->cpData; i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */ - - /* - * Free the private key structure - */ - EVP_PKEY_free(pPrivateKey); - } - } - - /* - * Let the user know when we're successful. - */ - if (nPassPhraseDialog > 0) { - sc = mySrvConfig(s); - if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) { - fprintf(stdout, "\n"); - fprintf(stdout, "Ok: Pass Phrase Dialog successful.\n"); - } - } - - /* - * Wipe out the used memory from the - * pass phrase array and then deallocate it - */ - if (!ssl_ds_array_isempty(aPassPhrase)) { - ssl_ds_array_wipeout(aPassPhrase); - ssl_ds_array_kill(aPassPhrase); - ssl_log(s, SSL_LOG_INFO, "Init: Wiped out the queried pass phrases from memory"); - } - - return; -} - -int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify) -{ - SSLModConfigRec *mc = myModConfig(); - server_rec *s; - pool *p; - ssl_ds_array *aPassPhrase; - SSLSrvConfigRec *sc; - int *pnPassPhraseCur; - char **cppPassPhraseCur; - char *cpVHostID; - char *cpAlgoType; - int *pnPassPhraseDialog; - int *pnPassPhraseDialogCur; - BOOL *pbPassPhraseDialogOnce; - int stderr_store; - char **cpp; - int len = -1; - - /* - * Reconnect to the context of ssl_phrase_Handle() - */ - s = myCtxVarGet(mc, 1, server_rec *); - p = myCtxVarGet(mc, 2, pool *); - aPassPhrase = myCtxVarGet(mc, 3, ssl_ds_array *); - pnPassPhraseCur = myCtxVarGet(mc, 4, int *); - cppPassPhraseCur = myCtxVarGet(mc, 5, char **); - cpVHostID = myCtxVarGet(mc, 6, char *); - cpAlgoType = myCtxVarGet(mc, 7, char *); - pnPassPhraseDialog = myCtxVarGet(mc, 8, int *); - pnPassPhraseDialogCur = myCtxVarGet(mc, 9, int *); - pbPassPhraseDialogOnce = myCtxVarGet(mc, 10, BOOL *); - sc = mySrvConfig(s); - - (*pnPassPhraseDialog)++; - (*pnPassPhraseDialogCur)++; - - /* - * When remembered pass phrases are available use them... - */ - if ((cpp = (char **)ssl_ds_array_get(aPassPhrase, *pnPassPhraseCur)) != NULL) { - ap_cpystrn(buf, *cpp, bufsize); - len = strlen(buf); - return len; - } - - /* - * Builtin dialog - */ - if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) { - char *prompt; - int i; -#ifdef WIN32 - FILE *con; -#endif - - ssl_log(s, SSL_LOG_INFO, - "Init: Requesting pass phrase via builtin terminal dialog"); - - /* - * Reconnect STDERR to terminal (here STDOUT) because - * at our init stage Apache already connected STDERR - * to the general error logfile. - */ -#ifdef WIN32 - stderr_store = STDERR_FILENO_STORE; -#else - if ((stderr_store = open("/dev/null", O_WRONLY)) == -1) - stderr_store = STDERR_FILENO_STORE; -#endif - dup2(STDERR_FILENO, stderr_store); -#ifdef WIN32 - if ((con = fopen("con", "w")) != NULL) - dup2(fileno(con), STDERR_FILENO); - else - dup2(STDOUT_FILENO, STDERR_FILENO); -#else - dup2(STDOUT_FILENO, STDERR_FILENO); -#endif - - /* - * The first time display a header to inform the user about what - * program he actually speaks to, which module is responsible for - * this terminal dialog and why to the hell he has to enter - * something... - */ - if (*pnPassPhraseDialog == 1) { - fprintf(stderr, "%s mod_ssl/%s (Pass Phrase Dialog)\n", - SERVER_BASEVERSION, MOD_SSL_VERSION); - fprintf(stderr, "Some of your private key files are encrypted for security reasons.\n"); - fprintf(stderr, "In order to read them you have to provide us with the pass phrases.\n"); - } - if (*pbPassPhraseDialogOnce) { - *pbPassPhraseDialogOnce = FALSE; - fprintf(stderr, "\n"); - fprintf(stderr, "Server %s (%s)\n", cpVHostID, cpAlgoType); - } - - /* - * Emulate the OpenSSL internal pass phrase dialog - * (see crypto/pem/pem_lib.c:def_callback() for details) - */ - prompt = "Enter pass phrase:"; - for (;;) { - if ((i = EVP_read_pw_string(buf, bufsize, prompt, FALSE)) != 0) { - PEMerr(PEM_F_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD); - memset(buf, 0, (unsigned int)bufsize); - return (-1); - } - len = strlen(buf); - if (len < 1) - fprintf(stderr, "Apache:mod_ssl:Error: Pass phrase empty (needs to be at least 1 character).\n"); - else - break; - } - - /* - * Restore STDERR to Apache error logfile - */ - dup2(stderr_store, STDERR_FILENO); - close(stderr_store); -#ifdef WIN32 - if (con != NULL) - fclose(con); -#endif - } - - /* - * Filter program - */ - else if (sc->nPassPhraseDialogType == SSL_PPTYPE_FILTER) { - char *cmd; - char *result; - - ssl_log(s, SSL_LOG_INFO, - "Init: Requesting pass phrase from dialog filter program (%s)", - sc->szPassPhraseDialogPath); - - if (strchr(sc->szPassPhraseDialogPath, ' ') != NULL) - cmd = ap_psprintf(p, "\"%s\" %s %s", sc->szPassPhraseDialogPath, cpVHostID, cpAlgoType); - else - cmd = ap_psprintf(p, "%s %s %s", sc->szPassPhraseDialogPath, cpVHostID, cpAlgoType); - result = ssl_util_readfilter(s, p, cmd); - ap_cpystrn(buf, result, bufsize); - len = strlen(buf); - } - - /* - * Ok, we now have the pass phrase, so give it back - */ - *cppPassPhraseCur = ap_pstrdup(p, buf); - - /* - * And return it's length to OpenSSL... - */ - return (len); -} - diff --git a/modules/ssl/ssl_engine_rand.c b/modules/ssl/ssl_engine_rand.c deleted file mode 100644 index afb49b4f5c..0000000000 --- a/modules/ssl/ssl_engine_rand.c +++ /dev/null @@ -1,215 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_engine_rand.c -** Random Number Generator Seeding -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - /* ``The generation of random - numbers is too important - to be left to chance.'' */ - -#include "mod_ssl.h" - - -/* _________________________________________________________________ -** -** Support for better seeding of SSL library's RNG -** _________________________________________________________________ -*/ - -static int ssl_rand_choosenum(int, int); -static int ssl_rand_feedfp(pool *, FILE *, int); - -int ssl_rand_seed(server_rec *s, pool *p, ssl_rsctx_t nCtx, char *prefix) -{ - SSLModConfigRec *mc; - array_header *apRandSeed; - ssl_randseed_t *pRandSeeds; - ssl_randseed_t *pRandSeed; - unsigned char stackdata[256]; - int nReq, nDone; - FILE *fp; - int i, n, l; - time_t t; - pid_t pid; - - mc = myModConfig(); - nReq = 0; - nDone = 0; - apRandSeed = mc->aRandSeed; - pRandSeeds = (ssl_randseed_t *)apRandSeed->elts; - for (i = 0; i < apRandSeed->nelts; i++) { - pRandSeed = &pRandSeeds[i]; - if (pRandSeed->nCtx == nCtx) { - nReq += pRandSeed->nBytes; - if (pRandSeed->nSrc == SSL_RSSRC_FILE) { - /* - * seed in contents of an external file - */ - if ((fp = ap_pfopen(p, pRandSeed->cpPath, "r")) == NULL) - continue; - nDone += ssl_rand_feedfp(p, fp, pRandSeed->nBytes); - ap_pfclose(p, fp); - } - else if (pRandSeed->nSrc == SSL_RSSRC_EXEC) { - /* - * seed in contents generated by an external program - */ - if ((fp = ssl_util_ppopen(s, p, ap_psprintf(p, "%s %d", - pRandSeed->cpPath, pRandSeed->nBytes))) == NULL) - continue; - nDone += ssl_rand_feedfp(p, fp, pRandSeed->nBytes); - ssl_util_ppclose(s, p, fp); - } -#if SSL_LIBRARY_VERSION >= 0x00905100 - else if (pRandSeed->nSrc == SSL_RSSRC_EGD) { - /* - * seed in contents provided by the external - * Entropy Gathering Daemon (EGD) - */ - if ((n = RAND_egd(pRandSeed->cpPath)) == -1) - continue; - nDone += n; - } -#endif - else if (pRandSeed->nSrc == SSL_RSSRC_BUILTIN) { - /* - * seed in the current time (usually just 4 bytes) - */ - t = time(NULL); - l = sizeof(time_t); - RAND_seed((unsigned char *)&t, l); - nDone += l; - - /* - * seed in the current process id (usually just 4 bytes) - */ - pid = getpid(); - l = sizeof(pid_t); - RAND_seed((unsigned char *)&pid, l); - nDone += l; - - /* - * seed in some current state of the run-time stack (128 bytes) - */ - n = ssl_rand_choosenum(0, sizeof(stackdata)-128-1); - RAND_seed(stackdata+n, 128); - nDone += 128; - - /* - * seed in an 1KB extract of the current scoreboard - */ - if (ap_scoreboard_image != NULL) { - n = ssl_rand_choosenum(0, SCOREBOARD_SIZE-1024-1); - RAND_seed((unsigned char *)ap_scoreboard_image+n, 1024); - nDone += 1024; - } - } - } - } - ssl_log(s, SSL_LOG_INFO, "%sSeeding PRNG with %d bytes of entropy", prefix, nDone); - -#if SSL_LIBRARY_VERSION >= 0x00905100 - if (RAND_status() == 0) - ssl_log(s, SSL_LOG_WARN, "%sPRNG still contains not sufficient entropy!", prefix); -#endif - return nDone; -} - -#define BUFSIZE 8192 - -static int ssl_rand_feedfp(pool *p, FILE *fp, int nReq) -{ - int nDone; - unsigned char caBuf[BUFSIZE]; - int nBuf; - int nRead; - int nTodo; - - nDone = 0; - nRead = BUFSIZE; - nTodo = nReq; - while (1) { - if (nReq > 0) - nRead = (nTodo < BUFSIZE ? nTodo : BUFSIZE); - if ((nBuf = (int)fread(caBuf, 1, nRead, fp)) <= 0) - break; - RAND_seed(caBuf, nBuf); - nDone += nBuf; - if (nReq > 0) { - nTodo -= nBuf; - if (nTodo <= 0) - break; - } - } - return nDone; -} - -static int ssl_rand_choosenum(int l, int h) -{ - int i; - char buf[50]; - - srand((unsigned int)time(NULL)); - ap_snprintf(buf, sizeof(buf), "%.0f", - (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l))); - i = atoi(buf)+1; - if (i < l) i = l; - if (i > h) i = h; - return i; -} - diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c deleted file mode 100644 index c0755a5ec8..0000000000 --- a/modules/ssl/ssl_engine_vars.c +++ /dev/null @@ -1,615 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_engine_vars.c -** Variable Lookup Facility -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - /* ``Those of you who think they - know everything are very annoying - to those of us who do.'' - -- Unknown */ -#include "mod_ssl.h" - - -/* _________________________________________________________________ -** -** Variable Lookup -** _________________________________________________________________ -*/ - -static char *ssl_var_lookup_header(pool *p, request_rec *r, const char *name); -static char *ssl_var_lookup_ssl(pool *p, conn_rec *c, char *var); -static char *ssl_var_lookup_ssl_cert(pool *p, X509 *xs, char *var); -static char *ssl_var_lookup_ssl_cert_dn(pool *p, X509_NAME *xsname, char *var); -static char *ssl_var_lookup_ssl_cert_valid(pool *p, ASN1_UTCTIME *tm); -static char *ssl_var_lookup_ssl_cert_serial(pool *p, X509 *xs); -static char *ssl_var_lookup_ssl_cert_chain(pool *p, STACK_OF(X509) *sk, char *var); -static char *ssl_var_lookup_ssl_cert_PEM(pool *p, X509 *xs); -static char *ssl_var_lookup_ssl_cert_verify(pool *p, conn_rec *c); -static char *ssl_var_lookup_ssl_cipher(pool *p, conn_rec *c, char *var); -static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize); -static char *ssl_var_lookup_ssl_version(pool *p, char *var); - -void ssl_var_register(void) -{ - ap_hook_configure("ap::mod_ssl::var_lookup", - AP_HOOK_SIG6(ptr,ptr,ptr,ptr,ptr,ptr), AP_HOOK_DECLINE(NULL)); - ap_hook_register("ap::mod_ssl::var_lookup", - ssl_var_lookup, AP_HOOK_NOCTX); - return; -} - -void ssl_var_unregister(void) -{ - ap_hook_unregister("ap::mod_ssl::var_lookup", ssl_var_lookup); - return; -} - -char *ssl_var_lookup(pool *p, server_rec *s, conn_rec *c, request_rec *r, char *var) -{ - SSLModConfigRec *mc = myModConfig(); - char *result; - BOOL resdup; - time_t tc; - struct tm *tm; - - result = NULL; - resdup = TRUE; - - /* - * When no pool is given try to find one - */ - if (p == NULL) { - if (r != NULL) - p = r->pool; - else if (c != NULL) - p = c->pool; - else - p = mc->pPool; - } - - /* - * Request dependent stuff - */ - if (r != NULL) { - if (strcEQ(var, "HTTP_USER_AGENT")) - result = ssl_var_lookup_header(p, r, "User-Agent"); - else if (strcEQ(var, "HTTP_REFERER")) - result = ssl_var_lookup_header(p, r, "Referer"); - else if (strcEQ(var, "HTTP_COOKIE")) - result = ssl_var_lookup_header(p, r, "Cookie"); - else if (strcEQ(var, "HTTP_FORWARDED")) - result = ssl_var_lookup_header(p, r, "Forwarded"); - else if (strcEQ(var, "HTTP_HOST")) - result = ssl_var_lookup_header(p, r, "Host"); - else if (strcEQ(var, "HTTP_PROXY_CONNECTION")) - result = ssl_var_lookup_header(p, r, "Proxy-Connection"); - else if (strcEQ(var, "HTTP_ACCEPT")) - result = ssl_var_lookup_header(p, r, "Accept"); - else if (strlen(var) > 5 && strcEQn(var, "HTTP:", 5)) - /* all other headers from which we are still not know about */ - result = ssl_var_lookup_header(p, r, var+5); - else if (strcEQ(var, "THE_REQUEST")) - result = r->the_request; - else if (strcEQ(var, "REQUEST_METHOD")) - result = (char *)(r->method); - else if (strcEQ(var, "REQUEST_SCHEME")) - result = ap_http_method(r); - else if (strcEQ(var, "REQUEST_URI")) - result = r->uri; - else if (strcEQ(var, "SCRIPT_FILENAME") || - strcEQ(var, "REQUEST_FILENAME")) - result = r->filename; - else if (strcEQ(var, "PATH_INFO")) - result = r->path_info; - else if (strcEQ(var, "QUERY_STRING")) - result = r->args; - else if (strcEQ(var, "REMOTE_HOST")) - result = (char *)ap_get_remote_host(r->connection, - r->per_dir_config, REMOTE_NAME); - else if (strcEQ(var, "REMOTE_IDENT")) - result = (char *)ap_get_remote_logname(r); - else if (strcEQ(var, "IS_SUBREQ")) - result = (r->main != NULL ? "true" : "false"); - else if (strcEQ(var, "DOCUMENT_ROOT")) - result = (char *)ap_document_root(r); - else if (strcEQ(var, "SERVER_ADMIN")) - result = r->server->server_admin; - else if (strcEQ(var, "SERVER_NAME")) - result = (char *)ap_get_server_name(r); - else if (strcEQ(var, "SERVER_PORT")) - result = ap_psprintf(p, "%u", ap_get_server_port(r)); - else if (strcEQ(var, "SERVER_PROTOCOL")) - result = r->protocol; - } - - /* - * Connection stuff - */ - if (result == NULL && c != NULL) { - if (strcEQ(var, "REMOTE_ADDR")) - result = c->remote_ip; - else if (strcEQ(var, "REMOTE_USER")) - result = c->user; - else if (strcEQ(var, "AUTH_TYPE")) - result = c->ap_auth_type; - else if (strlen(var) > 4 && strcEQn(var, "SSL_", 4)) - result = ssl_var_lookup_ssl(p, c, var+4); - else if (strcEQ(var, "HTTPS")) { - if (ap_ctx_get(c->client->ctx, "ssl") != NULL) - result = "on"; - else - result = "off"; - } - } - - /* - * Totally independent stuff - */ - if (result == NULL) { - if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12)) - result = ssl_var_lookup_ssl_version(p, var+12); - else if (strcEQ(var, "SERVER_SOFTWARE")) - result = (char *)ap_get_server_version(); - else if (strcEQ(var, "API_VERSION")) { - result = ap_psprintf(p, "%d", MODULE_MAGIC_NUMBER); - resdup = FALSE; - } - else if (strcEQ(var, "TIME_YEAR")) { - tc = time(NULL); - tm = localtime(&tc); - result = ap_psprintf(p, "%02d%02d", - (tm->tm_year / 100) + 19, tm->tm_year % 100); - resdup = FALSE; - } -#define MKTIMESTR(format, tmfield) \ - tc = time(NULL); \ - tm = localtime(&tc); \ - result = ap_psprintf(p, format, tm->tmfield); \ - resdup = FALSE; - else if (strcEQ(var, "TIME_MON")) { - MKTIMESTR("%02d", tm_mon+1) - } - else if (strcEQ(var, "TIME_DAY")) { - MKTIMESTR("%02d", tm_mday) - } - else if (strcEQ(var, "TIME_HOUR")) { - MKTIMESTR("%02d", tm_hour) - } - else if (strcEQ(var, "TIME_MIN")) { - MKTIMESTR("%02d", tm_min) - } - else if (strcEQ(var, "TIME_SEC")) { - MKTIMESTR("%02d", tm_sec) - } - else if (strcEQ(var, "TIME_WDAY")) { - MKTIMESTR("%d", tm_wday) - } - else if (strcEQ(var, "TIME")) { - tc = time(NULL); - tm = localtime(&tc); - result = ap_psprintf(p, - "%02d%02d%02d%02d%02d%02d%02d", (tm->tm_year / 100) + 19, - (tm->tm_year % 100), tm->tm_mon+1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - resdup = FALSE; - } - /* all other env-variables from the parent Apache process */ - else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) { - result = (char *)ap_table_get(r->notes, var+4); - if (result == NULL) - result = (char *)ap_table_get(r->subprocess_env, var+4); - if (result == NULL) - result = getenv(var+4); - } - } - - if (result != NULL && resdup) - result = ap_pstrdup(p, result); - if (result == NULL) - result = ""; - return result; -} - -static char *ssl_var_lookup_header(pool *p, request_rec *r, const char *name) -{ - array_header *hdrs_arr; - table_entry *hdrs; - int i; - - hdrs_arr = ap_table_elts(r->headers_in); - hdrs = (table_entry *)hdrs_arr->elts; - for (i = 0; i < hdrs_arr->nelts; ++i) { - if (hdrs[i].key == NULL) - continue; - if (strcEQ(hdrs[i].key, name)) - return ap_pstrdup(p, hdrs[i].val); - } - return NULL; -} - -static char *ssl_var_lookup_ssl(pool *p, conn_rec *c, char *var) -{ - char *result; - X509 *xs; - STACK_OF(X509) *sk; - SSL *ssl; - - result = NULL; - - ssl = ap_ctx_get(c->client->ctx, "ssl"); - if (strlen(var) > 8 && strcEQn(var, "VERSION_", 8)) { - result = ssl_var_lookup_ssl_version(p, var+8); - } - else if (ssl != NULL && strcEQ(var, "PROTOCOL")) { - result = (char *)SSL_get_version(ssl); - } - else if (ssl != NULL && strcEQ(var, "SESSION_ID")) { - SSL_SESSION *pSession = SSL_get_session(ssl); - result = ap_pstrdup(p, SSL_SESSION_id2sz(pSession->session_id, - pSession->session_id_length)); - } - else if (ssl != NULL && strlen(var) >= 6 && strcEQn(var, "CIPHER", 6)) { - result = ssl_var_lookup_ssl_cipher(p, c, var+6); - } - else if (ssl != NULL && strlen(var) > 18 && strcEQn(var, "CLIENT_CERT_CHAIN_", 18)) { - sk = SSL_get_peer_cert_chain(ssl); - result = ssl_var_lookup_ssl_cert_chain(p, sk, var+17); - } - else if (ssl != NULL && strcEQ(var, "CLIENT_VERIFY")) { - result = ssl_var_lookup_ssl_cert_verify(p, c); - } - else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "CLIENT_", 7)) { - if ((xs = SSL_get_peer_certificate(ssl)) != NULL) - result = ssl_var_lookup_ssl_cert(p, xs, var+7); - } - else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "SERVER_", 7)) { - if ((xs = SSL_get_certificate(ssl)) != NULL) - result = ssl_var_lookup_ssl_cert(p, xs, var+7); - } - return result; -} - -static char *ssl_var_lookup_ssl_cert(pool *p, X509 *xs, char *var) -{ - char *result; - BOOL resdup; - X509_NAME *xsname; - int nid; - char *cp; - - result = NULL; - resdup = TRUE; - - if (strcEQ(var, "M_VERSION")) { - result = ap_psprintf(p, "%lu", X509_get_version(xs)+1); - resdup = FALSE; - } - else if (strcEQ(var, "M_SERIAL")) { - result = ssl_var_lookup_ssl_cert_serial(p, xs); - } - else if (strcEQ(var, "V_START")) { - result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notBefore(xs)); - } - else if (strcEQ(var, "V_END")) { - result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notAfter(xs)); - } - else if (strcEQ(var, "S_DN")) { - xsname = X509_get_subject_name(xs); - cp = X509_NAME_oneline(xsname, NULL, 0); - result = ap_pstrdup(p, cp); - free(cp); - resdup = FALSE; - } - else if (strlen(var) > 5 && strcEQn(var, "S_DN_", 5)) { - xsname = X509_get_subject_name(xs); - result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5); - resdup = FALSE; - } - else if (strcEQ(var, "I_DN")) { - xsname = X509_get_issuer_name(xs); - cp = X509_NAME_oneline(xsname, NULL, 0); - result = ap_pstrdup(p, cp); - free(cp); - resdup = FALSE; - } - else if (strlen(var) > 5 && strcEQn(var, "I_DN_", 5)) { - xsname = X509_get_issuer_name(xs); - result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5); - resdup = FALSE; - } - else if (strcEQ(var, "A_SIG")) { - nid = OBJ_obj2nid(xs->cert_info->signature->algorithm); - result = ap_pstrdup(p, (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid)); - resdup = FALSE; - } - else if (strcEQ(var, "A_KEY")) { - nid = OBJ_obj2nid(xs->cert_info->key->algor->algorithm); - result = ap_pstrdup(p, (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid)); - resdup = FALSE; - } - else if (strcEQ(var, "CERT")) { - result = ssl_var_lookup_ssl_cert_PEM(p, xs); - } - - if (result != NULL && resdup) - result = ap_pstrdup(p, result); - return result; -} - -static const struct { - char *name; - int nid; -} ssl_var_lookup_ssl_cert_dn_rec[] = { - { "C", NID_countryName }, - { "ST", NID_stateOrProvinceName }, /* officially (RFC2156) */ - { "SP", NID_stateOrProvinceName }, /* compatibility (SSLeay) */ - { "L", NID_localityName }, - { "O", NID_organizationName }, - { "OU", NID_organizationalUnitName }, - { "CN", NID_commonName }, - { "T", NID_title }, - { "I", NID_initials }, - { "G", NID_givenName }, - { "S", NID_surname }, - { "D", NID_description }, - { "UID", NID_uniqueIdentifier }, - { "Email", NID_pkcs9_emailAddress }, - { NULL, 0 } -}; - -static char *ssl_var_lookup_ssl_cert_dn(pool *p, X509_NAME *xsname, char *var) -{ - char *result; - X509_NAME_ENTRY *xsne; - int i, j, n; - - result = NULL; - - for (i = 0; ssl_var_lookup_ssl_cert_dn_rec[i].name != NULL; i++) { - if (strEQ(var, ssl_var_lookup_ssl_cert_dn_rec[i].name)) { - for (j = 0; j < sk_X509_NAME_ENTRY_num(xsname->entries); j++) { - xsne = sk_X509_NAME_ENTRY_value(xsname->entries, j); - n = OBJ_obj2nid(xsne->object); - if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid) { - result = ap_palloc(p, xsne->value->length+1); - ap_cpystrn(result, (char *)xsne->value->data, xsne->value->length+1); -#ifdef CHARSET_EBCDIC - ascii2ebcdic(result, result, xsne->value->length); -#endif /* CHARSET_EBCDIC */ - result[xsne->value->length] = NUL; - break; - } - } - break; - } - } - return result; -} - -static char *ssl_var_lookup_ssl_cert_valid(pool *p, ASN1_UTCTIME *tm) -{ - char *result; - BIO* bio; - int n; - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - return NULL; - ASN1_UTCTIME_print(bio, tm); - n = BIO_pending(bio); - result = ap_pcalloc(p, n+1); - n = BIO_read(bio, result, n); - result[n] = NUL; - BIO_free(bio); - return result; -} - -static char *ssl_var_lookup_ssl_cert_serial(pool *p, X509 *xs) -{ - char *result; - BIO *bio; - int n; - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - return NULL; - i2a_ASN1_INTEGER(bio, X509_get_serialNumber(xs)); - n = BIO_pending(bio); - result = ap_pcalloc(p, n+1); - n = BIO_read(bio, result, n); - result[n] = NUL; - BIO_free(bio); - return result; -} - -static char *ssl_var_lookup_ssl_cert_chain(pool *p, STACK_OF(X509) *sk, char *var) -{ - char *result; - X509 *xs; - int n; - - result = NULL; - - if (strspn(var, "0123456789") == strlen(var)) { - n = atoi(var); - if (n < sk_X509_num(sk)) { - xs = sk_X509_value(sk, n); - result = ssl_var_lookup_ssl_cert_PEM(p, xs); - } - } - - return result; -} - -static char *ssl_var_lookup_ssl_cert_PEM(pool *p, X509 *xs) -{ - char *result; - BIO *bio; - int n; - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - return NULL; - PEM_write_bio_X509(bio, xs); - n = BIO_pending(bio); - result = ap_pcalloc(p, n+1); - n = BIO_read(bio, result, n); - result[n] = NUL; - BIO_free(bio); - return result; -} - -static char *ssl_var_lookup_ssl_cert_verify(pool *p, conn_rec *c) -{ - char *result; - long vrc; - char *verr; - char *vinfo; - SSL *ssl; - X509 *xs; - - result = NULL; - ssl = ap_ctx_get(c->client->ctx, "ssl"); - verr = ap_ctx_get(c->client->ctx, "ssl::verify::error"); - vinfo = ap_ctx_get(c->client->ctx, "ssl::verify::info"); - vrc = SSL_get_verify_result(ssl); - xs = SSL_get_peer_certificate(ssl); - - if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs == NULL) - /* no client verification done at all */ - result = "NONE"; - else if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs != NULL) - /* client verification done successful */ - result = "SUCCESS"; - else if (vrc == X509_V_OK && vinfo != NULL && strEQ(vinfo, "GENEROUS")) - /* client verification done in generous way */ - result = "GENEROUS"; - else - /* client verification failed */ - result = ap_psprintf(p, "FAILED:%s", verr); - return result; -} - -static char *ssl_var_lookup_ssl_cipher(pool *p, conn_rec *c, char *var) -{ - char *result; - BOOL resdup; - int usekeysize, algkeysize; - SSL *ssl; - - result = NULL; - resdup = TRUE; - - ssl = ap_ctx_get(c->client->ctx, "ssl"); - ssl_var_lookup_ssl_cipher_bits(ssl, &usekeysize, &algkeysize); - - if (strEQ(var, "")) - result = (ssl != NULL ? (char *)SSL_get_cipher_name(ssl) : NULL); - else if (strcEQ(var, "_EXPORT")) - result = (usekeysize < 56 ? "true" : "false"); - else if (strcEQ(var, "_USEKEYSIZE")) { - result = ap_psprintf(p, "%d", usekeysize); - resdup = FALSE; - } - else if (strcEQ(var, "_ALGKEYSIZE")) { - result = ap_psprintf(p, "%d", algkeysize); - resdup = FALSE; - } - - if (result != NULL && resdup) - result = ap_pstrdup(p, result); - return result; -} - -static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize) -{ - SSL_CIPHER *cipher; - - *usekeysize = 0; - *algkeysize = 0; - if (ssl != NULL) - if ((cipher = SSL_get_current_cipher(ssl)) != NULL) - *usekeysize = SSL_CIPHER_get_bits(cipher, algkeysize); - return; -} - -static char *ssl_var_lookup_ssl_version(pool *p, char *var) -{ - char *result; - char *cp, *cp2; - - result = NULL; - - if (strEQ(var, "PRODUCT")) { -#if defined(SSL_PRODUCT_NAME) && defined(SSL_PRODUCT_VERSION) - result = ap_psprintf(p, "%s/%s", SSL_PRODUCT_NAME, SSL_PRODUCT_VERSION); -#else - result = NULL; -#endif - } - else if (strEQ(var, "INTERFACE")) { - result = ap_psprintf(p, "mod_ssl/%s", MOD_SSL_VERSION); - } - else if (strEQ(var, "LIBRARY")) { - result = ap_pstrdup(p, SSL_LIBRARY_TEXT); - if ((cp = strchr(result, ' ')) != NULL) { - *cp = '/'; - if ((cp2 = strchr(cp, ' ')) != NULL) - *cp2 = NUL; - } - } - return result; -} - diff --git a/modules/ssl/ssl_expr.c b/modules/ssl/ssl_expr.c deleted file mode 100644 index 49ab873ded..0000000000 --- a/modules/ssl/ssl_expr.c +++ /dev/null @@ -1,119 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_expr.c -** Expression Handling -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - /* ``It is hard to fly with - the eagles when you work - with the turkeys.'' - -- Unknown */ -#include "mod_ssl.h" - - -/* _________________________________________________________________ -** -** Expression Handling -** _________________________________________________________________ -*/ - -ssl_expr_info_type ssl_expr_info; -char *ssl_expr_error; - -ssl_expr *ssl_expr_comp(pool *p, char *expr) -{ - ssl_expr_info.pool = p; - ssl_expr_info.inputbuf = expr; - ssl_expr_info.inputlen = strlen(expr); - ssl_expr_info.inputptr = ssl_expr_info.inputbuf; - ssl_expr_info.expr = FALSE; - - ssl_expr_error = NULL; - if (ssl_expr_yyparse()) - return NULL; - return ssl_expr_info.expr; -} - -char *ssl_expr_get_error(void) -{ - if (ssl_expr_error == NULL) - return ""; - return ssl_expr_error; -} - -ssl_expr *ssl_expr_make(ssl_expr_node_op op, void *a1, void *a2) -{ - ssl_expr *node; - - node = (ssl_expr *)ap_palloc(ssl_expr_info.pool, sizeof(ssl_expr)); - node->node_op = op; - node->node_arg1 = (char *)a1; - node->node_arg2 = (char *)a2; - return node; -} - -int ssl_expr_exec(request_rec *r, ssl_expr *expr) -{ - BOOL rc; - - rc = ssl_expr_eval(r, expr); - if (ssl_expr_error != NULL) - return (-1); - else - return (rc ? 1 : 0); -} - diff --git a/modules/ssl/ssl_expr.h b/modules/ssl/ssl_expr.h deleted file mode 100644 index 419bb02192..0000000000 --- a/modules/ssl/ssl_expr.h +++ /dev/null @@ -1,139 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_expr.h -** Expression Handling (Header) -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - - /* ``May all your PUSHes be POPed.'' */ - -#ifndef SSL_EXPR_H -#define SSL_EXPR_H - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE !FALSE -#endif - -#ifndef YY_NULL -#define YY_NULL 0 -#endif - -#ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) -#endif - -#ifndef BOOL -#define BOOL unsigned int -#endif - -#ifndef NULL -#define NULL (void *)0 -#endif - -#ifndef NUL -#define NUL '\0' -#endif - -#ifndef YYDEBUG -#define YYDEBUG 0 -#endif - -typedef enum { - op_NOP, op_ListElement, - op_True, op_False, op_Not, op_Or, op_And, op_Comp, - op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE, op_IN, op_REG, op_NRE, - op_Digit, op_String, op_Regex, op_Var, op_Func -} ssl_expr_node_op; - -typedef struct { - ssl_expr_node_op node_op; - void *node_arg1; - void *node_arg2; -} ssl_expr_node; - -typedef ssl_expr_node ssl_expr; - -typedef struct { - pool *pool; - char *inputbuf; - int inputlen; - char *inputptr; - ssl_expr *expr; -} ssl_expr_info_type; - -extern ssl_expr_info_type ssl_expr_info; -extern char *ssl_expr_error; - -#define yylval ssl_expr_yylval -#define yyerror ssl_expr_yyerror -#define yyinput ssl_expr_yyinput - -extern int ssl_expr_yyparse(void); -extern int ssl_expr_yyerror(char *); -extern int ssl_expr_yylex(void); - -extern ssl_expr *ssl_expr_comp(pool *, char *); -extern int ssl_expr_exec(request_rec *, ssl_expr *); -extern char *ssl_expr_get_error(void); -extern ssl_expr *ssl_expr_make(ssl_expr_node_op, void *, void *); -extern BOOL ssl_expr_eval(request_rec *, ssl_expr *); - -#endif /* SSL_EXPR_H */ diff --git a/modules/ssl/ssl_expr_eval.c b/modules/ssl/ssl_expr_eval.c deleted file mode 100644 index d8c5ea5f9e..0000000000 --- a/modules/ssl/ssl_expr_eval.c +++ /dev/null @@ -1,282 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_expr_eval.c -** Expression Evaluation -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - /* ``Make love, - not software!'' - -- Unknown */ -#include "mod_ssl.h" - - -/* _________________________________________________________________ -** -** Expression Evaluation -** _________________________________________________________________ -*/ - -static BOOL ssl_expr_eval_comp(request_rec *, ssl_expr *); -static char *ssl_expr_eval_word(request_rec *, ssl_expr *); -static char *ssl_expr_eval_func_file(request_rec *, char *); -static int ssl_expr_eval_strcmplex(char *, char *); - -BOOL ssl_expr_eval(request_rec *r, ssl_expr *node) -{ - switch (node->node_op) { - case op_True: { - return TRUE; - } - case op_False: { - return FALSE; - } - case op_Not: { - ssl_expr *e = (ssl_expr *)node->node_arg1; - return (!ssl_expr_eval(r, e)); - } - case op_Or: { - ssl_expr *e1 = (ssl_expr *)node->node_arg1; - ssl_expr *e2 = (ssl_expr *)node->node_arg2; - return (ssl_expr_eval(r, e1) || ssl_expr_eval(r, e2)); - } - case op_And: { - ssl_expr *e1 = (ssl_expr *)node->node_arg1; - ssl_expr *e2 = (ssl_expr *)node->node_arg2; - return (ssl_expr_eval(r, e1) && ssl_expr_eval(r, e2)); - } - case op_Comp: { - ssl_expr *e = (ssl_expr *)node->node_arg1; - return ssl_expr_eval_comp(r, e); - } - default: { - ssl_expr_error = "Internal evaluation error: Unknown expression node"; - return FALSE; - } - } -} - -static BOOL ssl_expr_eval_comp(request_rec *r, ssl_expr *node) -{ - switch (node->node_op) { - case op_EQ: { - ssl_expr *e1 = (ssl_expr *)node->node_arg1; - ssl_expr *e2 = (ssl_expr *)node->node_arg2; - return (strcmp(ssl_expr_eval_word(r, e1), ssl_expr_eval_word(r, e2)) == 0); - } - case op_NE: { - ssl_expr *e1 = (ssl_expr *)node->node_arg1; - ssl_expr *e2 = (ssl_expr *)node->node_arg2; - return (strcmp(ssl_expr_eval_word(r, e1), ssl_expr_eval_word(r, e2)) != 0); - } - case op_LT: { - ssl_expr *e1 = (ssl_expr *)node->node_arg1; - ssl_expr *e2 = (ssl_expr *)node->node_arg2; - return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1), ssl_expr_eval_word(r, e2)) < 0); - } - case op_LE: { - ssl_expr *e1 = (ssl_expr *)node->node_arg1; - ssl_expr *e2 = (ssl_expr *)node->node_arg2; - return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1), ssl_expr_eval_word(r, e2)) <= 0); - } - case op_GT: { - ssl_expr *e1 = (ssl_expr *)node->node_arg1; - ssl_expr *e2 = (ssl_expr *)node->node_arg2; - return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1), ssl_expr_eval_word(r, e2)) > 0); - } - case op_GE: { - ssl_expr *e1 = (ssl_expr *)node->node_arg1; - ssl_expr *e2 = (ssl_expr *)node->node_arg2; - return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1), ssl_expr_eval_word(r, e2)) >= 0); - } - case op_IN: { - ssl_expr *e1 = (ssl_expr *)node->node_arg1; - ssl_expr *e2 = (ssl_expr *)node->node_arg2; - ssl_expr *e3; - char *w1 = ssl_expr_eval_word(r, e1); - BOOL found = FALSE; - do { - e3 = (ssl_expr *)e2->node_arg1; - e2 = (ssl_expr *)e2->node_arg2; - if (strcmp(w1, ssl_expr_eval_word(r, e3)) == 0) { - found = TRUE; - break; - } - } while (e2 != NULL); - return found; - } - case op_REG: { - ssl_expr *e1; - ssl_expr *e2; - char *word; - regex_t *regex; - - e1 = (ssl_expr *)node->node_arg1; - e2 = (ssl_expr *)node->node_arg2; - word = ssl_expr_eval_word(r, e1); - regex = (regex_t *)(e2->node_arg1); - return (regexec(regex, word, 0, NULL, 0) == 0); - } - case op_NRE: { - ssl_expr *e1; - ssl_expr *e2; - char *word; - regex_t *regex; - - e1 = (ssl_expr *)node->node_arg1; - e2 = (ssl_expr *)node->node_arg2; - word = ssl_expr_eval_word(r, e1); - regex = (regex_t *)(e2->node_arg1); - return !(regexec(regex, word, 0, NULL, 0) == 0); - } - default: { - ssl_expr_error = "Internal evaluation error: Unknown expression node"; - return FALSE; - } - } -} - -static char *ssl_expr_eval_word(request_rec *r, ssl_expr *node) -{ - switch (node->node_op) { - case op_Digit: { - char *string = (char *)node->node_arg1; - return string; - } - case op_String: { - char *string = (char *)node->node_arg1; - return string; - } - case op_Var: { - char *var = (char *)node->node_arg1; - char *val = ssl_var_lookup(r->pool, r->server, r->connection, r, var); - return (val == NULL ? "" : val); - } - case op_Func: { - char *name = (char *)node->node_arg1; - ssl_expr *args = (ssl_expr *)node->node_arg2; - if (strEQ(name, "file")) - return ssl_expr_eval_func_file(r, (char *)(args->node_arg1)); - else { - ssl_expr_error = "Internal evaluation error: Unknown function name"; - return ""; - } - } - default: { - ssl_expr_error = "Internal evaluation error: Unknown expression node"; - return FALSE; - } - } -} - -static char *ssl_expr_eval_func_file(request_rec *r, char *filename) -{ - FILE *fp; - char *buf; - int len; - - if ((fp = ap_pfopen(r->pool, filename, "r")) == NULL) { - ssl_expr_error = "Cannot open file"; - return ""; - } - fseek(fp, 0, SEEK_END); - len = ftell(fp); - if (len == 0) { - buf = (char *)ap_palloc(r->pool, sizeof(char) * 1); - *buf = NUL; - } - else { - if ((buf = (char *)ap_palloc(r->pool, sizeof(char) * len+1)) == NULL) { - ssl_expr_error = "Cannot allocate memory"; - ap_pfclose(r->pool, fp); - return ""; - } - fseek(fp, 0, SEEK_SET); - if (fread(buf, len, 1, fp) == 0) { - ssl_expr_error = "Cannot read from file"; - fclose(fp); - return (""); - } - buf[len] = NUL; - } - ap_pfclose(r->pool, fp); - return buf; -} - -/* a variant of strcmp(3) which works correctly also for number strings */ -static int ssl_expr_eval_strcmplex(char *cpNum1, char *cpNum2) -{ - int i, n1, n2; - - if (cpNum1 == NULL) - return -1; - if (cpNum2 == NULL) - return +1; - n1 = strlen(cpNum1); - n2 = strlen(cpNum2); - if (n1 > n2) - return 1; - if (n1 < n2) - return -1; - for (i = 0; i < n1; i++) { - if (cpNum1[i] > cpNum2[i]) - return 1; - if (cpNum1[i] < cpNum2[i]) - return -1; - } - return 0; -} - diff --git a/modules/ssl/ssl_expr_parse.c b/modules/ssl/ssl_expr_parse.c deleted file mode 100644 index 8e35553a4e..0000000000 --- a/modules/ssl/ssl_expr_parse.c +++ /dev/null @@ -1,605 +0,0 @@ -#ifndef lint -static char const -ssl_expr_yyrcsid[] = "$FreeBSD: src/usr.bin/yacc/skeleton.c,v 1.28 2000/01/17 02:04:06 bde Exp $"; -#endif -#include <stdlib.h> -#define YYBYACC 1 -#define YYMAJOR 1 -#define YYMINOR 9 -#define YYLEX ssl_expr_yylex() -#define YYEMPTY -1 -#define ssl_expr_yyclearin (ssl_expr_yychar=(YYEMPTY)) -#define ssl_expr_yyerrok (ssl_expr_yyerrflag=0) -#define YYRECOVERING() (ssl_expr_yyerrflag!=0) -static int ssl_expr_yygrowstack(); -#define YYPREFIX "ssl_expr_yy" -#line 72 "ssl_expr_parse.y" -#include "mod_ssl.h" -#line 75 "ssl_expr_parse.y" -typedef union { - char *cpVal; - ssl_expr *exVal; -} YYSTYPE; -#line 24 "y.tab.c" -#define YYERRCODE 256 -#define T_TRUE 257 -#define T_FALSE 258 -#define T_DIGIT 259 -#define T_ID 260 -#define T_STRING 261 -#define T_REGEX 262 -#define T_REGEX_I 263 -#define T_FUNC_FILE 264 -#define T_OP_EQ 265 -#define T_OP_NE 266 -#define T_OP_LT 267 -#define T_OP_LE 268 -#define T_OP_GT 269 -#define T_OP_GE 270 -#define T_OP_REG 271 -#define T_OP_NRE 272 -#define T_OP_IN 273 -#define T_OP_OR 274 -#define T_OP_AND 275 -#define T_OP_NOT 276 -const short ssl_expr_yylhs[] = { -1, - 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 5, 5, 6, - 6, 6, 6, 4, 4, 3, -}; -const short ssl_expr_yylen[] = { 2, - 1, 1, 1, 2, 3, 3, 1, 3, 3, 3, - 3, 3, 3, 3, 5, 3, 3, 1, 3, 1, - 1, 4, 1, 1, 1, 4, -}; -const short ssl_expr_yydefred[] = { 0, - 2, 3, 20, 21, 0, 0, 0, 0, 0, 0, - 7, 23, 0, 0, 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, - 0, 0, 6, 9, 10, 11, 12, 13, 14, 24, - 25, 16, 17, 0, 26, 22, 0, 18, 15, 0, - 19, -}; -const short ssl_expr_yydgoto[] = { 9, - 10, 11, 12, 42, 47, 13, -}; -const short ssl_expr_yysindex[] = { -37, - 0, 0, 0, 0, -35, -37, -37, -99, 0, -247, - 0, 0, -250, -229, 0, -39, -227, -37, -37, -33, - -33, -33, -33, -33, -33, -233, -233, -89, -6, 0, - -87, -239, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, -33, 0, 0, -38, 0, 0, -33, - 0, -}; -const short ssl_expr_yyrindex[] = { 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, -}; -const short ssl_expr_yygindex[] = { 0, - 7, 0, 0, 13, 0, -13, -}; -#define YYTABLESIZE 275 -const short ssl_expr_yytable[] = { 8, - 5, 30, 7, 8, 14, 50, 34, 35, 36, 37, - 38, 39, 15, 16, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 17, 32, 33, 18, 19, 40, 41, - 48, 29, 31, 44, 45, 19, 51, 46, 1, 43, - 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 2, 3, 0, 4, 0, 3, 5, 4, 0, 0, - 5, 0, 0, 0, 18, 19, 0, 0, 6, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 5, -}; -const short ssl_expr_yycheck[] = { 37, - 0, 41, 40, 37, 40, 44, 20, 21, 22, 23, - 24, 25, 6, 7, 265, 266, 267, 268, 269, 270, - 271, 272, 273, 123, 18, 19, 274, 275, 262, 263, - 44, 261, 260, 123, 41, 275, 50, 125, 0, 27, - -1, 41, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 125, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 257, - 258, 259, -1, 261, -1, 259, 264, 261, -1, -1, - 264, -1, -1, -1, 274, 275, -1, -1, 276, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 274, -}; -#define YYFINAL 9 -#ifndef YYDEBUG -#define YYDEBUG 0 -#endif -#define YYMAXTOKEN 276 -#if YYDEBUG -const char * const ssl_expr_yyname[] = { -"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,"'%'",0,0,"'('","')'",0,0,"','",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"T_TRUE", -"T_FALSE","T_DIGIT","T_ID","T_STRING","T_REGEX","T_REGEX_I","T_FUNC_FILE", -"T_OP_EQ","T_OP_NE","T_OP_LT","T_OP_LE","T_OP_GT","T_OP_GE","T_OP_REG", -"T_OP_NRE","T_OP_IN","T_OP_OR","T_OP_AND","T_OP_NOT", -}; -const char * const ssl_expr_yyrule[] = { -"$accept : root", -"root : expr", -"expr : T_TRUE", -"expr : T_FALSE", -"expr : T_OP_NOT expr", -"expr : expr T_OP_OR expr", -"expr : expr T_OP_AND expr", -"expr : comparison", -"expr : '(' expr ')'", -"comparison : word T_OP_EQ word", -"comparison : word T_OP_NE word", -"comparison : word T_OP_LT word", -"comparison : word T_OP_LE word", -"comparison : word T_OP_GT word", -"comparison : word T_OP_GE word", -"comparison : word T_OP_IN '{' words '}'", -"comparison : word T_OP_REG regex", -"comparison : word T_OP_NRE regex", -"words : word", -"words : words ',' word", -"word : T_DIGIT", -"word : T_STRING", -"word : '%' '{' T_ID '}'", -"word : funccall", -"regex : T_REGEX", -"regex : T_REGEX_I", -"funccall : T_FUNC_FILE '(' T_STRING ')'", -}; -#endif -#if YYDEBUG -#include <stdio.h> -#endif -#ifdef YYSTACKSIZE -#undef YYMAXDEPTH -#define YYMAXDEPTH YYSTACKSIZE -#else -#ifdef YYMAXDEPTH -#define YYSTACKSIZE YYMAXDEPTH -#else -#define YYSTACKSIZE 10000 -#define YYMAXDEPTH 10000 -#endif -#endif -#define YYINITSTACKSIZE 200 -int ssl_expr_yydebug; -int ssl_expr_yynerrs; -int ssl_expr_yyerrflag; -int ssl_expr_yychar; -short *ssl_expr_yyssp; -YYSTYPE *ssl_expr_yyvsp; -YYSTYPE ssl_expr_yyval; -YYSTYPE ssl_expr_yylval; -short *ssl_expr_yyss; -short *ssl_expr_yysslim; -YYSTYPE *ssl_expr_yyvs; -int ssl_expr_yystacksize; -#line 180 "ssl_expr_parse.y" - -int ssl_expr_yyerror(char *s) -{ - ssl_expr_error = s; - return 2; -} - -#line 230 "y.tab.c" -/* allocate initial stack or double stack size, up to YYMAXDEPTH */ -static int ssl_expr_yygrowstack() -{ - int newsize, i; - short *newss; - YYSTYPE *newvs; - - if ((newsize = ssl_expr_yystacksize) == 0) - newsize = YYINITSTACKSIZE; - else if (newsize >= YYMAXDEPTH) - return -1; - else if ((newsize *= 2) > YYMAXDEPTH) - newsize = YYMAXDEPTH; - i = ssl_expr_yyssp - ssl_expr_yyss; - newss = ssl_expr_yyss ? (short *)realloc(ssl_expr_yyss, newsize * sizeof *newss) : - (short *)malloc(newsize * sizeof *newss); - if (newss == NULL) - return -1; - ssl_expr_yyss = newss; - ssl_expr_yyssp = newss + i; - newvs = ssl_expr_yyvs ? (YYSTYPE *)realloc(ssl_expr_yyvs, newsize * sizeof *newvs) : - (YYSTYPE *)malloc(newsize * sizeof *newvs); - if (newvs == NULL) - return -1; - ssl_expr_yyvs = newvs; - ssl_expr_yyvsp = newvs + i; - ssl_expr_yystacksize = newsize; - ssl_expr_yysslim = ssl_expr_yyss + newsize - 1; - return 0; -} - -#define YYABORT goto ssl_expr_yyabort -#define YYREJECT goto ssl_expr_yyabort -#define YYACCEPT goto ssl_expr_yyaccept -#define YYERROR goto ssl_expr_yyerrlab - -#ifndef YYPARSE_PARAM -#if defined(__cplusplus) || __STDC__ -#define YYPARSE_PARAM_ARG void -#define YYPARSE_PARAM_DECL -#else /* ! ANSI-C/C++ */ -#define YYPARSE_PARAM_ARG -#define YYPARSE_PARAM_DECL -#endif /* ANSI-C/C++ */ -#else /* YYPARSE_PARAM */ -#ifndef YYPARSE_PARAM_TYPE -#define YYPARSE_PARAM_TYPE void * -#endif -#if defined(__cplusplus) || __STDC__ -#define YYPARSE_PARAM_ARG YYPARSE_PARAM_TYPE YYPARSE_PARAM -#define YYPARSE_PARAM_DECL -#else /* ! ANSI-C/C++ */ -#define YYPARSE_PARAM_ARG YYPARSE_PARAM -#define YYPARSE_PARAM_DECL YYPARSE_PARAM_TYPE YYPARSE_PARAM; -#endif /* ANSI-C/C++ */ -#endif /* ! YYPARSE_PARAM */ - -int -ssl_expr_yyparse (YYPARSE_PARAM_ARG) - YYPARSE_PARAM_DECL -{ - register int ssl_expr_yym, ssl_expr_yyn, ssl_expr_yystate; -#if YYDEBUG - register const char *ssl_expr_yys; - - if ((ssl_expr_yys = getenv("YYDEBUG"))) - { - ssl_expr_yyn = *ssl_expr_yys; - if (ssl_expr_yyn >= '0' && ssl_expr_yyn <= '9') - ssl_expr_yydebug = ssl_expr_yyn - '0'; - } -#endif - - ssl_expr_yynerrs = 0; - ssl_expr_yyerrflag = 0; - ssl_expr_yychar = (-1); - - if (ssl_expr_yyss == NULL && ssl_expr_yygrowstack()) goto ssl_expr_yyoverflow; - ssl_expr_yyssp = ssl_expr_yyss; - ssl_expr_yyvsp = ssl_expr_yyvs; - *ssl_expr_yyssp = ssl_expr_yystate = 0; - -ssl_expr_yyloop: - if ((ssl_expr_yyn = ssl_expr_yydefred[ssl_expr_yystate])) goto ssl_expr_yyreduce; - if (ssl_expr_yychar < 0) - { - if ((ssl_expr_yychar = ssl_expr_yylex()) < 0) ssl_expr_yychar = 0; -#if YYDEBUG - if (ssl_expr_yydebug) - { - ssl_expr_yys = 0; - if (ssl_expr_yychar <= YYMAXTOKEN) ssl_expr_yys = ssl_expr_yyname[ssl_expr_yychar]; - if (!ssl_expr_yys) ssl_expr_yys = "illegal-symbol"; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, ssl_expr_yystate, ssl_expr_yychar, ssl_expr_yys); - } -#endif - } - if ((ssl_expr_yyn = ssl_expr_yysindex[ssl_expr_yystate]) && (ssl_expr_yyn += ssl_expr_yychar) >= 0 && - ssl_expr_yyn <= YYTABLESIZE && ssl_expr_yycheck[ssl_expr_yyn] == ssl_expr_yychar) - { -#if YYDEBUG - if (ssl_expr_yydebug) - printf("%sdebug: state %d, shifting to state %d\n", - YYPREFIX, ssl_expr_yystate, ssl_expr_yytable[ssl_expr_yyn]); -#endif - if (ssl_expr_yyssp >= ssl_expr_yysslim && ssl_expr_yygrowstack()) - { - goto ssl_expr_yyoverflow; - } - *++ssl_expr_yyssp = ssl_expr_yystate = ssl_expr_yytable[ssl_expr_yyn]; - *++ssl_expr_yyvsp = ssl_expr_yylval; - ssl_expr_yychar = (-1); - if (ssl_expr_yyerrflag > 0) --ssl_expr_yyerrflag; - goto ssl_expr_yyloop; - } - if ((ssl_expr_yyn = ssl_expr_yyrindex[ssl_expr_yystate]) && (ssl_expr_yyn += ssl_expr_yychar) >= 0 && - ssl_expr_yyn <= YYTABLESIZE && ssl_expr_yycheck[ssl_expr_yyn] == ssl_expr_yychar) - { - ssl_expr_yyn = ssl_expr_yytable[ssl_expr_yyn]; - goto ssl_expr_yyreduce; - } - if (ssl_expr_yyerrflag) goto ssl_expr_yyinrecovery; -#if defined(lint) || defined(__GNUC__) - goto ssl_expr_yynewerror; -#endif -ssl_expr_yynewerror: - ssl_expr_yyerror("syntax error"); -#if defined(lint) || defined(__GNUC__) - goto ssl_expr_yyerrlab; -#endif -ssl_expr_yyerrlab: - ++ssl_expr_yynerrs; -ssl_expr_yyinrecovery: - if (ssl_expr_yyerrflag < 3) - { - ssl_expr_yyerrflag = 3; - for (;;) - { - if ((ssl_expr_yyn = ssl_expr_yysindex[*ssl_expr_yyssp]) && (ssl_expr_yyn += YYERRCODE) >= 0 && - ssl_expr_yyn <= YYTABLESIZE && ssl_expr_yycheck[ssl_expr_yyn] == YYERRCODE) - { -#if YYDEBUG - if (ssl_expr_yydebug) - printf("%sdebug: state %d, error recovery shifting\ - to state %d\n", YYPREFIX, *ssl_expr_yyssp, ssl_expr_yytable[ssl_expr_yyn]); -#endif - if (ssl_expr_yyssp >= ssl_expr_yysslim && ssl_expr_yygrowstack()) - { - goto ssl_expr_yyoverflow; - } - *++ssl_expr_yyssp = ssl_expr_yystate = ssl_expr_yytable[ssl_expr_yyn]; - *++ssl_expr_yyvsp = ssl_expr_yylval; - goto ssl_expr_yyloop; - } - else - { -#if YYDEBUG - if (ssl_expr_yydebug) - printf("%sdebug: error recovery discarding state %d\n", - YYPREFIX, *ssl_expr_yyssp); -#endif - if (ssl_expr_yyssp <= ssl_expr_yyss) goto ssl_expr_yyabort; - --ssl_expr_yyssp; - --ssl_expr_yyvsp; - } - } - } - else - { - if (ssl_expr_yychar == 0) goto ssl_expr_yyabort; -#if YYDEBUG - if (ssl_expr_yydebug) - { - ssl_expr_yys = 0; - if (ssl_expr_yychar <= YYMAXTOKEN) ssl_expr_yys = ssl_expr_yyname[ssl_expr_yychar]; - if (!ssl_expr_yys) ssl_expr_yys = "illegal-symbol"; - printf("%sdebug: state %d, error recovery discards token %d (%s)\n", - YYPREFIX, ssl_expr_yystate, ssl_expr_yychar, ssl_expr_yys); - } -#endif - ssl_expr_yychar = (-1); - goto ssl_expr_yyloop; - } -ssl_expr_yyreduce: -#if YYDEBUG - if (ssl_expr_yydebug) - printf("%sdebug: state %d, reducing by rule %d (%s)\n", - YYPREFIX, ssl_expr_yystate, ssl_expr_yyn, ssl_expr_yyrule[ssl_expr_yyn]); -#endif - ssl_expr_yym = ssl_expr_yylen[ssl_expr_yyn]; - ssl_expr_yyval = ssl_expr_yyvsp[1-ssl_expr_yym]; - switch (ssl_expr_yyn) - { -case 1: -#line 118 "ssl_expr_parse.y" -{ ssl_expr_info.expr = ssl_expr_yyvsp[0].exVal; } -break; -case 2: -#line 121 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_True, NULL, NULL); } -break; -case 3: -#line 122 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_False, NULL, NULL); } -break; -case 4: -#line 123 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_Not, ssl_expr_yyvsp[0].exVal, NULL); } -break; -case 5: -#line 124 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_Or, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); } -break; -case 6: -#line 125 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_And, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); } -break; -case 7: -#line 126 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_Comp, ssl_expr_yyvsp[0].exVal, NULL); } -break; -case 8: -#line 127 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_yyvsp[-1].exVal; } -break; -case 9: -#line 130 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_EQ, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); } -break; -case 10: -#line 131 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_NE, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); } -break; -case 11: -#line 132 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_LT, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); } -break; -case 12: -#line 133 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_LE, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); } -break; -case 13: -#line 134 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_GT, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); } -break; -case 14: -#line 135 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_GE, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); } -break; -case 15: -#line 136 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_IN, ssl_expr_yyvsp[-4].exVal, ssl_expr_yyvsp[-1].exVal); } -break; -case 16: -#line 137 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_REG, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); } -break; -case 17: -#line 138 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_NRE, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); } -break; -case 18: -#line 141 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_ListElement, ssl_expr_yyvsp[0].exVal, NULL); } -break; -case 19: -#line 142 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_ListElement, ssl_expr_yyvsp[0].exVal, ssl_expr_yyvsp[-2].exVal); } -break; -case 20: -#line 145 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_Digit, ssl_expr_yyvsp[0].cpVal, NULL); } -break; -case 21: -#line 146 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_String, ssl_expr_yyvsp[0].cpVal, NULL); } -break; -case 22: -#line 147 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_Var, ssl_expr_yyvsp[-1].cpVal, NULL); } -break; -case 23: -#line 148 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_yyvsp[0].exVal; } -break; -case 24: -#line 151 "ssl_expr_parse.y" -{ - regex_t *regex; - if ((regex = ap_pregcomp(ssl_expr_info.pool, ssl_expr_yyvsp[0].cpVal, - REG_EXTENDED|REG_NOSUB)) == NULL) { - ssl_expr_error = "Failed to compile regular expression"; - YYERROR; - regex = NULL; - } - ssl_expr_yyval.exVal = ssl_expr_make(op_Regex, regex, NULL); - } -break; -case 25: -#line 161 "ssl_expr_parse.y" -{ - regex_t *regex; - if ((regex = ap_pregcomp(ssl_expr_info.pool, ssl_expr_yyvsp[0].cpVal, - REG_EXTENDED|REG_NOSUB|REG_ICASE)) == NULL) { - ssl_expr_error = "Failed to compile regular expression"; - YYERROR; - regex = NULL; - } - ssl_expr_yyval.exVal = ssl_expr_make(op_Regex, regex, NULL); - } -break; -case 26: -#line 173 "ssl_expr_parse.y" -{ - ssl_expr *args = ssl_expr_make(op_ListElement, ssl_expr_yyvsp[-1].cpVal, NULL); - ssl_expr_yyval.exVal = ssl_expr_make(op_Func, "file", args); - } -break; -#line 550 "y.tab.c" - } - ssl_expr_yyssp -= ssl_expr_yym; - ssl_expr_yystate = *ssl_expr_yyssp; - ssl_expr_yyvsp -= ssl_expr_yym; - ssl_expr_yym = ssl_expr_yylhs[ssl_expr_yyn]; - if (ssl_expr_yystate == 0 && ssl_expr_yym == 0) - { -#if YYDEBUG - if (ssl_expr_yydebug) - printf("%sdebug: after reduction, shifting from state 0 to\ - state %d\n", YYPREFIX, YYFINAL); -#endif - ssl_expr_yystate = YYFINAL; - *++ssl_expr_yyssp = YYFINAL; - *++ssl_expr_yyvsp = ssl_expr_yyval; - if (ssl_expr_yychar < 0) - { - if ((ssl_expr_yychar = ssl_expr_yylex()) < 0) ssl_expr_yychar = 0; -#if YYDEBUG - if (ssl_expr_yydebug) - { - ssl_expr_yys = 0; - if (ssl_expr_yychar <= YYMAXTOKEN) ssl_expr_yys = ssl_expr_yyname[ssl_expr_yychar]; - if (!ssl_expr_yys) ssl_expr_yys = "illegal-symbol"; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, YYFINAL, ssl_expr_yychar, ssl_expr_yys); - } -#endif - } - if (ssl_expr_yychar == 0) goto ssl_expr_yyaccept; - goto ssl_expr_yyloop; - } - if ((ssl_expr_yyn = ssl_expr_yygindex[ssl_expr_yym]) && (ssl_expr_yyn += ssl_expr_yystate) >= 0 && - ssl_expr_yyn <= YYTABLESIZE && ssl_expr_yycheck[ssl_expr_yyn] == ssl_expr_yystate) - ssl_expr_yystate = ssl_expr_yytable[ssl_expr_yyn]; - else - ssl_expr_yystate = ssl_expr_yydgoto[ssl_expr_yym]; -#if YYDEBUG - if (ssl_expr_yydebug) - printf("%sdebug: after reduction, shifting from state %d \ -to state %d\n", YYPREFIX, *ssl_expr_yyssp, ssl_expr_yystate); -#endif - if (ssl_expr_yyssp >= ssl_expr_yysslim && ssl_expr_yygrowstack()) - { - goto ssl_expr_yyoverflow; - } - *++ssl_expr_yyssp = ssl_expr_yystate; - *++ssl_expr_yyvsp = ssl_expr_yyval; - goto ssl_expr_yyloop; -ssl_expr_yyoverflow: - ssl_expr_yyerror("yacc stack overflow"); -ssl_expr_yyabort: - return (1); -ssl_expr_yyaccept: - return (0); -} diff --git a/modules/ssl/ssl_expr_parse.h b/modules/ssl/ssl_expr_parse.h deleted file mode 100644 index 618cacbe3b..0000000000 --- a/modules/ssl/ssl_expr_parse.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef YYERRCODE -#define YYERRCODE 256 -#endif - -#define T_TRUE 257 -#define T_FALSE 258 -#define T_DIGIT 259 -#define T_ID 260 -#define T_STRING 261 -#define T_REGEX 262 -#define T_REGEX_I 263 -#define T_FUNC_FILE 264 -#define T_OP_EQ 265 -#define T_OP_NE 266 -#define T_OP_LT 267 -#define T_OP_LE 268 -#define T_OP_GT 269 -#define T_OP_GE 270 -#define T_OP_REG 271 -#define T_OP_NRE 272 -#define T_OP_IN 273 -#define T_OP_OR 274 -#define T_OP_AND 275 -#define T_OP_NOT 276 -typedef union { - char *cpVal; - ssl_expr *exVal; -} YYSTYPE; -extern YYSTYPE ssl_expr_yylval; diff --git a/modules/ssl/ssl_expr_parse.y b/modules/ssl/ssl_expr_parse.y deleted file mode 100644 index 1e3ad6e513..0000000000 --- a/modules/ssl/ssl_expr_parse.y +++ /dev/null @@ -1,186 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | -** | '_ ` _ \ / _ \ / _` | / __/ __| | -** | | | | | | (_) | (_| | \__ \__ \ | mod_ssl - Apache Interface to OpenSSL -** |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/ -** |_____| -** ssl_expr_parse.y -** Expression LR(1) Parser -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - - /* ``What you see is all you get.'' - -- Brian Kernighan */ - -/* _________________________________________________________________ -** -** Expression Parser -** _________________________________________________________________ -*/ - -%{ -#include "mod_ssl.h" -%} - -%union { - char *cpVal; - ssl_expr *exVal; -} - -%token T_TRUE -%token T_FALSE - -%token <cpVal> T_DIGIT -%token <cpVal> T_ID -%token <cpVal> T_STRING -%token <cpVal> T_REGEX -%token <cpVal> T_REGEX_I - -%token T_FUNC_FILE - -%token T_OP_EQ -%token T_OP_NE -%token T_OP_LT -%token T_OP_LE -%token T_OP_GT -%token T_OP_GE -%token T_OP_REG -%token T_OP_NRE -%token T_OP_IN - -%token T_OP_OR -%token T_OP_AND -%token T_OP_NOT - -%left T_OP_OR -%left T_OP_AND -%left T_OP_NOT - -%type <exVal> expr -%type <exVal> comparison -%type <exVal> funccall -%type <exVal> regex -%type <exVal> words -%type <exVal> word - -%% - -root : expr { ssl_expr_info.expr = $1; } - ; - -expr : T_TRUE { $$ = ssl_expr_make(op_True, NULL, NULL); } - | T_FALSE { $$ = ssl_expr_make(op_False, NULL, NULL); } - | T_OP_NOT expr { $$ = ssl_expr_make(op_Not, $2, NULL); } - | expr T_OP_OR expr { $$ = ssl_expr_make(op_Or, $1, $3); } - | expr T_OP_AND expr { $$ = ssl_expr_make(op_And, $1, $3); } - | comparison { $$ = ssl_expr_make(op_Comp, $1, NULL); } - | '(' expr ')' { $$ = $2; } - ; - -comparison: word T_OP_EQ word { $$ = ssl_expr_make(op_EQ, $1, $3); } - | word T_OP_NE word { $$ = ssl_expr_make(op_NE, $1, $3); } - | word T_OP_LT word { $$ = ssl_expr_make(op_LT, $1, $3); } - | word T_OP_LE word { $$ = ssl_expr_make(op_LE, $1, $3); } - | word T_OP_GT word { $$ = ssl_expr_make(op_GT, $1, $3); } - | word T_OP_GE word { $$ = ssl_expr_make(op_GE, $1, $3); } - | word T_OP_IN '{' words '}' { $$ = ssl_expr_make(op_IN, $1, $4); } - | word T_OP_REG regex { $$ = ssl_expr_make(op_REG, $1, $3); } - | word T_OP_NRE regex { $$ = ssl_expr_make(op_NRE, $1, $3); } - ; - -words : word { $$ = ssl_expr_make(op_ListElement, $1, NULL); } - | words ',' word { $$ = ssl_expr_make(op_ListElement, $3, $1); } - ; - -word : T_DIGIT { $$ = ssl_expr_make(op_Digit, $1, NULL); } - | T_STRING { $$ = ssl_expr_make(op_String, $1, NULL); } - | '%' '{' T_ID '}' { $$ = ssl_expr_make(op_Var, $3, NULL); } - | funccall { $$ = $1; } - ; - -regex : T_REGEX { - regex_t *regex; - if ((regex = ap_pregcomp(ssl_expr_info.pool, $1, - REG_EXTENDED|REG_NOSUB)) == NULL) { - ssl_expr_error = "Failed to compile regular expression"; - YYERROR; - regex = NULL; - } - $$ = ssl_expr_make(op_Regex, regex, NULL); - } - | T_REGEX_I { - regex_t *regex; - if ((regex = ap_pregcomp(ssl_expr_info.pool, $1, - REG_EXTENDED|REG_NOSUB|REG_ICASE)) == NULL) { - ssl_expr_error = "Failed to compile regular expression"; - YYERROR; - regex = NULL; - } - $$ = ssl_expr_make(op_Regex, regex, NULL); - } - ; - -funccall : T_FUNC_FILE '(' T_STRING ')' { - ssl_expr *args = ssl_expr_make(op_ListElement, $3, NULL); - $$ = ssl_expr_make(op_Func, "file", args); - } - ; - -%% - -int yyerror(char *s) -{ - ssl_expr_error = s; - return 2; -} - diff --git a/modules/ssl/ssl_expr_scan.c b/modules/ssl/ssl_expr_scan.c deleted file mode 100644 index f3e9f9d1f5..0000000000 --- a/modules/ssl/ssl_expr_scan.c +++ /dev/null @@ -1,2002 +0,0 @@ -#define yy_create_buffer ssl_expr_yy_create_buffer -#define yy_delete_buffer ssl_expr_yy_delete_buffer -#define yy_scan_buffer ssl_expr_yy_scan_buffer -#define yy_scan_string ssl_expr_yy_scan_string -#define yy_scan_bytes ssl_expr_yy_scan_bytes -#define yy_flex_debug ssl_expr_yy_flex_debug -#define yy_init_buffer ssl_expr_yy_init_buffer -#define yy_flush_buffer ssl_expr_yy_flush_buffer -#define yy_load_buffer_state ssl_expr_yy_load_buffer_state -#define yy_switch_to_buffer ssl_expr_yy_switch_to_buffer -#define yyin ssl_expr_yyin -#define yyleng ssl_expr_yyleng -#define yylex ssl_expr_yylex -#define yyout ssl_expr_yyout -#define yyrestart ssl_expr_yyrestart -#define yytext ssl_expr_yytext - -/* A lexical scanner generated by flex */ - -/* Scanner skeleton version: - */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 - -#include <stdio.h> - - -/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ -#ifdef c_plusplus -#ifndef __cplusplus -#define __cplusplus -#endif -#endif - - -#ifdef __cplusplus - -#include <stdlib.h> -#include <unistd.h> - -/* Use prototypes in function declarations. */ -#define YY_USE_PROTOS - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -#if __STDC__ - -#define YY_USE_PROTOS -#define YY_USE_CONST - -#endif /* __STDC__ */ -#endif /* ! __cplusplus */ - -#ifdef __TURBOC__ - #pragma warn -rch - #pragma warn -use -#include <io.h> -#include <stdlib.h> -#define YY_USE_CONST -#define YY_USE_PROTOS -#endif - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - - -#ifdef YY_USE_PROTOS -#define YY_PROTO(proto) proto -#else -#define YY_PROTO(proto) () -#endif - -/* Returned upon end-of-file. */ -#define YY_NULL 0 - -/* Promotes a possibly negative, possibly signed char to an unsigned - * integer for use as an array index. If the signed char is negative, - * we want to instead treat it as an 8-bit unsigned char, hence the - * double cast. - */ -#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) - -/* Enter a start condition. This macro really ought to take a parameter, - * but we do it the disgusting crufty way forced on us by the ()-less - * definition of BEGIN. - */ -#define BEGIN yy_start = 1 + 2 * - -/* Translate the current start state into a value that can be later handed - * to BEGIN to return to the state. The YYSTATE alias is for lex - * compatibility. - */ -#define YY_START ((yy_start - 1) / 2) -#define YYSTATE YY_START - -/* Action number for EOF rule of a given start state. */ -#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) - -/* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE yyrestart( yyin ) - -#define YY_END_OF_BUFFER_CHAR 0 - -/* Size of default input buffer. */ -#define YY_BUF_SIZE 16384 - -typedef struct yy_buffer_state *YY_BUFFER_STATE; - -extern int yyleng; -extern FILE *yyin, *yyout; - -#define EOB_ACT_CONTINUE_SCAN 0 -#define EOB_ACT_END_OF_FILE 1 -#define EOB_ACT_LAST_MATCH 2 - -/* The funky do-while in the following #define is used to turn the definition - * int a single C statement (which needs a semi-colon terminator). This - * avoids problems with code like: - * - * if ( condition_holds ) - * yyless( 5 ); - * else - * do_something_else(); - * - * Prior to using the do-while the compiler would get upset at the - * "else" because it interpreted the "if" statement as being all - * done when it reached the ';' after the yyless() call. - */ - -/* Return all but the first 'n' matched characters back to the input stream. */ - -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - *yy_cp = yy_hold_char; \ - YY_RESTORE_YY_MORE_OFFSET \ - yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ - } \ - while ( 0 ) - -#define unput(c) yyunput( c, yytext_ptr ) - -/* The following is because we cannot portably get our hands on size_t - * (without autoconf's help, which isn't available because we want - * flex-generated scanners to compile on their own). - */ -typedef unsigned int yy_size_t; - - -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; -#define YY_BUFFER_NEW 0 -#define YY_BUFFER_NORMAL 1 - /* When an EOF's been seen but there's still some text to process - * then we mark the buffer as YY_EOF_PENDING, to indicate that we - * shouldn't try reading from the input source any more. We might - * still have a bunch of tokens to match, though, because of - * possible backing-up. - * - * When we actually see the EOF, we change the status to "new" - * (via yyrestart()), so that the user can continue scanning by - * just pointing yyin at a new input file. - */ -#define YY_BUFFER_EOF_PENDING 2 - }; - -static YY_BUFFER_STATE yy_current_buffer = 0; - -/* We provide macros for accessing buffer states in case in the - * future we want to put the buffer states in a more general - * "scanner state". - */ -#define YY_CURRENT_BUFFER yy_current_buffer - - -/* yy_hold_char holds the character lost when yytext is formed. */ -static char yy_hold_char; - -static int yy_n_chars; /* number of characters read into yy_ch_buf */ - - -int yyleng; - -/* Points to current character in buffer. */ -static char *yy_c_buf_p = (char *) 0; -static int yy_init = 1; /* whether we need to initialize */ -static int yy_start = 0; /* start state number */ - -/* Flag which is used to allow yywrap()'s to do buffer switches - * instead of setting up a fresh yyin. A bit of a hack ... - */ -static int yy_did_buffer_switch_on_eof; - -void yyrestart YY_PROTO(( FILE *input_file )); - -void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); -void yy_load_buffer_state YY_PROTO(( void )); -YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); -void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); -void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); -void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); -#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) - -YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); -YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); -YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); - -static void *yy_flex_alloc YY_PROTO(( yy_size_t )); -static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); -static void yy_flex_free YY_PROTO(( void * )); - -#define yy_new_buffer yy_create_buffer - -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_is_interactive = is_interactive; \ - } - -#define yy_set_bol(at_bol) \ - { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_at_bol = at_bol; \ - } - -#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) - - -#define yywrap() 1 -#define YY_SKIP_YYWRAP -typedef unsigned char YY_CHAR; -FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; -typedef int yy_state_type; -extern char *yytext; -#define yytext_ptr yytext - -static yy_state_type yy_get_previous_state YY_PROTO(( void )); -static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); -static int yy_get_next_buffer YY_PROTO(( void )); -static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); - -/* Done after the current pattern has been matched and before the - * corresponding action - sets up yytext. - */ -#define YY_DO_BEFORE_ACTION \ - yytext_ptr = yy_bp; \ - yyleng = (int) (yy_cp - yy_bp); \ - yy_hold_char = *yy_cp; \ - *yy_cp = '\0'; \ - yy_c_buf_p = yy_cp; - -#define YY_NUM_RULES 46 -#define YY_END_OF_BUFFER 47 -static yyconst short int yy_accept[86] = - { 0, - 0, 0, 0, 0, 0, 0, 0, 0, 47, 45, - 1, 38, 2, 45, 43, 24, 45, 28, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, - 13, 4, 3, 14, 16, 18, 17, 1, 22, 32, - 34, 43, 26, 20, 31, 30, 44, 44, 19, 44, - 44, 29, 27, 39, 25, 23, 15, 15, 21, 44, - 35, 44, 36, 13, 12, 5, 6, 10, 11, 7, - 8, 9, 33, 44, 44, 37, 44, 5, 6, 44, - 40, 41, 5, 42, 0 - } ; - -static yyconst int yy_ec[256] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 4, 5, 1, 1, 1, 6, 1, 1, - 1, 1, 1, 1, 7, 1, 1, 8, 8, 8, - 8, 8, 8, 8, 8, 9, 9, 7, 1, 10, - 11, 12, 1, 1, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 1, 14, 1, 1, 7, 1, 15, 16, 13, 17, - - 18, 19, 20, 13, 21, 13, 13, 22, 23, 24, - 25, 13, 26, 27, 28, 29, 30, 13, 13, 13, - 13, 13, 1, 31, 1, 32, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 - } ; - -static yyconst int yy_meta[33] = - { 0, - 1, 1, 2, 1, 3, 1, 4, 4, 4, 1, - 1, 1, 4, 3, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 1, 1 - } ; - -static yyconst short int yy_base[93] = - { 0, - 0, 0, 30, 31, 0, 0, 82, 81, 101, 142, - 35, 28, 142, 94, 32, 88, 31, 87, 0, 69, - 66, 28, 28, 67, 29, 63, 30, 63, 62, 57, - 0, 142, 142, 88, 142, 142, 142, 48, 142, 142, - 142, 44, 142, 142, 142, 142, 0, 70, 0, 64, - 63, 0, 0, 0, 0, 0, 142, 0, 0, 55, - 0, 46, 142, 0, 142, 53, 62, 142, 142, 142, - 142, 142, 0, 44, 48, 0, 41, 70, 72, 38, - 0, 0, 74, 0, 142, 117, 121, 125, 50, 129, - 133, 137 - - } ; - -static yyconst short int yy_def[93] = - { 0, - 85, 1, 86, 86, 87, 87, 88, 88, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 89, 89, - 89, 89, 89, 89, 89, 90, 89, 89, 89, 85, - 91, 85, 85, 92, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 89, 89, 89, 89, - 89, 89, 89, 89, 89, 89, 85, 89, 89, 89, - 89, 89, 85, 91, 85, 85, 85, 85, 85, 85, - 85, 85, 89, 89, 89, 89, 89, 85, 85, 89, - 89, 89, 85, 89, 0, 85, 85, 85, 85, 85, - 85, 85 - - } ; - -static yyconst short int yy_nxt[175] = - { 0, - 10, 11, 11, 12, 13, 14, 10, 15, 15, 16, - 17, 18, 19, 10, 20, 19, 19, 21, 22, 23, - 24, 25, 26, 27, 28, 19, 19, 19, 29, 19, - 30, 10, 32, 32, 33, 33, 38, 38, 39, 42, - 42, 44, 50, 34, 34, 52, 55, 59, 51, 38, - 38, 42, 42, 47, 60, 84, 53, 56, 82, 40, - 78, 79, 45, 57, 57, 81, 57, 57, 57, 79, - 79, 80, 57, 57, 57, 77, 57, 83, 79, 79, - 79, 79, 79, 76, 75, 74, 73, 63, 62, 61, - 54, 49, 48, 57, 57, 66, 67, 46, 43, 41, - - 85, 37, 37, 68, 85, 85, 69, 85, 85, 85, - 85, 70, 85, 85, 71, 85, 72, 31, 31, 31, - 31, 35, 35, 35, 35, 36, 36, 36, 36, 58, - 85, 58, 58, 64, 85, 85, 64, 65, 65, 65, - 65, 9, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85 - } ; - -static yyconst short int yy_chk[175] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 3, 4, 3, 4, 11, 11, 12, 15, - 15, 17, 22, 3, 4, 23, 25, 27, 22, 38, - 38, 42, 42, 89, 27, 80, 23, 25, 77, 12, - 66, 66, 17, 26, 26, 75, 26, 26, 26, 67, - 67, 74, 26, 26, 26, 62, 26, 78, 78, 79, - 79, 83, 83, 60, 51, 50, 48, 30, 29, 28, - 24, 21, 20, 26, 26, 34, 34, 18, 16, 14, - - 9, 8, 7, 34, 0, 0, 34, 0, 0, 0, - 0, 34, 0, 0, 34, 0, 34, 86, 86, 86, - 86, 87, 87, 87, 87, 88, 88, 88, 88, 90, - 0, 90, 90, 91, 0, 0, 91, 92, 92, 92, - 92, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85 - } ; - -static yy_state_type yy_last_accepting_state; -static char *yy_last_accepting_cpos; - -/* The intent behind this definition is that it'll catch - * any uses of REJECT which flex missed. - */ -#define REJECT reject_used_but_not_detected -#define yymore() yymore_used_but_not_detected -#define YY_MORE_ADJ 0 -#define YY_RESTORE_YY_MORE_OFFSET -char *yytext; -#line 1 "ssl_expr_scan.l" -#define INITIAL 0 -/* _ _ -** _ __ ___ ___ __| | ___ ___| | -** | '_ ` _ \ / _ \ / _` | / __/ __| | -** | | | | | | (_) | (_| | \__ \__ \ | mod_ssl - Apache Interface to OpenSSL -** |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/ -** |_____| -** ssl_expr_scan.l -** Expression Scanner -*/ -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ -/* ``Killing for peace is -like fucking for virginity.'' --- Unknown */ -/* _________________________________________________________________ -** -** Expression Scanner -** _________________________________________________________________ -*/ -#line 73 "ssl_expr_scan.l" -#include "mod_ssl.h" - -#include "ssl_expr_parse.h" - -#define YY_NO_UNPUT 1 -int yyinput(char *buf, int max_size); - -#undef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - (result = yyinput(buf, max_size)) - -#define MAX_STR_LEN 2048 -/* %option stack */ -#define YY_NEVER_INTERACTIVE 1 -#define str 1 - -#define regex 2 -#define regex_flags 3 - -#line 537 "lex.ssl_expr_yy.c" - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int yywrap YY_PROTO(( void )); -#else -extern int yywrap YY_PROTO(( void )); -#endif -#endif - -#ifndef YY_NO_UNPUT -static void yyunput YY_PROTO(( int c, char *buf_ptr )); -#endif - -#ifndef yytext_ptr -static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen YY_PROTO(( yyconst char * )); -#endif - -#ifndef YY_NO_INPUT -#ifdef __cplusplus -static int yyinput YY_PROTO(( void )); -#else -static int input YY_PROTO(( void )); -#endif -#endif - -#if YY_STACK_USED -static int yy_start_stack_ptr = 0; -static int yy_start_stack_depth = 0; -static int *yy_start_stack = 0; -#ifndef YY_NO_PUSH_STATE -static void yy_push_state YY_PROTO(( int new_state )); -#endif -#ifndef YY_NO_POP_STATE -static void yy_pop_state YY_PROTO(( void )); -#endif -#ifndef YY_NO_TOP_STATE -static int yy_top_state YY_PROTO(( void )); -#endif - -#else -#define YY_NO_PUSH_STATE 1 -#define YY_NO_POP_STATE 1 -#define YY_NO_TOP_STATE 1 -#endif - -#ifdef YY_MALLOC_DECL -YY_MALLOC_DECL -#else -#if __STDC__ -#ifndef __cplusplus -#include <stdlib.h> -#endif -#else -/* Just try to get by without declaring the routines. This will fail - * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) - * or sizeof(void*) != sizeof(int). - */ -#endif -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#endif - -/* Copy whatever the last rule matched to the standard output. */ - -#ifndef ECHO -/* This used to be an fputs(), but since the string might contain NUL's, - * we now use fwrite(). - */ -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) -#endif - -/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, - * is returned in "result". - */ -#ifndef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - if ( yy_current_buffer->yy_is_interactive ) \ - { \ - int c = '*', n; \ - for ( n = 0; n < max_size && \ - (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ - buf[n] = (char) c; \ - if ( c == '\n' ) \ - buf[n++] = (char) c; \ - if ( c == EOF && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - result = n; \ - } \ - else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ - && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); -#endif - -/* No semi-colon after return; correct usage is to write "yyterminate();" - - * we don't want an extra ';' after the "return" because that will cause - * some compilers to complain about unreachable statements. - */ -#ifndef yyterminate -#define yyterminate() return YY_NULL -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Report a fatal error. */ -#ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) -#endif - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL int yylex YY_PROTO(( void )) -#endif - -/* Code executed at the beginning of each rule, after yytext and yyleng - * have been set up. - */ -#ifndef YY_USER_ACTION -#define YY_USER_ACTION -#endif - -/* Code executed at the end of each rule. */ -#ifndef YY_BREAK -#define YY_BREAK break; -#endif - -#define YY_RULE_SETUP \ - YY_USER_ACTION - -YY_DECL - { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; - -#line 94 "ssl_expr_scan.l" - - - char caStr[MAX_STR_LEN]; - char *cpStr = NULL; - char caRegex[MAX_STR_LEN]; - char *cpRegex = NULL; - char cRegexDel = NUL; - - /* - * Whitespaces - */ -#line 700 "lex.ssl_expr_yy.c" - - if ( yy_init ) - { - yy_init = 0; - -#ifdef YY_USER_INIT - YY_USER_INIT; -#endif - - if ( ! yy_start ) - yy_start = 1; /* first start state */ - - if ( ! yyin ) - yyin = stdin; - - if ( ! yyout ) - yyout = stdout; - - if ( ! yy_current_buffer ) - yy_current_buffer = - yy_create_buffer( yyin, YY_BUF_SIZE ); - - yy_load_buffer_state(); - } - - while ( 1 ) /* loops until end-of-file is reached */ - { - yy_cp = yy_c_buf_p; - - /* Support of yytext. */ - *yy_cp = yy_hold_char; - - /* yy_bp points to the position in yy_ch_buf of the start of - * the current run. - */ - yy_bp = yy_cp; - - yy_current_state = yy_start; -yy_match: - do - { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; - if ( yy_accept[yy_current_state] ) - { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 86 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - ++yy_cp; - } - while ( yy_current_state != 85 ); - yy_cp = yy_last_accepting_cpos; - yy_current_state = yy_last_accepting_state; - -yy_find_action: - yy_act = yy_accept[yy_current_state]; - - YY_DO_BEFORE_ACTION; - - -do_action: /* This label is used only to access EOF actions. */ - - - switch ( yy_act ) - { /* beginning of action switch */ - case 0: /* must back up */ - /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = yy_hold_char; - yy_cp = yy_last_accepting_cpos; - yy_current_state = yy_last_accepting_state; - goto yy_find_action; - -case 1: -YY_RULE_SETUP -#line 105 "ssl_expr_scan.l" -{ - /* NOP */ -} - YY_BREAK -/* - * C-style strings ("...") - */ -case 2: -YY_RULE_SETUP -#line 112 "ssl_expr_scan.l" -{ - cpStr = caStr; - BEGIN(str); -} - YY_BREAK -case 3: -YY_RULE_SETUP -#line 116 "ssl_expr_scan.l" -{ - BEGIN(INITIAL); - *cpStr = NUL; - yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, caStr); - return T_STRING; -} - YY_BREAK -case 4: -YY_RULE_SETUP -#line 122 "ssl_expr_scan.l" -{ - yyerror("Unterminated string"); -} - YY_BREAK -case 5: -YY_RULE_SETUP -#line 125 "ssl_expr_scan.l" -{ - int result; - - (void)sscanf(yytext+1, "%o", &result); - if (result > 0xff) - yyerror("Escape sequence out of bound"); - else - *cpStr++ = result; -} - YY_BREAK -case 6: -YY_RULE_SETUP -#line 134 "ssl_expr_scan.l" -{ - yyerror("Bad escape sequence"); -} - YY_BREAK -case 7: -YY_RULE_SETUP -#line 137 "ssl_expr_scan.l" -{ *cpStr++ = '\n'; } - YY_BREAK -case 8: -YY_RULE_SETUP -#line 138 "ssl_expr_scan.l" -{ *cpStr++ = '\r'; } - YY_BREAK -case 9: -YY_RULE_SETUP -#line 139 "ssl_expr_scan.l" -{ *cpStr++ = '\t'; } - YY_BREAK -case 10: -YY_RULE_SETUP -#line 140 "ssl_expr_scan.l" -{ *cpStr++ = '\b'; } - YY_BREAK -case 11: -YY_RULE_SETUP -#line 141 "ssl_expr_scan.l" -{ *cpStr++ = '\f'; } - YY_BREAK -case 12: -YY_RULE_SETUP -#line 142 "ssl_expr_scan.l" -{ - *cpStr++ = yytext[1]; -} - YY_BREAK -case 13: -YY_RULE_SETUP -#line 145 "ssl_expr_scan.l" -{ - char *cp = yytext; - while (*cp != NUL) - *cpStr++ = *cp++; -} - YY_BREAK -case 14: -YY_RULE_SETUP -#line 150 "ssl_expr_scan.l" -{ - *cpStr++ = yytext[1]; -} - YY_BREAK -/* - * Regular Expression - */ -case 15: -YY_RULE_SETUP -#line 157 "ssl_expr_scan.l" -{ - cRegexDel = yytext[1]; - cpRegex = caRegex; - BEGIN(regex); -} - YY_BREAK -case 16: -YY_RULE_SETUP -#line 162 "ssl_expr_scan.l" -{ - if (yytext[0] == cRegexDel) { - *cpRegex = NUL; - BEGIN(regex_flags); - } - else { - *cpRegex++ = yytext[0]; - } -} - YY_BREAK -case 17: -YY_RULE_SETUP -#line 171 "ssl_expr_scan.l" -{ - yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, caRegex); - BEGIN(INITIAL); - return T_REGEX_I; -} - YY_BREAK -case 18: -YY_RULE_SETUP -#line 176 "ssl_expr_scan.l" -{ - yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, caRegex); - yyless(0); - BEGIN(INITIAL); - return T_REGEX; -} - YY_BREAK -case YY_STATE_EOF(regex_flags): -#line 182 "ssl_expr_scan.l" -{ - yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, caRegex); - BEGIN(INITIAL); - return T_REGEX; -} - YY_BREAK -/* - * Operators - */ -case 19: -YY_RULE_SETUP -#line 191 "ssl_expr_scan.l" -{ return T_OP_EQ; } - YY_BREAK -case 20: -YY_RULE_SETUP -#line 192 "ssl_expr_scan.l" -{ return T_OP_EQ; } - YY_BREAK -case 21: -YY_RULE_SETUP -#line 193 "ssl_expr_scan.l" -{ return T_OP_NE; } - YY_BREAK -case 22: -YY_RULE_SETUP -#line 194 "ssl_expr_scan.l" -{ return T_OP_NE; } - YY_BREAK -case 23: -YY_RULE_SETUP -#line 195 "ssl_expr_scan.l" -{ return T_OP_LT; } - YY_BREAK -case 24: -YY_RULE_SETUP -#line 196 "ssl_expr_scan.l" -{ return T_OP_LT; } - YY_BREAK -case 25: -YY_RULE_SETUP -#line 197 "ssl_expr_scan.l" -{ return T_OP_LE; } - YY_BREAK -case 26: -YY_RULE_SETUP -#line 198 "ssl_expr_scan.l" -{ return T_OP_LE; } - YY_BREAK -case 27: -YY_RULE_SETUP -#line 199 "ssl_expr_scan.l" -{ return T_OP_GT; } - YY_BREAK -case 28: -YY_RULE_SETUP -#line 200 "ssl_expr_scan.l" -{ return T_OP_GT; } - YY_BREAK -case 29: -YY_RULE_SETUP -#line 201 "ssl_expr_scan.l" -{ return T_OP_GE; } - YY_BREAK -case 30: -YY_RULE_SETUP -#line 202 "ssl_expr_scan.l" -{ return T_OP_GE; } - YY_BREAK -case 31: -YY_RULE_SETUP -#line 203 "ssl_expr_scan.l" -{ return T_OP_REG; } - YY_BREAK -case 32: -YY_RULE_SETUP -#line 204 "ssl_expr_scan.l" -{ return T_OP_NRE; } - YY_BREAK -case 33: -YY_RULE_SETUP -#line 205 "ssl_expr_scan.l" -{ return T_OP_AND; } - YY_BREAK -case 34: -YY_RULE_SETUP -#line 206 "ssl_expr_scan.l" -{ return T_OP_AND; } - YY_BREAK -case 35: -YY_RULE_SETUP -#line 207 "ssl_expr_scan.l" -{ return T_OP_OR; } - YY_BREAK -case 36: -YY_RULE_SETUP -#line 208 "ssl_expr_scan.l" -{ return T_OP_OR; } - YY_BREAK -case 37: -YY_RULE_SETUP -#line 209 "ssl_expr_scan.l" -{ return T_OP_NOT; } - YY_BREAK -case 38: -YY_RULE_SETUP -#line 210 "ssl_expr_scan.l" -{ return T_OP_NOT; } - YY_BREAK -case 39: -YY_RULE_SETUP -#line 211 "ssl_expr_scan.l" -{ return T_OP_IN; } - YY_BREAK -/* - * Functions - */ -case 40: -YY_RULE_SETUP -#line 216 "ssl_expr_scan.l" -{ return T_FUNC_FILE; } - YY_BREAK -/* - * Specials - */ -case 41: -YY_RULE_SETUP -#line 221 "ssl_expr_scan.l" -{ return T_TRUE; } - YY_BREAK -case 42: -YY_RULE_SETUP -#line 222 "ssl_expr_scan.l" -{ return T_FALSE; } - YY_BREAK -/* - * Digits - */ -case 43: -YY_RULE_SETUP -#line 227 "ssl_expr_scan.l" -{ - yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, yytext); - return T_DIGIT; -} - YY_BREAK -/* - * Identifiers - */ -case 44: -YY_RULE_SETUP -#line 235 "ssl_expr_scan.l" -{ - yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, yytext); - return T_ID; -} - YY_BREAK -/* - * Anything else is returned as is... - */ -case 45: -YY_RULE_SETUP -#line 243 "ssl_expr_scan.l" -{ - return yytext[0]; -} - YY_BREAK -case 46: -YY_RULE_SETUP -#line 247 "ssl_expr_scan.l" -YY_FATAL_ERROR( "flex scanner jammed" ); - YY_BREAK -#line 1100 "lex.ssl_expr_yy.c" -case YY_STATE_EOF(INITIAL): -case YY_STATE_EOF(str): -case YY_STATE_EOF(regex): - yyterminate(); - - case YY_END_OF_BUFFER: - { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; - - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yy_hold_char; - YY_RESTORE_YY_MORE_OFFSET - - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) - { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed yyin at a new source and called - * yylex(). If so, then we have to assure - * consistency between yy_current_buffer and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - yy_n_chars = yy_current_buffer->yy_n_chars; - yy_current_buffer->yy_input_file = yyin; - yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; - } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) - { /* This was really a NUL. */ - yy_state_type yy_next_state; - - yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state(); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans( yy_current_state ); - - yy_bp = yytext_ptr + YY_MORE_ADJ; - - if ( yy_next_state ) - { - /* Consume the NUL. */ - yy_cp = ++yy_c_buf_p; - yy_current_state = yy_next_state; - goto yy_match; - } - - else - { - yy_cp = yy_last_accepting_cpos; - yy_current_state = yy_last_accepting_state; - goto yy_find_action; - } - } - - else switch ( yy_get_next_buffer() ) - { - case EOB_ACT_END_OF_FILE: - { - yy_did_buffer_switch_on_eof = 0; - - if ( yywrap() ) - { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * yytext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } - - else - { - if ( ! yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; - } - break; - } - - case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = - yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state(); - - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; - goto yy_match; - - case EOB_ACT_LAST_MATCH: - yy_c_buf_p = - &yy_current_buffer->yy_ch_buf[yy_n_chars]; - - yy_current_state = yy_get_previous_state(); - - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; - goto yy_find_action; - } - break; - } - - default: - YY_FATAL_ERROR( - "fatal flex scanner internal error--no action found" ); - } /* end of action switch */ - } /* end of scanning one token */ - } /* end of yylex */ - - -/* yy_get_next_buffer - try to read in a new buffer - * - * Returns a code representing an action: - * EOB_ACT_LAST_MATCH - - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position - * EOB_ACT_END_OF_FILE - end of file - */ - -static int yy_get_next_buffer() - { - register char *dest = yy_current_buffer->yy_ch_buf; - register char *source = yytext_ptr; - register int number_to_move, i; - int ret_val; - - if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( yy_current_buffer->yy_fill_buffer == 0 ) - { /* Don't try to fill the buffer, so this is an EOF. */ - if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) - { - /* We matched a single character, the EOB, so - * treat this as a final EOF. - */ - return EOB_ACT_END_OF_FILE; - } - - else - { - /* We matched some text prior to the EOB, first - * process it. - */ - return EOB_ACT_LAST_MATCH; - } - } - - /* Try to read more data. */ - - /* First move last chars to start of buffer. */ - number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; - - for ( i = 0; i < number_to_move; ++i ) - *(dest++) = *(source++); - - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) - /* don't do the read, it's not guaranteed to return an EOF, - * just force an EOF - */ - yy_current_buffer->yy_n_chars = yy_n_chars = 0; - - else - { - int num_to_read = - yy_current_buffer->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ -#ifdef YY_USES_REJECT - YY_FATAL_ERROR( -"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); -#else - - /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = yy_current_buffer; - - int yy_c_buf_p_offset = - (int) (yy_c_buf_p - b->yy_ch_buf); - - if ( b->yy_is_our_buffer ) - { - int new_size = b->yy_buf_size * 2; - - if ( new_size <= 0 ) - b->yy_buf_size += b->yy_buf_size / 8; - else - b->yy_buf_size *= 2; - - b->yy_ch_buf = (char *) - /* Include room in for 2 EOB chars. */ - yy_flex_realloc( (void *) b->yy_ch_buf, - b->yy_buf_size + 2 ); - } - else - /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; - - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( - "fatal error - scanner input buffer overflow" ); - - yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; - - num_to_read = yy_current_buffer->yy_buf_size - - number_to_move - 1; -#endif - } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), - yy_n_chars, num_to_read ); - - yy_current_buffer->yy_n_chars = yy_n_chars; - } - - if ( yy_n_chars == 0 ) - { - if ( number_to_move == YY_MORE_ADJ ) - { - ret_val = EOB_ACT_END_OF_FILE; - yyrestart( yyin ); - } - - else - { - ret_val = EOB_ACT_LAST_MATCH; - yy_current_buffer->yy_buffer_status = - YY_BUFFER_EOF_PENDING; - } - } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - yy_n_chars += number_to_move; - yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; - yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; - - yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; - - return ret_val; - } - - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - -static yy_state_type yy_get_previous_state() - { - register yy_state_type yy_current_state; - register char *yy_cp; - - yy_current_state = yy_start; - - for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) - { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); - if ( yy_accept[yy_current_state] ) - { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 86 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - } - - return yy_current_state; - } - - -/* yy_try_NUL_trans - try to make a transition on the NUL character - * - * synopsis - * next_state = yy_try_NUL_trans( current_state ); - */ - -#ifdef YY_USE_PROTOS -static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) -#else -static yy_state_type yy_try_NUL_trans( yy_current_state ) -yy_state_type yy_current_state; -#endif - { - register int yy_is_jam; - register char *yy_cp = yy_c_buf_p; - - register YY_CHAR yy_c = 1; - if ( yy_accept[yy_current_state] ) - { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 86 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 85); - - return yy_is_jam ? 0 : yy_current_state; - } - - -#ifndef YY_NO_UNPUT -#ifdef YY_USE_PROTOS -static void yyunput( int c, register char *yy_bp ) -#else -static void yyunput( c, yy_bp ) -int c; -register char *yy_bp; -#endif - { - register char *yy_cp = yy_c_buf_p; - - /* undo effects of setting up yytext */ - *yy_cp = yy_hold_char; - - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) - { /* need to shift things up to make room */ - /* +2 for EOB chars. */ - register int number_to_move = yy_n_chars + 2; - register char *dest = &yy_current_buffer->yy_ch_buf[ - yy_current_buffer->yy_buf_size + 2]; - register char *source = - &yy_current_buffer->yy_ch_buf[number_to_move]; - - while ( source > yy_current_buffer->yy_ch_buf ) - *--dest = *--source; - - yy_cp += (int) (dest - source); - yy_bp += (int) (dest - source); - yy_current_buffer->yy_n_chars = - yy_n_chars = yy_current_buffer->yy_buf_size; - - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) - YY_FATAL_ERROR( "flex scanner push-back overflow" ); - } - - *--yy_cp = (char) c; - - - yytext_ptr = yy_bp; - yy_hold_char = *yy_cp; - yy_c_buf_p = yy_cp; - } -#endif /* ifndef YY_NO_UNPUT */ - - -#ifdef __cplusplus -static int yyinput() -#else -static int input() -#endif - { - int c; - - *yy_c_buf_p = yy_hold_char; - - if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) - { - /* yy_c_buf_p now points to the character we want to return. - * If this occurs *before* the EOB characters, then it's a - * valid NUL; if not, then we've hit the end of the buffer. - */ - if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) - /* This was really a NUL. */ - *yy_c_buf_p = '\0'; - - else - { /* need more input */ - int offset = yy_c_buf_p - yytext_ptr; - ++yy_c_buf_p; - - switch ( yy_get_next_buffer() ) - { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ - - /* Reset buffer status. */ - yyrestart( yyin ); - - /* fall through */ - - case EOB_ACT_END_OF_FILE: - { - if ( yywrap() ) - return EOF; - - if ( ! yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; -#ifdef __cplusplus - return yyinput(); -#else - return input(); -#endif - } - - case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = yytext_ptr + offset; - break; - } - } - } - - c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ - *yy_c_buf_p = '\0'; /* preserve yytext */ - yy_hold_char = *++yy_c_buf_p; - - - return c; - } - - -#ifdef YY_USE_PROTOS -void yyrestart( FILE *input_file ) -#else -void yyrestart( input_file ) -FILE *input_file; -#endif - { - if ( ! yy_current_buffer ) - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); - - yy_init_buffer( yy_current_buffer, input_file ); - yy_load_buffer_state(); - } - - -#ifdef YY_USE_PROTOS -void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) -#else -void yy_switch_to_buffer( new_buffer ) -YY_BUFFER_STATE new_buffer; -#endif - { - if ( yy_current_buffer == new_buffer ) - return; - - if ( yy_current_buffer ) - { - /* Flush out information for old buffer. */ - *yy_c_buf_p = yy_hold_char; - yy_current_buffer->yy_buf_pos = yy_c_buf_p; - yy_current_buffer->yy_n_chars = yy_n_chars; - } - - yy_current_buffer = new_buffer; - yy_load_buffer_state(); - - /* We don't actually know whether we did this switch during - * EOF (yywrap()) processing, but the only time this flag - * is looked at is after yywrap() is called, so it's safe - * to go ahead and always set it. - */ - yy_did_buffer_switch_on_eof = 1; - } - - -#ifdef YY_USE_PROTOS -void yy_load_buffer_state( void ) -#else -void yy_load_buffer_state() -#endif - { - yy_n_chars = yy_current_buffer->yy_n_chars; - yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; - yyin = yy_current_buffer->yy_input_file; - yy_hold_char = *yy_c_buf_p; - } - - -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) -#else -YY_BUFFER_STATE yy_create_buffer( file, size ) -FILE *file; -int size; -#endif - { - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_buf_size = size; - - /* yy_ch_buf has to be 2 characters longer than the size given because - * we need to put in 2 end-of-buffer characters. - */ - b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_is_our_buffer = 1; - - yy_init_buffer( b, file ); - - return b; - } - - -#ifdef YY_USE_PROTOS -void yy_delete_buffer( YY_BUFFER_STATE b ) -#else -void yy_delete_buffer( b ) -YY_BUFFER_STATE b; -#endif - { - if ( ! b ) - return; - - if ( b == yy_current_buffer ) - yy_current_buffer = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - yy_flex_free( (void *) b->yy_ch_buf ); - - yy_flex_free( (void *) b ); - } - - -#ifndef YY_ALWAYS_INTERACTIVE -#ifndef YY_NEVER_INTERACTIVE -extern int isatty YY_PROTO(( int )); -#endif -#endif - -#ifdef YY_USE_PROTOS -void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) -#else -void yy_init_buffer( b, file ) -YY_BUFFER_STATE b; -FILE *file; -#endif - - - { - yy_flush_buffer( b ); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - -#if YY_ALWAYS_INTERACTIVE - b->yy_is_interactive = 1; -#else -#if YY_NEVER_INTERACTIVE - b->yy_is_interactive = 0; -#else - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; -#endif -#endif - } - - -#ifdef YY_USE_PROTOS -void yy_flush_buffer( YY_BUFFER_STATE b ) -#else -void yy_flush_buffer( b ) -YY_BUFFER_STATE b; -#endif - - { - if ( ! b ) - return; - - b->yy_n_chars = 0; - - /* We always need two end-of-buffer characters. The first causes - * a transition to the end-of-buffer state. The second causes - * a jam in that state. - */ - b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; - - b->yy_buf_pos = &b->yy_ch_buf[0]; - - b->yy_at_bol = 1; - b->yy_buffer_status = YY_BUFFER_NEW; - - if ( b == yy_current_buffer ) - yy_load_buffer_state(); - } - - -#ifndef YY_NO_SCAN_BUFFER -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) -#else -YY_BUFFER_STATE yy_scan_buffer( base, size ) -char *base; -yy_size_t size; -#endif - { - YY_BUFFER_STATE b; - - if ( size < 2 || - base[size-2] != YY_END_OF_BUFFER_CHAR || - base[size-1] != YY_END_OF_BUFFER_CHAR ) - /* They forgot to leave room for the EOB's. */ - return 0; - - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); - - b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ - b->yy_buf_pos = b->yy_ch_buf = base; - b->yy_is_our_buffer = 0; - b->yy_input_file = 0; - b->yy_n_chars = b->yy_buf_size; - b->yy_is_interactive = 0; - b->yy_at_bol = 1; - b->yy_fill_buffer = 0; - b->yy_buffer_status = YY_BUFFER_NEW; - - yy_switch_to_buffer( b ); - - return b; - } -#endif - - -#ifndef YY_NO_SCAN_STRING -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) -#else -YY_BUFFER_STATE yy_scan_string( yy_str ) -yyconst char *yy_str; -#endif - { - int len; - for ( len = 0; yy_str[len]; ++len ) - ; - - return yy_scan_bytes( yy_str, len ); - } -#endif - - -#ifndef YY_NO_SCAN_BYTES -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) -#else -YY_BUFFER_STATE yy_scan_bytes( bytes, len ) -yyconst char *bytes; -int len; -#endif - { - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - int i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = len + 2; - buf = (char *) yy_flex_alloc( n ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - - for ( i = 0; i < len; ++i ) - buf[i] = bytes[i]; - - buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; - - b = yy_scan_buffer( buf, n ); - if ( ! b ) - YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); - - /* It's okay to grow etc. this buffer, and we should throw it - * away when we're done. - */ - b->yy_is_our_buffer = 1; - - return b; - } -#endif - - -#ifndef YY_NO_PUSH_STATE -#ifdef YY_USE_PROTOS -static void yy_push_state( int new_state ) -#else -static void yy_push_state( new_state ) -int new_state; -#endif - { - if ( yy_start_stack_ptr >= yy_start_stack_depth ) - { - yy_size_t new_size; - - yy_start_stack_depth += YY_START_STACK_INCR; - new_size = yy_start_stack_depth * sizeof( int ); - - if ( ! yy_start_stack ) - yy_start_stack = (int *) yy_flex_alloc( new_size ); - - else - yy_start_stack = (int *) yy_flex_realloc( - (void *) yy_start_stack, new_size ); - - if ( ! yy_start_stack ) - YY_FATAL_ERROR( - "out of memory expanding start-condition stack" ); - } - - yy_start_stack[yy_start_stack_ptr++] = YY_START; - - BEGIN(new_state); - } -#endif - - -#ifndef YY_NO_POP_STATE -static void yy_pop_state() - { - if ( --yy_start_stack_ptr < 0 ) - YY_FATAL_ERROR( "start-condition stack underflow" ); - - BEGIN(yy_start_stack[yy_start_stack_ptr]); - } -#endif - - -#ifndef YY_NO_TOP_STATE -static int yy_top_state() - { - return yy_start_stack[yy_start_stack_ptr - 1]; - } -#endif - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -#ifdef YY_USE_PROTOS -static void yy_fatal_error( yyconst char msg[] ) -#else -static void yy_fatal_error( msg ) -char msg[]; -#endif - { - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); - } - - - -/* Redefine yyless() so it works in section 3 code. */ - -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - yytext[yyleng] = yy_hold_char; \ - yy_c_buf_p = yytext + n; \ - yy_hold_char = *yy_c_buf_p; \ - *yy_c_buf_p = '\0'; \ - yyleng = n; \ - } \ - while ( 0 ) - - -/* Internal utility routines. */ - -#ifndef yytext_ptr -#ifdef YY_USE_PROTOS -static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) -#else -static void yy_flex_strncpy( s1, s2, n ) -char *s1; -yyconst char *s2; -int n; -#endif - { - register int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; - } -#endif - -#ifdef YY_NEED_STRLEN -#ifdef YY_USE_PROTOS -static int yy_flex_strlen( yyconst char *s ) -#else -static int yy_flex_strlen( s ) -yyconst char *s; -#endif - { - register int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; - } -#endif - - -#ifdef YY_USE_PROTOS -static void *yy_flex_alloc( yy_size_t size ) -#else -static void *yy_flex_alloc( size ) -yy_size_t size; -#endif - { - return (void *) malloc( size ); - } - -#ifdef YY_USE_PROTOS -static void *yy_flex_realloc( void *ptr, yy_size_t size ) -#else -static void *yy_flex_realloc( ptr, size ) -void *ptr; -yy_size_t size; -#endif - { - /* The cast to (char *) in the following accommodates both - * implementations that use char* generic pointers, and those - * that use void* generic pointers. It works with the latter - * because both ANSI C and C++ allow castless assignment from - * any pointer type to void*, and deal with argument conversions - * as though doing an assignment. - */ - return (void *) realloc( (char *) ptr, size ); - } - -#ifdef YY_USE_PROTOS -static void yy_flex_free( void *ptr ) -#else -static void yy_flex_free( ptr ) -void *ptr; -#endif - { - free( ptr ); - } - -#if YY_MAIN -int main() - { - yylex(); - return 0; - } -#endif -#line 247 "ssl_expr_scan.l" - - -int yyinput(char *buf, int max_size) -{ - int n; - - if ((n = MIN(max_size, ssl_expr_info.inputbuf - + ssl_expr_info.inputlen - - ssl_expr_info.inputptr)) <= 0) - return YY_NULL; - memcpy(buf, ssl_expr_info.inputptr, n); - ssl_expr_info.inputptr += n; - return n; -} - diff --git a/modules/ssl/ssl_expr_scan.l b/modules/ssl/ssl_expr_scan.l deleted file mode 100644 index a0db7cccde..0000000000 --- a/modules/ssl/ssl_expr_scan.l +++ /dev/null @@ -1,261 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | -** | '_ ` _ \ / _ \ / _` | / __/ __| | -** | | | | | | (_) | (_| | \__ \__ \ | mod_ssl - Apache Interface to OpenSSL -** |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/ -** |_____| -** ssl_expr_scan.l -** Expression Scanner -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - - /* ``Killing for peace is - like fucking for virginity.'' - -- Unknown */ - -/* _________________________________________________________________ -** -** Expression Scanner -** _________________________________________________________________ -*/ - -%{ -#include "mod_ssl.h" - -#include "ssl_expr_parse.h" - -#define YY_NO_UNPUT 1 -int yyinput(char *buf, int max_size); - -#undef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - (result = yyinput(buf, max_size)) - -#define MAX_STR_LEN 2048 -%} - -%pointer -/* %option stack */ -%option never-interactive -%option noyywrap -%x str -%x regex regex_flags - -%% - - char caStr[MAX_STR_LEN]; - char *cpStr = NULL; - char caRegex[MAX_STR_LEN]; - char *cpRegex = NULL; - char cRegexDel = NUL; - - /* - * Whitespaces - */ -[ \t\n]+ { - /* NOP */ -} - - /* - * C-style strings ("...") - */ -\" { - cpStr = caStr; - BEGIN(str); -} -<str>\" { - BEGIN(INITIAL); - *cpStr = NUL; - yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, caStr); - return T_STRING; -} -<str>\n { - yyerror("Unterminated string"); -} -<str>\\[0-7]{1,3} { - int result; - - (void)sscanf(yytext+1, "%o", &result); - if (result > 0xff) - yyerror("Escape sequence out of bound"); - else - *cpStr++ = result; -} -<str>\\[0-9]+ { - yyerror("Bad escape sequence"); -} -<str>\\n { *cpStr++ = '\n'; } -<str>\\r { *cpStr++ = '\r'; } -<str>\\t { *cpStr++ = '\t'; } -<str>\\b { *cpStr++ = '\b'; } -<str>\\f { *cpStr++ = '\f'; } -<str>\\(.|\n) { - *cpStr++ = yytext[1]; -} -<str>[^\\\n\"]+ { - char *cp = yytext; - while (*cp != NUL) - *cpStr++ = *cp++; -} -<str>. { - *cpStr++ = yytext[1]; -} - - /* - * Regular Expression - */ -"m". { - cRegexDel = yytext[1]; - cpRegex = caRegex; - BEGIN(regex); -} -<regex>.|\n { - if (yytext[0] == cRegexDel) { - *cpRegex = NUL; - BEGIN(regex_flags); - } - else { - *cpRegex++ = yytext[0]; - } -} -<regex_flags>i { - yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, caRegex); - BEGIN(INITIAL); - return T_REGEX_I; -} -<regex_flags>.|\n { - yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, caRegex); - yyless(0); - BEGIN(INITIAL); - return T_REGEX; -} -<regex_flags><<EOF>> { - yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, caRegex); - BEGIN(INITIAL); - return T_REGEX; -} - - /* - * Operators - */ -"eq" { return T_OP_EQ; } -"==" { return T_OP_EQ; } -"ne" { return T_OP_NE; } -"!=" { return T_OP_NE; } -"lt" { return T_OP_LT; } -"<" { return T_OP_LT; } -"le" { return T_OP_LE; } -"<=" { return T_OP_LE; } -"gt" { return T_OP_GT; } -">" { return T_OP_GT; } -"ge" { return T_OP_GE; } -">=" { return T_OP_GE; } -"=~" { return T_OP_REG; } -"!~" { return T_OP_NRE; } -"and" { return T_OP_AND; } -"&&" { return T_OP_AND; } -"or" { return T_OP_OR; } -"||" { return T_OP_OR; } -"not" { return T_OP_NOT; } -"!" { return T_OP_NOT; } -"in" { return T_OP_IN; } - - /* - * Functions - */ -"file" { return T_FUNC_FILE; } - - /* - * Specials - */ -"true" { return T_TRUE; } -"false" { return T_FALSE; } - - /* - * Digits - */ -[0-9]+ { - yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, yytext); - return T_DIGIT; -} - - /* - * Identifiers - */ -[a-zA-Z][a-zA-Z0-9_:-]* { - yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, yytext); - return T_ID; -} - - /* - * Anything else is returned as is... - */ -.|\n { - return yytext[0]; -} - -%% - -int yyinput(char *buf, int max_size) -{ - int n; - - if ((n = MIN(max_size, ssl_expr_info.inputbuf - + ssl_expr_info.inputlen - - ssl_expr_info.inputptr)) <= 0) - return YY_NULL; - memcpy(buf, ssl_expr_info.inputptr, n); - ssl_expr_info.inputptr += n; - return n; -} - diff --git a/modules/ssl/ssl_scache.c b/modules/ssl/ssl_scache.c deleted file mode 100644 index 139c7865fe..0000000000 --- a/modules/ssl/ssl_scache.c +++ /dev/null @@ -1,204 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_scache.c -** Session Cache Abstraction -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - /* ``Open-Source Software: generous - programmers from around the world all - join forces to help you shoot - yourself in the foot for free.'' - -- Unknown */ -#include "mod_ssl.h" - -/* _________________________________________________________________ -** -** Session Cache: Common Abstraction Layer -** _________________________________________________________________ -*/ - -void ssl_scache_init(server_rec *s, pool *p) -{ - SSLModConfigRec *mc = myModConfig(); - - if (mc->nSessionCacheMode == SSL_SCMODE_DBM) - ssl_scache_dbm_init(s, p); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - ssl_scache_shmht_init(s, p); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) - ssl_scache_shmcb_init(s, p); -#ifdef SSL_VENDOR - else - ap_hook_use("ap::mod_ssl::vendor::scache_init", - AP_HOOK_SIG3(void,ptr,ptr), AP_HOOK_ALL, s, p); -#endif - return; -} - -void ssl_scache_kill(server_rec *s) -{ - SSLModConfigRec *mc = myModConfig(); - - if (mc->nSessionCacheMode == SSL_SCMODE_DBM) - ssl_scache_dbm_kill(s); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - ssl_scache_shmht_kill(s); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) - ssl_scache_shmcb_kill(s); -#ifdef SSL_VENDOR - else - ap_hook_use("ap::mod_ssl::vendor::scache_kill", - AP_HOOK_SIG2(void,ptr), AP_HOOK_ALL, s); -#endif - return; -} - -BOOL ssl_scache_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess) -{ - SSLModConfigRec *mc = myModConfig(); - BOOL rv = FALSE; - - if (mc->nSessionCacheMode == SSL_SCMODE_DBM) - rv = ssl_scache_dbm_store(s, id, idlen, expiry, sess); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - rv = ssl_scache_shmht_store(s, id, idlen, expiry, sess); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) - rv = ssl_scache_shmcb_store(s, id, idlen, expiry, sess); -#ifdef SSL_VENDOR - else - ap_hook_use("ap::mod_ssl::vendor::scache_store", - AP_HOOK_SIG6(int,ptr,ptr,int,int,ptr), AP_HOOK_ALL, - (int *)&rv, s, id, idlen, (int)expiry, sess); -#endif - return rv; -} - -SSL_SESSION *ssl_scache_retrieve(server_rec *s, UCHAR *id, int idlen) -{ - SSLModConfigRec *mc = myModConfig(); - SSL_SESSION *sess = NULL; - - if (mc->nSessionCacheMode == SSL_SCMODE_DBM) - sess = ssl_scache_dbm_retrieve(s, id, idlen); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - sess = ssl_scache_shmht_retrieve(s, id, idlen); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) - sess = ssl_scache_shmcb_retrieve(s, id, idlen); -#ifdef SSL_VENDOR - else - ap_hook_use("ap::mod_ssl::vendor::scache_retrieve", - AP_HOOK_SIG4(ptr,ptr,ptr,int), AP_HOOK_ALL, - &sess, s, id, idlen); -#endif - return sess; -} - -void ssl_scache_remove(server_rec *s, UCHAR *id, int idlen) -{ - SSLModConfigRec *mc = myModConfig(); - - if (mc->nSessionCacheMode == SSL_SCMODE_DBM) - ssl_scache_dbm_remove(s, id, idlen); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - ssl_scache_shmht_remove(s, id, idlen); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) - ssl_scache_shmcb_remove(s, id, idlen); -#ifdef SSL_VENDOR - else - ap_hook_use("ap::mod_ssl::vendor::scache_remove", - AP_HOOK_SIG4(void,ptr,ptr,int), AP_HOOK_ALL, s, id, idlen); -#endif - return; -} - -void ssl_scache_status(server_rec *s, pool *p, void (*func)(char *, void *), void *arg) -{ - SSLModConfigRec *mc = myModConfig(); - - if (mc->nSessionCacheMode == SSL_SCMODE_DBM) - ssl_scache_dbm_status(s, p, func, arg); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - ssl_scache_shmht_status(s, p, func, arg); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) - ssl_scache_shmcb_status(s, p, func, arg); -#ifdef SSL_VENDOR - else - ap_hook_use("ap::mod_ssl::vendor::scache_status", - AP_HOOK_SIG5(void,ptr,ptr,ptr,ptr), AP_HOOK_ALL, - s, p, func, arg); -#endif - return; -} - -void ssl_scache_expire(server_rec *s) -{ - SSLModConfigRec *mc = myModConfig(); - - if (mc->nSessionCacheMode == SSL_SCMODE_DBM) - ssl_scache_dbm_expire(s); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - ssl_scache_shmht_expire(s); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) - ssl_scache_shmcb_expire(s); -#ifdef SSL_VENDOR - else - ap_hook_use("ap::mod_ssl::vendor::scache_expire", - AP_HOOK_SIG2(void,ptr), AP_HOOK_ALL, s); -#endif - return; -} - diff --git a/modules/ssl/ssl_scache_dbm.c b/modules/ssl/ssl_scache_dbm.c deleted file mode 100644 index 323c612991..0000000000 --- a/modules/ssl/ssl_scache_dbm.c +++ /dev/null @@ -1,440 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_scache_dbm.c -** Session Cache via DBM -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - -#include "mod_ssl.h" - -void ssl_scache_dbm_init(server_rec *s, pool *p) -{ - SSLModConfigRec *mc = myModConfig(); - DBM *dbm; - - /* for the DBM we need the data file */ - if (mc->szSessionCacheDataFile == NULL) { - ssl_log(s, SSL_LOG_ERROR, "SSLSessionCache required"); - ssl_die(); - } - - /* open it once to create it and to make sure it _can_ be created */ - ssl_mutex_on(s); - if ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile, - O_RDWR|O_CREAT, SSL_DBM_FILE_MODE)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Cannot create SSLSessionCache DBM file `%s'", - mc->szSessionCacheDataFile); - ssl_mutex_off(s); - return; - } - ssl_dbm_close(dbm); - -#if !defined(OS2) && !defined(WIN32) - /* - * We have to make sure the Apache child processes have access to - * the DBM file. But because there are brain-dead platforms where we - * cannot exactly determine the suffixes we try all possibilities. - */ - if (geteuid() == 0 /* is superuser */) { - chown(mc->szSessionCacheDataFile, ap_user_id, -1 /* no gid change */); - if (chown(ap_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_DIR, NULL), - ap_user_id, -1) == -1) { - if (chown(ap_pstrcat(p, mc->szSessionCacheDataFile, ".db", NULL), - ap_user_id, -1) == -1) - chown(ap_pstrcat(p, mc->szSessionCacheDataFile, ".dir", NULL), - ap_user_id, -1); - } - if (chown(ap_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_PAG, NULL), - ap_user_id, -1) == -1) { - if (chown(ap_pstrcat(p, mc->szSessionCacheDataFile, ".db", NULL), - ap_user_id, -1) == -1) - chown(ap_pstrcat(p, mc->szSessionCacheDataFile, ".pag", NULL), - ap_user_id, -1); - } - } -#endif - ssl_mutex_off(s); - ssl_scache_dbm_expire(s); - return; -} - -void ssl_scache_dbm_kill(server_rec *s) -{ - SSLModConfigRec *mc = myModConfig(); - pool *p; - - if ((p = ap_make_sub_pool(NULL)) != NULL) { - /* the correct way */ - unlink(ap_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_DIR, NULL)); - unlink(ap_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_PAG, NULL)); - /* the additional ways to be sure */ - unlink(ap_pstrcat(p, mc->szSessionCacheDataFile, ".dir", NULL)); - unlink(ap_pstrcat(p, mc->szSessionCacheDataFile, ".pag", NULL)); - unlink(ap_pstrcat(p, mc->szSessionCacheDataFile, ".db", NULL)); - unlink(mc->szSessionCacheDataFile); - ap_destroy_pool(p); - } - return; -} - -BOOL ssl_scache_dbm_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess) -{ - SSLModConfigRec *mc = myModConfig(); - DBM *dbm; - datum dbmkey; - datum dbmval; - UCHAR ucaData[SSL_SESSION_MAX_DER]; - int nData; - UCHAR *ucp; - - /* streamline session data */ - ucp = ucaData; - nData = i2d_SSL_SESSION(sess, &ucp); - - /* be careful: do not try to store too much bytes in a DBM file! */ -#ifdef SSL_USE_SDBM - if ((idlen + nData) >= PAIRMAX) - return FALSE; -#else - if ((idlen + nData) >= 950 /* at least less than approx. 1KB */) - return FALSE; -#endif - - /* create DBM key */ - dbmkey.dptr = (char *)id; - dbmkey.dsize = idlen; - - /* create DBM value */ - dbmval.dsize = sizeof(time_t) + nData; - dbmval.dptr = (char *)malloc(dbmval.dsize); - if (dbmval.dptr == NULL) - return FALSE; - memcpy((char *)dbmval.dptr, &expiry, sizeof(time_t)); - memcpy((char *)dbmval.dptr+sizeof(time_t), ucaData, nData); - - /* and store it to the DBM file */ - ssl_mutex_on(s); - if ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile, - O_RDWR, SSL_DBM_FILE_MODE)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Cannot open SSLSessionCache DBM file `%s' for writing (store)", - mc->szSessionCacheDataFile); - ssl_mutex_off(s); - free(dbmval.dptr); - return FALSE; - } - if (ssl_dbm_store(dbm, dbmkey, dbmval, DBM_INSERT) < 0) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Cannot store SSL session to DBM file `%s'", - mc->szSessionCacheDataFile); - ssl_dbm_close(dbm); - ssl_mutex_off(s); - free(dbmval.dptr); - return FALSE; - } - ssl_dbm_close(dbm); - ssl_mutex_off(s); - - /* free temporary buffers */ - free(dbmval.dptr); - - /* allow the regular expiring to occur */ - ssl_scache_dbm_expire(s); - - return TRUE; -} - -SSL_SESSION *ssl_scache_dbm_retrieve(server_rec *s, UCHAR *id, int idlen) -{ - SSLModConfigRec *mc = myModConfig(); - DBM *dbm; - datum dbmkey; - datum dbmval; - SSL_SESSION *sess = NULL; - UCHAR *ucpData; - int nData; - time_t expiry; - time_t now; - - /* allow the regular expiring to occur */ - ssl_scache_dbm_expire(s); - - /* create DBM key and values */ - dbmkey.dptr = (char *)id; - dbmkey.dsize = idlen; - - /* and fetch it from the DBM file */ - ssl_mutex_on(s); - if ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile, - O_RDONLY, SSL_DBM_FILE_MODE)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Cannot open SSLSessionCache DBM file `%s' for reading (fetch)", - mc->szSessionCacheDataFile); - ssl_mutex_off(s); - return NULL; - } - dbmval = ssl_dbm_fetch(dbm, dbmkey); - ssl_dbm_close(dbm); - ssl_mutex_off(s); - - /* immediately return if not found */ - if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(time_t)) - return NULL; - - /* parse resulting data */ - nData = dbmval.dsize-sizeof(time_t); - ucpData = (UCHAR *)malloc(nData); - if (ucpData == NULL) - return NULL; - memcpy(ucpData, (char *)dbmval.dptr+sizeof(time_t), nData); - memcpy(&expiry, dbmval.dptr, sizeof(time_t)); - - /* make sure the stuff is still not expired */ - now = time(NULL); - if (expiry <= now) { - ssl_scache_dbm_remove(s, id, idlen); - return NULL; - } - - /* unstreamed SSL_SESSION */ - sess = d2i_SSL_SESSION(NULL, &ucpData, nData); - - return sess; -} - -void ssl_scache_dbm_remove(server_rec *s, UCHAR *id, int idlen) -{ - SSLModConfigRec *mc = myModConfig(); - DBM *dbm; - datum dbmkey; - - /* create DBM key and values */ - dbmkey.dptr = (char *)id; - dbmkey.dsize = idlen; - - /* and delete it from the DBM file */ - ssl_mutex_on(s); - if ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile, - O_RDWR, SSL_DBM_FILE_MODE)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Cannot open SSLSessionCache DBM file `%s' for writing (delete)", - mc->szSessionCacheDataFile); - ssl_mutex_off(s); - return; - } - ssl_dbm_delete(dbm, dbmkey); - ssl_dbm_close(dbm); - ssl_mutex_off(s); - - return; -} - -void ssl_scache_dbm_expire(server_rec *s) -{ - SSLModConfigRec *mc = myModConfig(); - SSLSrvConfigRec *sc = mySrvConfig(s); - static time_t tLast = 0; - DBM *dbm; - datum dbmkey; - datum dbmval; - pool *p; - time_t tExpiresAt; - int nElements = 0; - int nDeleted = 0; - int bDelete; - datum *keylist; - int keyidx; - int i; - time_t tNow; - - /* - * make sure the expiration for still not-accessed session - * cache entries is done only from time to time - */ - tNow = time(NULL); - if (tNow < tLast+sc->nSessionCacheTimeout) - return; - tLast = tNow; - - /* - * Here we have to be very carefully: Not all DBM libraries are - * smart enough to allow one to iterate over the elements and at the - * same time delete expired ones. Some of them get totally crazy - * while others have no problems. So we have to do it the slower but - * more safe way: we first iterate over all elements and remember - * those which have to be expired. Then in a second pass we delete - * all those expired elements. Additionally we reopen the DBM file - * to be really safe in state. - */ - -#define KEYMAX 1024 - - ssl_mutex_on(s); - for (;;) { - /* allocate the key array in a memory sub pool */ - if ((p = ap_make_sub_pool(NULL)) == NULL) - break; - if ((keylist = ap_palloc(p, sizeof(dbmkey)*KEYMAX)) == NULL) { - ap_destroy_pool(p); - break; - } - - /* pass 1: scan DBM database */ - keyidx = 0; - if ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile, - O_RDWR, SSL_DBM_FILE_MODE)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Cannot open SSLSessionCache DBM file `%s' for scanning", - mc->szSessionCacheDataFile); - ap_destroy_pool(p); - break; - } - dbmkey = ssl_dbm_firstkey(dbm); - while (dbmkey.dptr != NULL) { - nElements++; - bDelete = FALSE; - dbmval = ssl_dbm_fetch(dbm, dbmkey); - if (dbmval.dsize <= sizeof(time_t) || dbmval.dptr == NULL) - bDelete = TRUE; - else { - memcpy(&tExpiresAt, dbmval.dptr, sizeof(time_t)); - if (tExpiresAt <= tNow) - bDelete = TRUE; - } - if (bDelete) { - if ((keylist[keyidx].dptr = ap_palloc(p, dbmkey.dsize)) != NULL) { - memcpy(keylist[keyidx].dptr, dbmkey.dptr, dbmkey.dsize); - keylist[keyidx].dsize = dbmkey.dsize; - keyidx++; - if (keyidx == KEYMAX) - break; - } - } - dbmkey = ssl_dbm_nextkey(dbm); - } - ssl_dbm_close(dbm); - - /* pass 2: delete expired elements */ - if ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile, - O_RDWR, SSL_DBM_FILE_MODE)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Cannot re-open SSLSessionCache DBM file `%s' for expiring", - mc->szSessionCacheDataFile); - ap_destroy_pool(p); - break; - } - for (i = 0; i < keyidx; i++) { - ssl_dbm_delete(dbm, keylist[i]); - nDeleted++; - } - ssl_dbm_close(dbm); - - /* destroy temporary pool */ - ap_destroy_pool(p); - - if (keyidx < KEYMAX) - break; - } - ssl_mutex_off(s); - - ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache (DBM) Expiry: " - "old: %d, new: %d, removed: %d", nElements, nElements-nDeleted, nDeleted); - return; -} - -void ssl_scache_dbm_status(server_rec *s, pool *p, void (*func)(char *, void *), void *arg) -{ - SSLModConfigRec *mc = myModConfig(); - DBM *dbm; - datum dbmkey; - datum dbmval; - int nElem; - int nSize; - int nAverage; - - nElem = 0; - nSize = 0; - ssl_mutex_on(s); - if ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile, - O_RDONLY, SSL_DBM_FILE_MODE)) == NULL) { - ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, - "Cannot open SSLSessionCache DBM file `%s' for status retrival", - mc->szSessionCacheDataFile); - ssl_mutex_off(s); - return; - } - dbmkey = ssl_dbm_firstkey(dbm); - for ( ; dbmkey.dptr != NULL; dbmkey = ssl_dbm_nextkey(dbm)) { - dbmval = ssl_dbm_fetch(dbm, dbmkey); - if (dbmval.dptr == NULL) - continue; - nElem += 1; - nSize += dbmval.dsize; - } - ssl_dbm_close(dbm); - ssl_mutex_off(s); - if (nSize > 0 && nElem > 0) - nAverage = nSize / nElem; - else - nAverage = 0; - func(ap_psprintf(p, "cache type: <b>DBM</b>, maximum size: <b>unlimited</b><br>"), arg); - func(ap_psprintf(p, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize), arg); - func(ap_psprintf(p, "average session size: <b>%d</b> bytes<br>", nAverage), arg); - return; -} - diff --git a/modules/ssl/ssl_scache_shmcb.c b/modules/ssl/ssl_scache_shmcb.c deleted file mode 100644 index e588f0a5d1..0000000000 --- a/modules/ssl/ssl_scache_shmcb.c +++ /dev/null @@ -1,1343 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_scache_shmcb.c -** Session Cache via Shared Memory (Cyclic Buffer Variant) -*/ - -/* ==================================================================== - * Copyright (c) 2000-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - -#include "mod_ssl.h" - -/* - * This shared memory based SSL session cache implementation was - * originally written by Geoff Thorpe <geoff@eu.c2.net> for C2Net Europe - * and as a contribution to Ralf Engelschall's mod_ssl project. - */ - -/* - * The shared-memory segment header can be cast to and from the - * SHMCBHeader type, all other structures need to be initialised by - * utility functions. - * - * The "header" looks like this; - * - * data applying to the overall structure: - * - division_offset (unsigned int): - * how far into the shared memory segment the first division is. - * - division_size (unsigned int): - * how many bytes each division occupies. - * (NB: This includes the queue and the cache) - * - division_mask (unsigned char): - * the "mask" in the next line. Add one to this, - * and that's the number of divisions. - * - * data applying to within each division: - * - queue_size (unsigned int): - * how big each "queue" is. NB: The queue is the first block in each - * division and is followed immediately by the cache itself so so - * there's no cache_offset value. - * - * data applying to within each queue: - * - index_num (unsigned char): - * how many indexes in each cache's queue - * - index_offset (unsigned char): - * how far into the queue the first index is. - * - index_size: - * how big each index is. - * - * data applying to within each cache: - * - cache_data_offset (unsigned int): - * how far into the cache the session-data array is stored. - * - cache_data_size (unsigned int): - * how big each cache's data block is. - * - * statistics data (this will eventually be per-division but right now - * there's only one mutex): - * - stores (unsigned long): - * how many stores have been performed in the cache. - * - expiries (unsigned long): - * how many session have been expired from the cache. - * - scrolled (unsigned long): - * how many sessions have been scrolled out of full cache during a - * "store" operation. This is different to the "removes" stats as - * they are requested by mod_ssl/Apache, these are done because of - * cache logistics. (NB: Also, this value should be deducible from - * the others if my code has no bugs, but I count it anyway - plus - * it helps debugging :-). - * - retrieves_hit (unsigned long): - * how many session-retrieves have succeeded. - * - retrieves_miss (unsigned long): - * how many session-retrieves have failed. - * - removes_hit (unsigned long): - * - removes_miss (unsigned long): - * - * Following immediately after the header is an array of "divisions". - * Each division is simply a "queue" immediately followed by its - * corresponding "cache". Each division handles some pre-defined band - * of sessions by using the "division_mask" in the header. Eg. if - * division_mask=0x1f then there are 32 divisions, the first of which - * will store sessions whose least-significant 5 bits are 0, the second - * stores session whose LS 5 bits equal 1, etc. A queue is an indexing - * structure referring to its corresponding cache. - * - * A "queue" looks like this; - * - * - first_pos (unsigned int): - * the location within the array of indexes where the virtual - * "left-hand-edge" of the cyclic buffer is. - * - pos_count (unsigned int): - * the number of indexes occupied from first_pos onwards. - * - * ...followed by an array of indexes, each of which can be - * memcpy'd to and from an SHMCBIndex, and look like this; - * - * - expires (time_t): - * the time() value at which this session expires. - * - offset (unsigned int): - * the offset within the cache data block where the corresponding - * session is stored. - * - s_id2 (unsigned char): - * the second byte of the session_id, stored as an optimisation to - * reduce the number of d2i_SSL_SESSION calls that are made when doing - * a lookup. - * - removed (unsigned char): - * a byte used to indicate whether a session has been "passively" - * removed. Ie. it is still in the cache but is to be disregarded by - * any "retrieve" operation. - * - * A "cache" looks like this; - * - * - first_pos (unsigned int): - * the location within the data block where the virtual - * "left-hand-edge" of the cyclic buffer is. - * - pos_count (unsigned int): - * the number of bytes used in the data block from first_pos onwards. - * - * ...followed by the data block in which actual DER-encoded SSL - * sessions are stored. - */ - -/* - * Header - can be memcpy'd to and from the front of the shared - * memory segment. NB: The first copy (commented out) has the - * elements in a meaningful order, but due to data-alignment - * braindeadness, the second (uncommented) copy has the types grouped - * so as to decrease "struct-bloat". sigh. - */ -typedef struct { -#if 0 - unsigned char division_mask; - unsigned int division_offset; - unsigned int division_size; - unsigned int queue_size; - unsigned char index_num; - unsigned char index_offset; - unsigned char index_size; - unsigned int cache_data_offset; - unsigned int cache_data_size; - unsigned long num_stores; - unsigned long num_expiries; - unsigned long num_scrolled; - unsigned long num_retrieves_hit; - unsigned long num_retrieves_miss; - unsigned long num_removes_hit; - unsigned long num_removes_miss; -#else - unsigned long num_stores; - unsigned long num_expiries; - unsigned long num_scrolled; - unsigned long num_retrieves_hit; - unsigned long num_retrieves_miss; - unsigned long num_removes_hit; - unsigned long num_removes_miss; - unsigned int division_offset; - unsigned int division_size; - unsigned int queue_size; - unsigned int cache_data_offset; - unsigned int cache_data_size; - unsigned char division_mask; - unsigned char index_num; - unsigned char index_offset; - unsigned char index_size; -#endif -} SHMCBHeader; - -/* - * Index - can be memcpy'd to and from an index inside each - * queue's index array. - */ -typedef struct { - time_t expires; - unsigned int offset; - unsigned char s_id2; - unsigned char removed; -} SHMCBIndex; - -/* - * Queue - must be populated by a call to shmcb_get_division - * and the structure's pointers are used for updating (ie. - * the structure doesn't need any "set" to update values). - */ -typedef struct { - SHMCBHeader *header; - unsigned int *first_pos; - unsigned int *pos_count; - SHMCBIndex *indexes; -} SHMCBQueue; - -/* - * Cache - same comment as for Queue. 'Queue's are in a 1-1 - * correspondance with 'Cache's and are usually carried round - * in a pair, they are only seperated for clarity. - */ -typedef struct { - SHMCBHeader *header; - unsigned int *first_pos; - unsigned int *pos_count; - unsigned char *data; -} SHMCBCache; - -/* - * Forward function prototypes. - */ - -/* Functions for working around data-alignment-picky systems (sparcs, - Irix, etc). These use "memcpy" as a way of foxing these systems into - treating the composite types as byte-arrays rather than higher-level - primitives that it prefers to have 4-(or 8-)byte aligned. I don't - envisage this being a performance issue as a couple of 2 or 4 byte - memcpys can hardly make a dent on the massive memmove operations this - cache technique avoids, nor the overheads of ASN en/decoding. */ -static unsigned int shmcb_get_safe_uint(unsigned int *); -static void shmcb_set_safe_uint(unsigned int *, unsigned int); -#if 0 /* Unused so far */ -static unsigned long shmcb_get_safe_ulong(unsigned long *); -static void shmcb_set_safe_ulong(unsigned long *, unsigned long); -#endif -static time_t shmcb_get_safe_time(time_t *); -static void shmcb_set_safe_time(time_t *, time_t); - -/* Underlying functions for session-caching */ -static BOOL shmcb_init_memory(server_rec *, void *, unsigned int); -static BOOL shmcb_store_session(server_rec *, void *, UCHAR *, int, SSL_SESSION *, time_t); -static SSL_SESSION *shmcb_retrieve_session(server_rec *, void *, UCHAR *, int); -static BOOL shmcb_remove_session(server_rec *, void *, UCHAR *, int); - -/* Utility functions for manipulating the structures */ -static void shmcb_get_header(void *, SHMCBHeader **); -static BOOL shmcb_get_division(SHMCBHeader *, SHMCBQueue *, SHMCBCache *, unsigned int); -static SHMCBIndex *shmcb_get_index(const SHMCBQueue *, unsigned int); -static unsigned int shmcb_expire_division(server_rec *, SHMCBQueue *, SHMCBCache *); -static BOOL shmcb_insert_encoded_session(server_rec *, SHMCBQueue *, SHMCBCache *, unsigned char *, unsigned int, unsigned char *, time_t); -static SSL_SESSION *shmcb_lookup_session_id(server_rec *, SHMCBQueue *, SHMCBCache *, UCHAR *, int); -static BOOL shmcb_remove_session_id(server_rec *, SHMCBQueue *, SHMCBCache *, UCHAR *, int); - -/* - * Data-alignment functions (a.k.a. avoidance tactics) - * - * NB: On HPUX (and possibly others) there is a *very* mischievous little - * "optimisation" in the compilers where it will convert the following; - * memcpy(dest_ptr, &source, sizeof(unsigned int)); - * (where dest_ptr is of type (unsigned int *) and source is (unsigned int)) - * into; - * *dest_ptr = source; (or *dest_ptr = *(&source), not sure). - * Either way, it completely destroys the whole point of these _safe_ - * functions, because the assignment operation will fall victim to the - * architecture's byte-alignment dictations, whereas the memcpy (as a - * byte-by-byte copy) should not. sigh. So, if you're wondering about the - * apparently unnecessary conversions to (unsigned char *) in these - * functions, you now have an explanation. Don't just revert them back and - * say "ooh look, it still works" - if you try it on HPUX (well, 32-bit - * HPUX 11.00 at least) you may find it fails with a SIGBUS. :-( - */ - -static unsigned int shmcb_get_safe_uint(unsigned int *ptr) -{ - unsigned char *from; - unsigned int ret; - - from = (unsigned char *)ptr; - memcpy(&ret, from, sizeof(unsigned int)); - return ret; -} - -static void shmcb_set_safe_uint(unsigned int *ptr, unsigned int val) -{ - unsigned char *to, *from; - - to = (unsigned char *)ptr; - from = (unsigned char *)(&val); - memcpy(to, from, sizeof(unsigned int)); -} - -#if 0 /* Unused so far */ -static unsigned long shmcb_get_safe_ulong(unsigned long *ptr) -{ - unsigned char *from; - unsigned long ret; - - from = (unsigned char *)ptr; - memcpy(&ret, from, sizeof(unsigned long)); - return ret; -} - -static void shmcb_set_safe_ulong(unsigned long *ptr, unsigned long val) -{ - unsigned char *to, *from; - - to = (unsigned char *)ptr; - from = (unsigned char *)(&val); - memcpy(to, from, sizeof(unsigned long)); -} -#endif - -static time_t shmcb_get_safe_time(time_t * ptr) -{ - unsigned char *from; - time_t ret; - - from = (unsigned char *)ptr; - memcpy(&ret, from, sizeof(time_t)); - return ret; -} - -static void shmcb_set_safe_time(time_t * ptr, time_t val) -{ - unsigned char *to, *from; - - to = (unsigned char *)ptr; - from = (unsigned char *)(&val); - memcpy(to, from, sizeof(time_t)); -} - -/* -** -** High-Level "handlers" as per ssl_scache.c -** -*/ - -static void *shmcb_malloc(size_t size) -{ - SSLModConfigRec *mc = myModConfig(); - return ap_mm_malloc(mc->pSessionCacheDataMM, size); -} - -void ssl_scache_shmcb_init(server_rec *s, pool *p) -{ - SSLModConfigRec *mc = myModConfig(); - AP_MM *mm; - void *shm_segment = NULL; - int avail, avail_orig; - - /* - * Create shared memory segment - */ - if (mc->szSessionCacheDataFile == NULL) { - ssl_log(s, SSL_LOG_ERROR, "SSLSessionCache required"); - ssl_die(); - } - if ((mm = ap_mm_create(mc->nSessionCacheDataSize, - mc->szSessionCacheDataFile)) == NULL) { - ssl_log(s, SSL_LOG_ERROR, - "Cannot allocate shared memory: %s", ap_mm_error()); - ssl_die(); - } - mc->pSessionCacheDataMM = mm; - - /* - * Make sure the child processes have access to the underlying files - */ - ap_mm_permission(mm, SSL_MM_FILE_MODE, ap_user_id, -1); - - /* - * Create cache inside the shared memory segment - */ - avail = avail_orig = ap_mm_available(mm); - ssl_log(s, SSL_LOG_TRACE, "Shared-memory segment has %u available", - avail); - - /* - * For some reason to do with MM's internal management, I can't - * allocate the full amount. Implement a reasonable form of trial - * and error and output trace information. - */ - while ((shm_segment == NULL) && ((avail_orig - avail) * 100 < avail_orig)) { - shm_segment = shmcb_malloc(avail); - if (shm_segment == NULL) { - ssl_log(s, SSL_LOG_TRACE, - "shmcb_malloc attempt for %u bytes failed", avail); - avail -= 2; - } - } - if (shm_segment == NULL) { - ssl_log(s, SSL_LOG_ERROR, - "Cannot allocate memory for the 'shmcb' session cache\n"); - ssl_die(); - } - ssl_log(s, SSL_LOG_TRACE, "shmcb_init allocated %u bytes of shared " - "memory", avail); - if (!shmcb_init_memory(s, shm_segment, avail)) { - ssl_log(s, SSL_LOG_ERROR, - "Failure initialising 'shmcb' shared memory"); - ssl_die(); - } - ssl_log(s, SSL_LOG_INFO, "Shared memory session cache initialised"); - - /* - * Success ... we hack the memory block into place by cheating for - * now and stealing a member variable the original shared memory - * cache was using. :-) - */ - mc->tSessionCacheDataTable = (table_t *) shm_segment; - return; -} - -void ssl_scache_shmcb_kill(server_rec *s) -{ - SSLModConfigRec *mc = myModConfig(); - - if (mc->pSessionCacheDataMM != NULL) { - ap_mm_destroy(mc->pSessionCacheDataMM); - mc->pSessionCacheDataMM = NULL; - } - return; -} - -BOOL ssl_scache_shmcb_store(server_rec *s, UCHAR * id, int idlen, - time_t timeout, SSL_SESSION * pSession) -{ - SSLModConfigRec *mc = myModConfig(); - void *shm_segment; - BOOL to_return = FALSE; - - /* We've kludged our pointer into the other cache's member variable. */ - shm_segment = (void *) mc->tSessionCacheDataTable; - ssl_mutex_on(s); - if (!shmcb_store_session(s, shm_segment, id, idlen, pSession, timeout)) - /* in this cache engine, "stores" should never fail. */ - ssl_log(s, SSL_LOG_ERROR, "'shmcb' code was unable to store a " - "session in the cache."); - else { - ssl_log(s, SSL_LOG_TRACE, "shmcb_store successful"); - to_return = TRUE; - } - ssl_mutex_off(s); - return to_return; -} - -SSL_SESSION *ssl_scache_shmcb_retrieve(server_rec *s, UCHAR * id, int idlen) -{ - SSLModConfigRec *mc = myModConfig(); - void *shm_segment; - SSL_SESSION *pSession; - - /* We've kludged our pointer into the other cache's member variable. */ - shm_segment = (void *) mc->tSessionCacheDataTable; - ssl_mutex_on(s); - pSession = shmcb_retrieve_session(s, shm_segment, id, idlen); - ssl_mutex_off(s); - if (pSession) - ssl_log(s, SSL_LOG_TRACE, "shmcb_retrieve had a hit"); - else { - ssl_log(s, SSL_LOG_TRACE, "shmcb_retrieve had a miss"); - ssl_log(s, SSL_LOG_INFO, "Client requested a 'session-resume' but " - "we have no such session."); - } - return pSession; -} - -void ssl_scache_shmcb_remove(server_rec *s, UCHAR * id, int idlen) -{ - SSLModConfigRec *mc = myModConfig(); - void *shm_segment; - - /* We've kludged our pointer into the other cache's member variable. */ - shm_segment = (void *) mc->tSessionCacheDataTable; - shmcb_remove_session(s, shm_segment, id, idlen); -} - -void ssl_scache_shmcb_expire(server_rec *s) -{ - /* NOP */ - return; -} - -void ssl_scache_shmcb_status(server_rec *s, pool *p, - void (*func) (char *, void *), void *arg) -{ - SSLModConfigRec *mc = myModConfig(); - SHMCBHeader *header; - SHMCBQueue queue; - SHMCBCache cache; - SHMCBIndex *idx; - void *shm_segment; - unsigned int loop, total, cache_total, non_empty_divisions; - int index_pct, cache_pct; - double expiry_total; - time_t average_expiry, now, max_expiry, min_expiry, idxexpiry; - - ssl_log(s, SSL_LOG_TRACE, "inside ssl_scache_shmcb_status"); - - /* We've kludged our pointer into the other cache's member variable. */ - shm_segment = (void *) mc->tSessionCacheDataTable; - - /* Get the header structure. */ - shmcb_get_header(shm_segment, &header); - total = cache_total = non_empty_divisions = 0; - average_expiry = max_expiry = min_expiry = 0; - expiry_total = 0; - - /* It may seem strange to grab "now" at this point, but in theory - * we should never have a negative threshold but grabbing "now" after - * the loop (which performs expiries) could allow that chance. */ - now = time(NULL); - for (loop = 0; loop <= header->division_mask; loop++) { - if (shmcb_get_division(header, &queue, &cache, loop)) { - shmcb_expire_division(s, &queue, &cache); - total += shmcb_get_safe_uint(queue.pos_count); - cache_total += shmcb_get_safe_uint(cache.pos_count); - if (shmcb_get_safe_uint(queue.pos_count) > 0) { - idx = shmcb_get_index(&queue, - shmcb_get_safe_uint(queue.first_pos)); - non_empty_divisions++; - idxexpiry = shmcb_get_safe_time(&(idx->expires)); - expiry_total += (double) idxexpiry; - max_expiry = (idxexpiry > max_expiry ? idxexpiry : - max_expiry); - if (min_expiry == 0) - min_expiry = idxexpiry; - else - min_expiry = (idxexpiry < min_expiry ? idxexpiry : - min_expiry); - } - } - } - index_pct = (100 * total) / (header->index_num * (header->division_mask + 1)); - cache_pct = (100 * cache_total) / (header->cache_data_size * (header->division_mask + 1)); - func(ap_psprintf(p, "cache type: <b>SHMCB</b>, shared memory: <b>%d</b> " - "bytes, current sessions: <b>%d</b><br>", - mc->nSessionCacheDataSize, total), arg); - func(ap_psprintf(p, "sub-caches: <b>%d</b>, indexes per sub-cache: " - "<b>%d</b><br>", (int) header->division_mask + 1, - (int) header->index_num), arg); - if (non_empty_divisions != 0) { - average_expiry = (time_t)(expiry_total / (double)non_empty_divisions); - func(ap_psprintf(p, "time left on oldest entries' SSL sessions: "), arg); - if (now < average_expiry) - func(ap_psprintf(p, "avg: <b>%d</b> seconds, (range: %d...%d)<br>", - (int)(average_expiry - now), (int) (min_expiry - now), - (int)(max_expiry - now)), arg); - else - func(ap_psprintf(p, "expiry threshold: <b>Calculation Error!</b>" - "<br>"), arg); - - } - func(ap_psprintf(p, "index usage: <b>%d%%</b>, cache usage: <b>%d%%</b>" - "<br>", index_pct, cache_pct), arg); - func(ap_psprintf(p, "total sessions stored since starting: <b>%lu</b><br>", - header->num_stores), arg); - func(ap_psprintf(p, "total sessions expired since starting: <b>%lu</b><br>", - header->num_expiries), arg); - func(ap_psprintf(p, "total (pre-expiry) sessions scrolled out of the " - "cache: <b>%lu</b><br>", header->num_scrolled), arg); - func(ap_psprintf(p, "total retrieves since starting: <b>%lu</b> hit, " - "<b>%lu</b> miss<br>", header->num_retrieves_hit, - header->num_retrieves_miss), arg); - func(ap_psprintf(p, "total removes since starting: <b>%lu</b> hit, " - "<b>%lu</b> miss<br>", header->num_removes_hit, - header->num_removes_miss), arg); - ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_status"); - return; -} - -/* -** -** Memory manipulation and low-level cache operations -** -*/ - -static BOOL shmcb_init_memory( - server_rec *s, void *shm_mem, - unsigned int shm_mem_size) -{ - SHMCBHeader *header; - SHMCBQueue queue; - SHMCBCache cache; - unsigned int temp, loop, granularity; - - ssl_log(s, SSL_LOG_TRACE, "entered shmcb_init_memory()"); - - /* Calculate some sizes... */ - temp = sizeof(SHMCBHeader); - - /* If the segment is ridiculously too small, bail out */ - if (shm_mem_size < (2*temp)) { - ssl_log(s, SSL_LOG_ERROR, "shared memory segment too small"); - return FALSE; - } - - /* Make temp the amount of memory without the header */ - temp = shm_mem_size - temp; - - /* Work on the basis that you need 10 bytes index for each session - * (approx 150 bytes), which is to divide temp by 160 - and then - * make sure we err on having too index space to burn even when - * the cache is full, which is a lot less stupid than having - * having not enough index space to utilise the whole cache!. */ - temp /= 120; - ssl_log(s, SSL_LOG_TRACE, "for %u bytes, recommending %u indexes", - shm_mem_size, temp); - - /* We should divide these indexes evenly amongst the queues. Try - * to get it so that there are roughly half the number of divisions - * as there are indexes in each division. */ - granularity = 256; - while ((temp / granularity) < (2 * granularity)) - granularity /= 2; - - /* So we have 'granularity' divisions, set 'temp' equal to the - * number of indexes in each division. */ - temp /= granularity; - - /* Too small? Bail ... */ - if (temp < 5) { - ssl_log(s, SSL_LOG_ERROR, "shared memory segment too small"); - return FALSE; - } - - /* OK, we're sorted - from here on in, the return should be TRUE */ - header = (SHMCBHeader *)shm_mem; - header->division_mask = (unsigned char)(granularity - 1); - header->division_offset = sizeof(SHMCBHeader); - header->index_num = temp; - header->index_offset = (2 * sizeof(unsigned int)); - header->index_size = sizeof(SHMCBIndex); - header->queue_size = header->index_offset + - (header->index_num * header->index_size); - - /* Now calculate the space for each division */ - temp = shm_mem_size - header->division_offset; - header->division_size = temp / granularity; - - /* Calculate the space left in each division for the cache */ - temp -= header->queue_size; - header->cache_data_offset = (2 * sizeof(unsigned int)); - header->cache_data_size = header->division_size - - header->queue_size - header->cache_data_offset; - - /* Output trace info */ - ssl_log(s, SSL_LOG_TRACE, "shmcb_init_memory choices follow"); - ssl_log(s, SSL_LOG_TRACE, "division_mask = 0x%02X", header->division_mask); - ssl_log(s, SSL_LOG_TRACE, "division_offset = %u", header->division_offset); - ssl_log(s, SSL_LOG_TRACE, "division_size = %u", header->division_size); - ssl_log(s, SSL_LOG_TRACE, "queue_size = %u", header->queue_size); - ssl_log(s, SSL_LOG_TRACE, "index_num = %u", header->index_num); - ssl_log(s, SSL_LOG_TRACE, "index_offset = %u", header->index_offset); - ssl_log(s, SSL_LOG_TRACE, "index_size = %u", header->index_size); - ssl_log(s, SSL_LOG_TRACE, "cache_data_offset = %u", header->cache_data_offset); - ssl_log(s, SSL_LOG_TRACE, "cache_data_size = %u", header->cache_data_size); - - /* The header is done, make the caches empty */ - for (loop = 0; loop < granularity; loop++) { - if (!shmcb_get_division(header, &queue, &cache, loop)) - ssl_log(s, SSL_LOG_ERROR, "shmcb_init_memory, " "internal error"); - shmcb_set_safe_uint(cache.first_pos, 0); - shmcb_set_safe_uint(cache.pos_count, 0); - shmcb_set_safe_uint(queue.first_pos, 0); - shmcb_set_safe_uint(queue.pos_count, 0); - } - - ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_init_memory()"); - return TRUE; -} - -static BOOL shmcb_store_session( - server_rec *s, void *shm_segment, UCHAR * id, - int idlen, SSL_SESSION * pSession, - time_t timeout) -{ - SHMCBHeader *header; - SHMCBQueue queue; - SHMCBCache cache; - unsigned char masked_index; - unsigned char encoded[SSL_SESSION_MAX_DER]; - unsigned char *ptr_encoded; - unsigned int len_encoded; - time_t expiry_time; - - ssl_log(s, SSL_LOG_TRACE, "inside shmcb_store_session"); - - /* Get the header structure, which division this session will fall into etc. */ - shmcb_get_header(shm_segment, &header); - masked_index = pSession->session_id[0] & header->division_mask; - ssl_log(s, SSL_LOG_TRACE, "session_id[0]=%u, masked index=%u", - pSession->session_id[0], masked_index); - if (!shmcb_get_division(header, &queue, &cache, (unsigned int)masked_index)) { - ssl_log(s, SSL_LOG_ERROR, "shmcb_store_session, " "internal error"); - return FALSE; - } - - /* Serialise the session, work out how much we're dealing - * with. NB: This check could be removed if we're not paranoid - * or we find some assurance that it will never be necessary. */ - len_encoded = i2d_SSL_SESSION(pSession, NULL); - if (len_encoded > SSL_SESSION_MAX_DER) { - ssl_log(s, SSL_LOG_ERROR, "session is too big (%u bytes)", - len_encoded); - return FALSE; - } - ptr_encoded = encoded; - len_encoded = i2d_SSL_SESSION(pSession, &ptr_encoded); - expiry_time = timeout; - if (!shmcb_insert_encoded_session(s, &queue, &cache, encoded, - len_encoded, pSession->session_id, - expiry_time)) { - ssl_log(s, SSL_LOG_ERROR, "can't store a session!"); - return FALSE; - } - ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_store successfully"); - header->num_stores++; - return TRUE; -} - -static SSL_SESSION *shmcb_retrieve_session( - server_rec *s, void *shm_segment, - UCHAR * id, int idlen) -{ - SHMCBHeader *header; - SHMCBQueue queue; - SHMCBCache cache; - unsigned char masked_index; - SSL_SESSION *pSession; - - ssl_log(s, SSL_LOG_TRACE, "inside shmcb_retrieve_session"); - if (idlen < 2) { - ssl_log(s, SSL_LOG_ERROR, "unusably short session_id provided " - "(%u bytes)", idlen); - return FALSE; - } - - /* Get the header structure, which division this session lookup - * will come from etc. */ - shmcb_get_header(shm_segment, &header); - masked_index = id[0] & header->division_mask; - ssl_log(s, SSL_LOG_TRACE, "id[0]=%u, masked index=%u", id[0], - masked_index); - if (!shmcb_get_division(header, &queue, &cache, (unsigned int) masked_index)) { - ssl_log(s, SSL_LOG_ERROR, "shmcb_retrieve_session, " "internal error"); - header->num_retrieves_miss++; - return FALSE; - } - - /* Get the session corresponding to the session_id or NULL if it - * doesn't exist (or is flagged as "removed"). */ - pSession = shmcb_lookup_session_id(s, &queue, &cache, id, idlen); - if (pSession) - header->num_retrieves_hit++; - else - header->num_retrieves_miss++; - ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_retrieve_session"); - return pSession; -} - -static BOOL shmcb_remove_session( - server_rec *s, void *shm_segment, - UCHAR * id, int idlen) -{ - SHMCBHeader *header; - SHMCBQueue queue; - SHMCBCache cache; - unsigned char masked_index; - BOOL res; - - ssl_log(s, SSL_LOG_TRACE, "inside shmcb_remove_session"); - if (id == NULL) { - ssl_log(s, SSL_LOG_ERROR, "remove called with NULL session_id!"); - return FALSE; - } - - /* Get the header structure, which division this session remove - * will happen in etc. */ - shmcb_get_header(shm_segment, &header); - masked_index = id[0] & header->division_mask; - ssl_log(s, SSL_LOG_TRACE, "id[0]=%u, masked index=%u", - id[0], masked_index); - if (!shmcb_get_division(header, &queue, &cache, (unsigned int)masked_index)) { - ssl_log(s, SSL_LOG_ERROR, "shmcb_remove_session, internal error"); - header->num_removes_miss++; - return FALSE; - } - res = shmcb_remove_session_id(s, &queue, &cache, id, idlen); - if (res) - header->num_removes_hit++; - else - header->num_removes_miss++; - ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_remove_session"); - return res; -} - - -/* -** -** Weirdo cyclic buffer functions -** -*/ - -/* This gets used in the cyclic "index array" (in the 'Queue's) and - * in the cyclic 'Cache's too ... you provide the "width" of the - * cyclic store, the starting position and how far to move (with - * wrapping if necessary). Basically it's addition modulo buf_size. */ -static unsigned int shmcb_cyclic_increment( - unsigned int buf_size, - unsigned int start_pos, - unsigned int to_add) -{ - start_pos += to_add; - while (start_pos >= buf_size) - start_pos -= buf_size; - return start_pos; -} - -/* Given two positions in a cyclic buffer, calculate the "distance". - * This is to cover the case ("non-trivial") where the 'next' offset - * is to the left of the 'start' offset. NB: This calculates the - * space inclusive of one end-point but not the other. There is an - * ambiguous case (which is why we use the <start_pos,offset> - * coordinate system rather than <start_pos,end_pos> one) when 'start' - * is the same as 'next'. It could indicate the buffer is full or it - * can indicate the buffer is empty ... I choose the latter as it's - * easier and usually necessary to check if the buffer is full anyway - * before doing incremental logic (which is this useful for), but we - * definitely need the empty case handled - in fact it's our starting - * state!! */ -static unsigned int shmcb_cyclic_space( - unsigned int buf_size, - unsigned int start_offset, - unsigned int next_offset) -{ - /* Is it the trivial case? */ - if (start_offset <= next_offset) - return (next_offset - start_offset); /* yes */ - else - return ((buf_size - start_offset) + next_offset); /* no */ -} - -/* A "normal-to-cyclic" memcpy ... this takes a linear block of - * memory and copies it onto a cyclic buffer. The purpose and - * function of this is pretty obvious, you need to cover the case - * that the destination (cyclic) buffer has to wrap round. */ -static void shmcb_cyclic_ntoc_memcpy( - unsigned int buf_size, - unsigned char *data, - unsigned int dest_offset, - unsigned char *src, unsigned int src_len) -{ - /* Can it be copied all in one go? */ - if (dest_offset + src_len < buf_size) - /* yes */ - memcpy(data + dest_offset, src, src_len); - else { - /* no */ - memcpy(data + dest_offset, src, buf_size - dest_offset); - memcpy(data, src + buf_size - dest_offset, - src_len + dest_offset - buf_size); - } - return; -} - -/* A "cyclic-to-normal" memcpy ... given the last function, this - * one's purpose is clear, it copies out of a cyclic buffer handling - * wrapping. */ -static void shmcb_cyclic_cton_memcpy( - unsigned int buf_size, - unsigned char *dest, - unsigned char *data, - unsigned int src_offset, - unsigned int src_len) -{ - /* Can it be copied all in one go? */ - if (src_offset + src_len < buf_size) - /* yes */ - memcpy(dest, data + src_offset, src_len); - else { - /* no */ - memcpy(dest, data + src_offset, buf_size - src_offset); - memcpy(dest + buf_size - src_offset, data, - src_len + src_offset - buf_size); - } - return; -} - -/* Here's the cool hack that makes it all work ... by simply - * making the first collection of bytes *be* our header structure - * (casting it into the C structure), we have the perfect way to - * maintain state in a shared-memory session cache from one call - * (and process) to the next, use the shared memory itself! The - * original mod_ssl shared-memory session cache uses variables - * inside the context, but we simply use that for storing the - * pointer to the shared memory itself. And don't forget, after - * Apache's initialisation, this "header" is constant/read-only - * so we can read it outside any locking. - * <grin> - sometimes I just *love* coding y'know?! */ -static void shmcb_get_header(void *shm_mem, SHMCBHeader **header) -{ - *header = (SHMCBHeader *)shm_mem; - return; -} - -/* This is what populates our "interesting" structures. Given a - * pointer to the header, and an index into the appropriate - * division (this must have already been masked using the - * division_mask by the caller!), we can populate the provided - * SHMCBQueue and SHMCBCache structures with values and - * pointers to the underlying shared memory. Upon returning - * (if not FALSE), the caller can meddle with the pointer - * values and they will map into the shared-memory directly, - * as such there's no need to "free" or "set" the Queue or - * Cache values, they were themselves references to the *real* - * data. */ -static BOOL shmcb_get_division( - SHMCBHeader *header, SHMCBQueue *queue, - SHMCBCache *cache, unsigned int idx) -{ - unsigned char *pQueue; - unsigned char *pCache; - - /* bounds check */ - if (idx > (unsigned int) header->division_mask) - return FALSE; - - /* Locate the blocks of memory storing the corresponding data */ - pQueue = ((unsigned char *) header) + header->division_offset + - (idx * header->division_size); - pCache = pQueue + header->queue_size; - - /* Populate the structures with appropriate pointers */ - queue->first_pos = (unsigned int *) pQueue; - - /* Our structures stay packed, no matter what the system's - * data-alignment regime is. */ - queue->pos_count = (unsigned int *) (pQueue + sizeof(unsigned int)); - queue->indexes = (SHMCBIndex *) (pQueue + (2 * sizeof(unsigned int))); - cache->first_pos = (unsigned int *) pCache; - cache->pos_count = (unsigned int *) (pCache + sizeof(unsigned int)); - cache->data = (unsigned char *) (pCache + (2 * sizeof(unsigned int))); - queue->header = cache->header = header; - - return TRUE; -} - -/* This returns a pointer to the piece of shared memory containing - * a specified 'Index'. SHMCBIndex, like SHMCBHeader, is a fixed - * width non-referencing structure of primitive types that can be - * cast onto the corresponding block of shared memory. Thus, by - * returning a cast pointer to that section of shared memory, the - * caller can read and write values to and from the "structure" and - * they are actually reading and writing the underlying shared - * memory. */ -static SHMCBIndex *shmcb_get_index( - const SHMCBQueue *queue, unsigned int idx) -{ - /* bounds check */ - if (idx > (unsigned int) queue->header->index_num) - return NULL; - - /* Return a pointer to the index. NB: I am being horribly pendantic - * here so as to avoid any potential data-alignment assumptions being - * placed on the pointer arithmetic by the compiler (sigh). */ - return (SHMCBIndex *)(((unsigned char *) queue->indexes) + - (idx * sizeof(SHMCBIndex))); -} - -/* This functions rolls expired cache (and index) entries off the front - * of the cyclic buffers in a division. The function returns the number - * of expired sessions. */ -static unsigned int shmcb_expire_division( - server_rec *s, SHMCBQueue *queue, SHMCBCache *cache) -{ - SHMCBIndex *idx; - time_t now; - unsigned int loop, index_num, pos_count, new_pos; - SHMCBHeader *header; - - ssl_log(s, SSL_LOG_TRACE, "entering shmcb_expire_division"); - - /* We must calculate num and space ourselves based on expiry times. */ - now = time(NULL); - loop = 0; - new_pos = shmcb_get_safe_uint(queue->first_pos); - - /* Cache useful values */ - header = queue->header; - index_num = header->index_num; - pos_count = shmcb_get_safe_uint(queue->pos_count); - while (loop < pos_count) { - idx = shmcb_get_index(queue, new_pos); - if (shmcb_get_safe_time(&(idx->expires)) > now) - /* it hasn't expired yet, we're done iterating */ - break; - /* This one should be expired too. Shift to the next entry. */ - loop++; - new_pos = shmcb_cyclic_increment(index_num, new_pos, 1); - } - - /* Find the new_offset and make the expiries happen. */ - if (loop > 0) { - ssl_log(s, SSL_LOG_TRACE, "will be expiring %u sessions", loop); - /* We calculate the new_offset by "peeking" (or in the - * case it's the last entry, "sneaking" ;-). */ - if (loop == pos_count) { - /* We are expiring everything! This is easy to do... */ - shmcb_set_safe_uint(queue->pos_count, 0); - shmcb_set_safe_uint(cache->pos_count, 0); - } - else { - /* The Queue is easy to adjust */ - shmcb_set_safe_uint(queue->pos_count, - shmcb_get_safe_uint(queue->pos_count) - loop); - shmcb_set_safe_uint(queue->first_pos, new_pos); - /* peek to the start of the next session */ - idx = shmcb_get_index(queue, new_pos); - /* We can use shmcb_cyclic_space because we've guaranteed - * we don't fit the ambiguous full/empty case. */ - shmcb_set_safe_uint(cache->pos_count, - shmcb_get_safe_uint(cache->pos_count) - - shmcb_cyclic_space(header->cache_data_size, - shmcb_get_safe_uint(cache->first_pos), - shmcb_get_safe_uint(&(idx->offset)))); - shmcb_set_safe_uint(cache->first_pos, shmcb_get_safe_uint(&(idx->offset))); - } - ssl_log(s, SSL_LOG_TRACE, "we now have %u sessions", - shmcb_get_safe_uint(queue->pos_count)); - } - header->num_expiries += loop; - return loop; -} - -/* Inserts a new encoded session into a queue/cache pair - expiring - * (early or otherwise) any leading sessions as necessary to ensure - * there is room. An error return (FALSE) should only happen in the - * event of surreal values being passed on, or ridiculously small - * cache sizes. NB: For tracing purposes, this function is also given - * the server_rec to allow "ssl_log()". */ -static BOOL shmcb_insert_encoded_session( - server_rec *s, SHMCBQueue * queue, - SHMCBCache * cache, - unsigned char *encoded, - unsigned int encoded_len, - unsigned char *session_id, - time_t expiry_time) -{ - SHMCBHeader *header; - SHMCBIndex *idx = NULL; - unsigned int gap, new_pos, loop, new_offset; - int need; - - ssl_log(s, SSL_LOG_TRACE, "entering shmcb_insert_encoded_session, " - "*queue->pos_count = %u", shmcb_get_safe_uint(queue->pos_count)); - - /* If there's entries to expire, ditch them first thing. */ - shmcb_expire_division(s, queue, cache); - header = cache->header; - gap = header->cache_data_size - shmcb_get_safe_uint(cache->pos_count); - if (gap < encoded_len) { - new_pos = shmcb_get_safe_uint(queue->first_pos); - loop = 0; - need = (int) encoded_len - (int) gap; - while ((need > 0) && (loop + 1 < shmcb_get_safe_uint(queue->pos_count))) { - new_pos = shmcb_cyclic_increment(header->index_num, new_pos, 1); - loop += 1; - idx = shmcb_get_index(queue, new_pos); - need = (int) encoded_len - (int) gap - - shmcb_cyclic_space(header->cache_data_size, - shmcb_get_safe_uint(cache->first_pos), - shmcb_get_safe_uint(&(idx->offset))); - } - if (loop > 0) { - ssl_log(s, SSL_LOG_TRACE, "about to scroll %u sessions from %u", - loop, shmcb_get_safe_uint(queue->pos_count)); - /* We are removing "loop" items from the cache. */ - shmcb_set_safe_uint(cache->pos_count, - shmcb_get_safe_uint(cache->pos_count) - - shmcb_cyclic_space(header->cache_data_size, - shmcb_get_safe_uint(cache->first_pos), - shmcb_get_safe_uint(&(idx->offset)))); - shmcb_set_safe_uint(cache->first_pos, shmcb_get_safe_uint(&(idx->offset))); - shmcb_set_safe_uint(queue->pos_count, shmcb_get_safe_uint(queue->pos_count) - loop); - shmcb_set_safe_uint(queue->first_pos, new_pos); - ssl_log(s, SSL_LOG_TRACE, "now only have %u sessions", - shmcb_get_safe_uint(queue->pos_count)); - /* Update the stats!!! */ - header->num_scrolled += loop; - } - } - - /* probably unecessary checks, but I'll leave them until this code - * is verified. */ - if (shmcb_get_safe_uint(cache->pos_count) + encoded_len > - header->cache_data_size) { - ssl_log(s, SSL_LOG_ERROR, "shmcb_insert_encoded_session, " - "internal error"); - return FALSE; - } - if (shmcb_get_safe_uint(queue->pos_count) == header->index_num) { - ssl_log(s, SSL_LOG_ERROR, "shmcb_insert_encoded_session, " - "internal error"); - return FALSE; - } - ssl_log(s, SSL_LOG_TRACE, "we have %u bytes and %u indexes free - " - "enough", header->cache_data_size - - shmcb_get_safe_uint(cache->pos_count), header->index_num - - shmcb_get_safe_uint(queue->pos_count)); - - - /* HERE WE ASSUME THAT THE NEW SESSION SHOULD GO ON THE END! I'M NOT - * CHECKING WHETHER IT SHOULD BE GENUINELY "INSERTED" SOMEWHERE. - * - * We either fix that, or find out at a "higher" (read "mod_ssl") - * level whether it is possible to have distinct session caches for - * any attempted tomfoolery to do with different session timeouts. - * Knowing in advance that we can have a cache-wide constant timeout - * would make this stuff *MUCH* more efficient. Mind you, it's very - * efficient right now because I'm ignoring this problem!!! - */ - - /* Increment to the first unused byte */ - new_offset = shmcb_cyclic_increment(header->cache_data_size, - shmcb_get_safe_uint(cache->first_pos), - shmcb_get_safe_uint(cache->pos_count)); - /* Copy the DER-encoded session into place */ - shmcb_cyclic_ntoc_memcpy(header->cache_data_size, cache->data, - new_offset, encoded, encoded_len); - /* Get the new index that this session is stored in. */ - new_pos = shmcb_cyclic_increment(header->index_num, - shmcb_get_safe_uint(queue->first_pos), - shmcb_get_safe_uint(queue->pos_count)); - ssl_log(s, SSL_LOG_TRACE, "storing in index %u, at offset %u", new_pos, - new_offset); - idx = shmcb_get_index(queue, new_pos); - if (idx == NULL) { - ssl_log(s, SSL_LOG_ERROR, "shmcb_insert_encoded_session, " - "internal error"); - return FALSE; - } - memset(idx, 0, sizeof(SHMCBIndex)); - shmcb_set_safe_time(&(idx->expires), expiry_time); - shmcb_set_safe_uint(&(idx->offset), new_offset); - - /* idx->removed = (unsigned char)0; */ /* Not needed given the memset above. */ - idx->s_id2 = session_id[1]; - ssl_log(s, SSL_LOG_TRACE, "session_id[0]=%u, idx->s_id2=%u", - session_id[0], session_id[1]); - - /* All that remains is to adjust the cache's and queue's "pos_count"s. */ - shmcb_set_safe_uint(cache->pos_count, - shmcb_get_safe_uint(cache->pos_count) + encoded_len); - shmcb_set_safe_uint(queue->pos_count, - shmcb_get_safe_uint(queue->pos_count) + 1); - - /* And just for good debugging measure ... */ - ssl_log(s, SSL_LOG_TRACE, "leaving now with %u bytes in the cache and " - "%u indexes", shmcb_get_safe_uint(cache->pos_count), - shmcb_get_safe_uint(queue->pos_count)); - ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_insert_encoded_session"); - return TRUE; -} - -/* Performs a lookup into a queue/cache pair for a - * session_id. If found, the session is deserialised - * and returned, otherwise NULL. */ -static SSL_SESSION *shmcb_lookup_session_id( - server_rec *s, SHMCBQueue *queue, - SHMCBCache *cache, UCHAR *id, - int idlen) -{ - unsigned char tempasn[SSL_SESSION_MAX_DER]; - SHMCBIndex *idx; - SHMCBHeader *header; - SSL_SESSION *pSession = NULL; - unsigned int curr_pos, loop, count; - unsigned char *ptr; - time_t now; - - ssl_log(s, SSL_LOG_TRACE, "entering shmcb_lookup_session_id"); - - /* If there are entries to expire, ditch them first thing. */ - shmcb_expire_division(s, queue, cache); - now = time(NULL); - curr_pos = shmcb_get_safe_uint(queue->first_pos); - count = shmcb_get_safe_uint(queue->pos_count); - header = queue->header; - for (loop = 0; loop < count; loop++) { - ssl_log(s, SSL_LOG_TRACE, "loop=%u, count=%u, curr_pos=%u", - loop, count, curr_pos); - idx = shmcb_get_index(queue, curr_pos); - ssl_log(s, SSL_LOG_TRACE, "idx->s_id2=%u, id[1]=%u, offset=%u", - idx->s_id2, id[1], shmcb_get_safe_uint(&(idx->offset))); - /* Only look into the session further if; - * (a) the second byte of the session_id matches, - * (b) the "removed" flag isn't set, - * (c) the session hasn't expired yet. - * We do (c) like this so that it saves us having to - * do natural expiries ... naturally expired sessions - * scroll off the front anyway when the cache is full and - * "rotating", the only real issue that remains is the - * removal or disabling of forcibly killed sessions. */ - if ((idx->s_id2 == id[1]) && !idx->removed && - (shmcb_get_safe_time(&(idx->expires)) > now)) { - ssl_log(s, SSL_LOG_TRACE, "at index %u, found possible " - "session match", curr_pos); - shmcb_cyclic_cton_memcpy(header->cache_data_size, - tempasn, cache->data, - shmcb_get_safe_uint(&(idx->offset)), - SSL_SESSION_MAX_DER); - ptr = tempasn; - pSession = d2i_SSL_SESSION(NULL, &ptr, SSL_SESSION_MAX_DER); - if (pSession == NULL) { - ssl_log(s, SSL_LOG_ERROR, "scach2_lookup_" - "session_id, internal error"); - return NULL; - } - if ((pSession->session_id_length == idlen) && - (memcmp(pSession->session_id, id, idlen) == 0)) { - ssl_log(s, SSL_LOG_TRACE, "a match!"); - return pSession; - } - ssl_log(s, SSL_LOG_TRACE, "not a match"); - SSL_SESSION_free(pSession); - pSession = NULL; - } - curr_pos = shmcb_cyclic_increment(header->index_num, curr_pos, 1); - } - ssl_log(s, SSL_LOG_TRACE, "no matching sessions were found"); - return NULL; -} - -static BOOL shmcb_remove_session_id( - server_rec *s, SHMCBQueue *queue, - SHMCBCache *cache, UCHAR *id, int idlen) -{ - unsigned char tempasn[SSL_SESSION_MAX_DER]; - SSL_SESSION *pSession = NULL; - SHMCBIndex *idx; - SHMCBHeader *header; - unsigned int curr_pos, loop, count; - unsigned char *ptr; - BOOL to_return = FALSE; - - ssl_log(s, SSL_LOG_TRACE, "entering shmcb_remove_session_id"); - - /* If there's entries to expire, ditch them first thing. */ - /* shmcb_expire_division(s, queue, cache); */ - - /* Regarding the above ... hmmm ... I know my expiry code is slightly - * "faster" than all this remove stuff ... but if the higher level - * code calls a "remove" operation (and this *only* seems to happen - * when it has spotted an expired session before we had a chance to) - * then it should get credit for a remove (stats-wise). Also, in the - * off-chance that the server *requests* a renegotiate and wants to - * wipe the session clean we should give that priority over our own - * routine expiry handling. So I've moved the expiry check to *after* - * this general remove stuff. */ - curr_pos = shmcb_get_safe_uint(queue->first_pos); - count = shmcb_get_safe_uint(queue->pos_count); - header = cache->header; - for (loop = 0; loop < count; loop++) { - ssl_log(s, SSL_LOG_TRACE, "loop=%u, count=%u, curr_pos=%u", - loop, count, curr_pos); - idx = shmcb_get_index(queue, curr_pos); - ssl_log(s, SSL_LOG_TRACE, "idx->s_id2=%u, id[1]=%u", idx->s_id2, - id[1]); - /* Only look into the session further if the second byte of the - * session_id matches. */ - if (idx->s_id2 == id[1]) { - ssl_log(s, SSL_LOG_TRACE, "at index %u, found possible " - "session match", curr_pos); - shmcb_cyclic_cton_memcpy(header->cache_data_size, - tempasn, cache->data, - shmcb_get_safe_uint(&(idx->offset)), - SSL_SESSION_MAX_DER); - ptr = tempasn; - pSession = d2i_SSL_SESSION(NULL, &ptr, SSL_SESSION_MAX_DER); - if (pSession == NULL) { - ssl_log(s, SSL_LOG_ERROR, "shmcb_remove_session_id, " - "internal error"); - goto end; - } - if ((pSession->session_id_length == idlen) - && (memcmp(id, pSession->session_id, idlen) == 0)) { - ssl_log(s, SSL_LOG_TRACE, "a match!"); - /* Scrub out this session "quietly" */ - idx->removed = (unsigned char) 1; - SSL_SESSION_free(pSession); - to_return = TRUE; - goto end; - } - ssl_log(s, SSL_LOG_TRACE, "not a match"); - SSL_SESSION_free(pSession); - pSession = NULL; - } - curr_pos = shmcb_cyclic_increment(header->index_num, curr_pos, 1); - } - ssl_log(s, SSL_LOG_TRACE, "no matching sessions were found"); - - /* If there's entries to expire, ditch them now. */ - shmcb_expire_division(s, queue, cache); -end: - ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_remove_session_id"); - return to_return; -} - diff --git a/modules/ssl/ssl_util.c b/modules/ssl/ssl_util.c deleted file mode 100644 index af4a9672f2..0000000000 --- a/modules/ssl/ssl_util.c +++ /dev/null @@ -1,437 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_util.c -** Utility Functions -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - -/* ==================================================================== - * Copyright (c) 1995-1999 Ben Laurie. 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 Ben Laurie - * for use in the Apache-SSL HTTP server project." - * - * 4. The name "Apache-SSL Server" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Ben Laurie - * for use in the Apache-SSL HTTP server project." - * - * THIS SOFTWARE IS PROVIDED BY BEN LAURIE ``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 BEN LAURIE OR - * HIS 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. - * ==================================================================== - */ - /* ``Every day of my life - I am forced to add another - name to the list of people - who piss me off!'' - -- Calvin */ -#include "mod_ssl.h" - - -/* _________________________________________________________________ -** -** Utility Functions -** _________________________________________________________________ -*/ - -char *ssl_util_server_root_relative(pool *p, char *what, char *arg) -{ - char *rv = NULL; - -#ifdef SSL_VENDOR - ap_hook_use("ap::mod_ssl::vendor::ssl_server_root_relative", - AP_HOOK_SIG4(ptr,ptr,ptr,ptr), AP_HOOK_ALL, &rv, p, what, arg); - if (rv != NULL) - return rv; -#endif - rv = ap_server_root_relative(p, arg); - return rv; -} - -char *ssl_util_vhostid(pool *p, server_rec *s) -{ - char *id; - SSLSrvConfigRec *sc; - char *host; - unsigned int port; - - host = s->server_hostname; - if (s->port != 0) - port = s->port; - else { - sc = mySrvConfig(s); - if (sc->bEnabled) - port = DEFAULT_HTTPS_PORT; - else - port = DEFAULT_HTTP_PORT; - } - id = ap_psprintf(p, "%s:%u", host, port); - return id; -} - -void ssl_util_strupper(char *s) -{ - for (; *s; ++s) - *s = toupper(*s); - return; -} - -static const char ssl_util_uuencode_six2pr[64+1] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -void ssl_util_uuencode(char *szTo, const char *szFrom, BOOL bPad) -{ - ssl_util_uuencode_binary((unsigned char *)szTo, - (const unsigned char *)szFrom, - strlen(szFrom), bPad); -} - -void ssl_util_uuencode_binary( - unsigned char *szTo, const unsigned char *szFrom, int nLength, BOOL bPad) -{ - const unsigned char *s; - int nPad = 0; - - for (s = szFrom; nLength > 0; s += 3) { - *szTo++ = ssl_util_uuencode_six2pr[s[0] >> 2]; - *szTo++ = ssl_util_uuencode_six2pr[(s[0] << 4 | s[1] >> 4) & 0x3f]; - if (--nLength == 0) { - nPad = 2; - break; - } - *szTo++ = ssl_util_uuencode_six2pr[(s[1] << 2 | s[2] >> 6) & 0x3f]; - if (--nLength == 0) { - nPad = 1; - break; - } - *szTo++ = ssl_util_uuencode_six2pr[s[2] & 0x3f]; - --nLength; - } - while(bPad && nPad--) - *szTo++ = NUL; - *szTo = NUL; - return; -} - -FILE *ssl_util_ppopen(server_rec *s, pool *p, char *cmd) -{ - FILE *fpout; - int rc; - - fpout = NULL; - rc = ap_spawn_child(p, ssl_util_ppopen_child, - (void *)cmd, kill_after_timeout, - NULL, &fpout, NULL); - if (rc == 0 || fpout == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, s, - "ssl_util_ppopen: could not run: %s", cmd); - return NULL; - } - return (fpout); -} - -int ssl_util_ppopen_child(void *cmd, child_info *pinfo) -{ - int child_pid = 1; - - /* - * Prepare for exec - */ - ap_cleanup_for_exec(); -#ifdef SIGHUP - signal(SIGHUP, SIG_IGN); -#endif - - /* - * Exec() the child program - */ -#if defined(WIN32) - /* MS Windows */ - { - char pCommand[MAX_STRING_LEN]; - STARTUPINFO si; - PROCESS_INFORMATION pi; - - ap_snprintf(pCommand, sizeof(pCommand), "%s /C %s", SHELL_PATH, cmd); - - memset(&si, 0, sizeof(si)); - memset(&pi, 0, sizeof(pi)); - - si.cb = sizeof(si); - si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; - si.wShowWindow = SW_HIDE; - si.hStdInput = pinfo->hPipeInputRead; - si.hStdOutput = pinfo->hPipeOutputWrite; - si.hStdError = pinfo->hPipeErrorWrite; - - if (CreateProcess(NULL, pCommand, NULL, NULL, TRUE, 0, - environ, NULL, &si, &pi)) { - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - child_pid = pi.dwProcessId; - } - } -#elif defined(OS2) - /* IBM OS/2 */ - spawnl(P_NOWAIT, SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); -#else - /* Standard Unix */ - execl(SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); -#endif - return (child_pid); -} - -void ssl_util_ppclose(server_rec *s, pool *p, FILE *fp) -{ - ap_pfclose(p, fp); - return; -} - -/* - * Run a filter program and read the first line of its stdout output - */ -char *ssl_util_readfilter(server_rec *s, pool *p, char *cmd) -{ - static char buf[MAX_STRING_LEN]; - FILE *fp; - char c; - int k; - - if ((fp = ssl_util_ppopen(s, p, cmd)) == NULL) - return NULL; - for (k = 0; read(fileno(fp), &c, 1) == 1 - && (k < MAX_STRING_LEN-1) ; ) { - if (c == '\n' || c == '\r') - break; - buf[k++] = c; - } - buf[k] = NUL; - ssl_util_ppclose(s, p, fp); - - return buf; -} - -BOOL ssl_util_path_check(ssl_pathcheck_t pcm, char *path) -{ - struct stat sb; - - if (path == NULL) - return FALSE; - if (pcm & SSL_PCM_EXISTS && stat(path, &sb) != 0) - return FALSE; - if (pcm & SSL_PCM_ISREG && !S_ISREG(sb.st_mode)) - return FALSE; - if (pcm & SSL_PCM_ISDIR && !S_ISDIR(sb.st_mode)) - return FALSE; - if (pcm & SSL_PCM_ISNONZERO && sb.st_mode <= 0) - return FALSE; - return TRUE; -} - -ssl_algo_t ssl_util_algotypeof(X509 *pCert, EVP_PKEY *pKey) -{ - ssl_algo_t t; - - t = SSL_ALGO_UNKNOWN; - if (pCert != NULL) - pKey = X509_get_pubkey(pCert); - if (pKey != NULL) { - switch (EVP_PKEY_type(pKey->type)) { - case EVP_PKEY_RSA: - t = SSL_ALGO_RSA; - break; - case EVP_PKEY_DSA: - t = SSL_ALGO_DSA; - break; - default: - break; - } - } - return t; -} - -char *ssl_util_algotypestr(ssl_algo_t t) -{ - char *cp; - - cp = "UNKNOWN"; - switch (t) { - case SSL_ALGO_RSA: - cp = "RSA"; - break; - case SSL_ALGO_DSA: - cp = "DSA"; - break; - default: - break; - } - return cp; -} - -char *ssl_util_ptxtsub( - pool *p, const char *cpLine, const char *cpMatch, char *cpSubst) -{ -#define MAX_PTXTSUB 100 - char *cppMatch[MAX_PTXTSUB]; - char *cpResult; - int nResult; - int nLine; - int nSubst; - int nMatch; - char *cpI; - char *cpO; - char *cp; - int i; - - /* - * Pass 1: find substitution locations and calculate sizes - */ - nLine = strlen(cpLine); - nMatch = strlen(cpMatch); - nSubst = strlen(cpSubst); - for (cpI = (char *)cpLine, i = 0, nResult = 0; - cpI < cpLine+nLine && i < MAX_PTXTSUB; ) { - if ((cp = strstr(cpI, cpMatch)) != NULL) { - cppMatch[i++] = cp; - nResult += ((cp-cpI)+nSubst); - cpI = (cp+nMatch); - } - else { - nResult += strlen(cpI); - break; - } - } - cppMatch[i] = NULL; - if (i == 0) - return NULL; - - /* - * Pass 2: allocate memory and assemble result - */ - cpResult = ap_pcalloc(p, nResult+1); - for (cpI = (char *)cpLine, cpO = cpResult, i = 0; cppMatch[i] != NULL; i++) { - ap_cpystrn(cpO, cpI, cppMatch[i]-cpI+1); - cpO += (cppMatch[i]-cpI); - ap_cpystrn(cpO, cpSubst, nSubst+1); - cpO += nSubst; - cpI = (cppMatch[i]+nMatch); - } - ap_cpystrn(cpO, cpI, cpResult+nResult-cpO+1); - - return cpResult; -} - -/* _________________________________________________________________ -** -** Special Functions for Win32/OpenSSL -** _________________________________________________________________ -*/ - -#ifdef WIN32 -static HANDLE lock_cs[CRYPTO_NUM_LOCKS]; - -static void win32_locking_callback(int mode, int type, char* file, int line) -{ - if (mode & CRYPTO_LOCK) - WaitForSingleObject(lock_cs[type], INFINITE); - else - ReleaseMutex(lock_cs[type]); - return; -} -#endif /* WIN32 */ - -void ssl_util_thread_setup(void) -{ -#ifdef WIN32 - int i; - - for (i = 0; i < CRYPTO_NUM_LOCKS; i++) - lock_cs[i] = CreateMutex(NULL, FALSE, NULL); - CRYPTO_set_locking_callback((void(*)(int, int, const char *, int)) - win32_locking_callback); -#endif /* WIN32 */ - return; -} - diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c deleted file mode 100644 index 19f6bd3629..0000000000 --- a/modules/ssl/ssl_util_ssl.c +++ /dev/null @@ -1,544 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_util_ssl.c -** Additional Utility Functions for OpenSSL -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - -#include "mod_ssl.h" - - -/* _________________________________________________________________ -** -** Additional High-Level Functions for OpenSSL -** _________________________________________________________________ -*/ - -int SSL_get_app_data2_idx(void) -{ - static int app_data2_idx = -1; - - if (app_data2_idx < 0) { - app_data2_idx = SSL_get_ex_new_index(0, - "Second Application Data for SSL", NULL, NULL, NULL); - app_data2_idx = SSL_get_ex_new_index(0, - "Second Application Data for SSL", NULL, NULL, NULL); - } - return(app_data2_idx); -} - -void *SSL_get_app_data2(SSL *ssl) -{ - return (void *)SSL_get_ex_data(ssl, SSL_get_app_data2_idx()); -} - -void SSL_set_app_data2(SSL *ssl, void *arg) -{ - SSL_set_ex_data(ssl, SSL_get_app_data2_idx(), (char *)arg); - return; -} - -/* _________________________________________________________________ -** -** High-Level Certificate / Private Key Loading -** _________________________________________________________________ -*/ - -X509 *SSL_read_X509(FILE *fp, X509 **x509, int (*cb)()) -{ - X509 *rc; - BIO *bioS; - BIO *bioF; - - /* 1. try PEM (= DER+Base64+headers) */ -#if SSL_LIBRARY_VERSION < 0x00904000 - rc = PEM_read_X509(fp, x509, cb); -#else - rc = PEM_read_X509(fp, x509, cb, NULL); -#endif - if (rc == NULL) { - /* 2. try DER+Base64 */ - fseek(fp, 0L, SEEK_SET); - if ((bioS = BIO_new(BIO_s_fd())) == NULL) - return NULL; - BIO_set_fd(bioS, fileno(fp), BIO_NOCLOSE); - if ((bioF = BIO_new(BIO_f_base64())) == NULL) { - BIO_free(bioS); - return NULL; - } - bioS = BIO_push(bioF, bioS); - rc = d2i_X509_bio(bioS, NULL); - BIO_free_all(bioS); - if (rc == NULL) { - /* 3. try plain DER */ - fseek(fp, 0L, SEEK_SET); - if ((bioS = BIO_new(BIO_s_fd())) == NULL) - return NULL; - BIO_set_fd(bioS, fileno(fp), BIO_NOCLOSE); - rc = d2i_X509_bio(bioS, NULL); - BIO_free(bioS); - } - } - if (rc != NULL && x509 != NULL) { - if (*x509 != NULL) - X509_free(*x509); - *x509 = rc; - } - return rc; -} - -#if SSL_LIBRARY_VERSION <= 0x00904100 -static EVP_PKEY *d2i_PrivateKey_bio(BIO *bio, EVP_PKEY **key) -{ - return ((EVP_PKEY *)ASN1_d2i_bio( - (char *(*)())EVP_PKEY_new, - (char *(*)())d2i_PrivateKey, - (bio), (unsigned char **)(key))); -} -#endif - -EVP_PKEY *SSL_read_PrivateKey(FILE *fp, EVP_PKEY **key, int (*cb)()) -{ - EVP_PKEY *rc; - BIO *bioS; - BIO *bioF; - - /* 1. try PEM (= DER+Base64+headers) */ -#if SSL_LIBRARY_VERSION < 0x00904000 - rc = PEM_read_PrivateKey(fp, key, cb); -#else - rc = PEM_read_PrivateKey(fp, key, cb, NULL); -#endif - if (rc == NULL) { - /* 2. try DER+Base64 */ - fseek(fp, 0L, SEEK_SET); - if ((bioS = BIO_new(BIO_s_fd())) == NULL) - return NULL; - BIO_set_fd(bioS, fileno(fp), BIO_NOCLOSE); - if ((bioF = BIO_new(BIO_f_base64())) == NULL) { - BIO_free(bioS); - return NULL; - } - bioS = BIO_push(bioF, bioS); - rc = d2i_PrivateKey_bio(bioS, NULL); - BIO_free_all(bioS); - if (rc == NULL) { - /* 3. try plain DER */ - fseek(fp, 0L, SEEK_SET); - if ((bioS = BIO_new(BIO_s_fd())) == NULL) - return NULL; - BIO_set_fd(bioS, fileno(fp), BIO_NOCLOSE); - rc = d2i_PrivateKey_bio(bioS, NULL); - BIO_free(bioS); - } - } - if (rc != NULL && key != NULL) { - if (*key != NULL) - EVP_PKEY_free(*key); - *key = rc; - } - return rc; -} - -/* _________________________________________________________________ -** -** Smart shutdown -** _________________________________________________________________ -*/ - -int SSL_smart_shutdown(SSL *ssl) -{ - int i; - int rc; - - /* - * Repeat the calls, because SSL_shutdown internally dispatches through a - * little state machine. Usually only one or two interation should be - * needed, so we restrict the total number of restrictions in order to - * avoid process hangs in case the client played bad with the socket - * connection and OpenSSL cannot recognize it. - */ - rc = 0; - for (i = 0; i < 4 /* max 2x pending + 2x data = 4 */; i++) { - if ((rc = SSL_shutdown(ssl))) - break; - } - return rc; -} - -/* _________________________________________________________________ -** -** Certificate Revocation List (CRL) Storage -** _________________________________________________________________ -*/ - -X509_STORE *SSL_X509_STORE_create(char *cpFile, char *cpPath) -{ - X509_STORE *pStore; - X509_LOOKUP *pLookup; - - if (cpFile == NULL && cpPath == NULL) - return NULL; - if ((pStore = X509_STORE_new()) == NULL) - return NULL; - if (cpFile != NULL) { - if ((pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_file())) == NULL) { - X509_STORE_free(pStore); - return NULL; - } - X509_LOOKUP_load_file(pLookup, cpFile, X509_FILETYPE_PEM); - } - if (cpPath != NULL) { - if ((pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_hash_dir())) == NULL) { - X509_STORE_free(pStore); - return NULL; - } - X509_LOOKUP_add_dir(pLookup, cpPath, X509_FILETYPE_PEM); - } - return pStore; -} - -int SSL_X509_STORE_lookup(X509_STORE *pStore, int nType, - X509_NAME *pName, X509_OBJECT *pObj) -{ - X509_STORE_CTX pStoreCtx; - int rc; - - X509_STORE_CTX_init(&pStoreCtx, pStore, NULL, NULL); - rc = X509_STORE_get_by_subject(&pStoreCtx, nType, pName, pObj); - X509_STORE_CTX_cleanup(&pStoreCtx); - return rc; -} - -/* _________________________________________________________________ -** -** Cipher Suite Spec String Creation -** _________________________________________________________________ -*/ - -char *SSL_make_ciphersuite(pool *p, SSL *ssl) -{ - STACK_OF(SSL_CIPHER) *sk; - SSL_CIPHER *c; - int i; - int l; - char *cpCipherSuite; - char *cp; - - if (ssl == NULL) - return ""; - if ((sk = SSL_get_ciphers(ssl)) == NULL) - return ""; - l = 0; - for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { - c = sk_SSL_CIPHER_value(sk, i); - l += strlen(c->name)+2+1; - } - if (l == 0) - return ""; - cpCipherSuite = (char *)ap_palloc(p, l+1); - cp = cpCipherSuite; - for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { - c = sk_SSL_CIPHER_value(sk, i); - l = strlen(c->name); - memcpy(cp, c->name, l); - cp += l; - *cp++ = '/'; - *cp++ = (c->valid == 1 ? '1' : '0'); - *cp++ = ':'; - } - *(cp-1) = NUL; - return cpCipherSuite; -} - -/* _________________________________________________________________ -** -** Certificate Checks -** _________________________________________________________________ -*/ - -/* check whether cert contains extended key usage with a SGC tag */ -BOOL SSL_X509_isSGC(X509 *cert) -{ - X509_EXTENSION *ext; - int ext_nid; - STACK *sk; - BOOL is_sgc; - int idx; - int i; - - is_sgc = FALSE; - idx = X509_get_ext_by_NID(cert, NID_ext_key_usage, -1); - if (idx >= 0) { - ext = X509_get_ext(cert, idx); - if ((sk = (STACK *)X509V3_EXT_d2i(ext)) != NULL) { - for (i = 0; i < sk_num(sk); i++) { - ext_nid = OBJ_obj2nid((ASN1_OBJECT *)sk_value(sk, i)); - if (ext_nid == NID_ms_sgc || ext_nid == NID_ns_sgc) { - is_sgc = TRUE; - break; - } - } - } - } - return is_sgc; -} - -/* retrieve basic constraints ingredients */ -BOOL SSL_X509_getBC(X509 *cert, int *ca, int *pathlen) -{ - X509_EXTENSION *ext; - BASIC_CONSTRAINTS *bc; - int idx; - BIGNUM *bn = NULL; - char *cp; - - if ((idx = X509_get_ext_by_NID(cert, NID_basic_constraints, -1)) < 0) - return FALSE; - ext = X509_get_ext(cert, idx); - if (ext == NULL) - return FALSE; - if ((bc = (BASIC_CONSTRAINTS *)X509V3_EXT_d2i(ext)) == NULL) - return FALSE; - *ca = bc->ca; - *pathlen = -1 /* unlimited */; - if (bc->pathlen != NULL) { - if ((bn = ASN1_INTEGER_to_BN(bc->pathlen, NULL)) == NULL) - return FALSE; - if ((cp = BN_bn2dec(bn)) == NULL) - return FALSE; - *pathlen = atoi(cp); - free(cp); - BN_free(bn); - } - BASIC_CONSTRAINTS_free(bc); - return TRUE; -} - -/* retrieve subject CommonName of certificate */ -BOOL SSL_X509_getCN(pool *p, X509 *xs, char **cppCN) -{ - X509_NAME *xsn; - X509_NAME_ENTRY *xsne; - int i, nid; - - xsn = X509_get_subject_name(xs); - for (i = 0; i < sk_X509_NAME_ENTRY_num(xsn->entries); i++) { - xsne = sk_X509_NAME_ENTRY_value(xsn->entries, i); - nid = OBJ_obj2nid(xsne->object); - if (nid == NID_commonName) { - *cppCN = ap_palloc(p, xsne->value->length+1); - ap_cpystrn(*cppCN, (char *)xsne->value->data, xsne->value->length+1); - (*cppCN)[xsne->value->length] = NUL; -#ifdef CHARSET_EBCDIC - ascii2ebcdic(*cppCN, *cppCN, strlen(*cppCN)); -#endif - return TRUE; - } - } - return FALSE; -} - -/* _________________________________________________________________ -** -** Low-Level CA Certificate Loading -** _________________________________________________________________ -*/ - -#ifdef SSL_EXPERIMENTAL_PROXY - -BOOL SSL_load_CrtAndKeyInfo_file(pool *p, STACK_OF(X509_INFO) *sk, char *filename) -{ - BIO *in; - - if ((in = BIO_new(BIO_s_file())) == NULL) - return FALSE; - if (BIO_read_filename(in, filename) <= 0) { - BIO_free(in); - return FALSE; - } - ERR_clear_error(); -#if SSL_LIBRARY_VERSION < 0x00904000 - PEM_X509_INFO_read_bio(in, sk, NULL); -#else - PEM_X509_INFO_read_bio(in, sk, NULL, NULL); -#endif - BIO_free(in); - return TRUE; -} - -BOOL SSL_load_CrtAndKeyInfo_path(pool *p, STACK_OF(X509_INFO) *sk, char *pathname) -{ - struct stat st; - DIR *dir; - pool *sp; - struct dirent *nextent; - char *fullname; - BOOL ok; - - sp = ap_make_sub_pool(p); - if ((dir = ap_popendir(sp, pathname)) == NULL) { - ap_destroy_pool(sp); - return FALSE; - } - ok = FALSE; - while ((nextent = readdir(dir)) != NULL) { - fullname = ap_pstrcat(sp, pathname, "/", nextent->d_name, NULL); - if (stat(fullname, &st) != 0) - continue; - if (!S_ISREG(st.st_mode)) - continue; - if (SSL_load_CrtAndKeyInfo_file(sp, sk, fullname)) - ok = TRUE; - } - ap_pclosedir(p, dir); - ap_destroy_pool(sp); - return ok; -} - -#endif /* SSL_EXPERIMENTAL_PROXY */ - -/* _________________________________________________________________ -** -** Extra Server Certificate Chain Support -** _________________________________________________________________ -*/ - -/* - * Read a file that optionally contains the server certificate in PEM - * format, possibly followed by a sequence of CA certificates that - * should be sent to the peer in the SSL Certificate message. - */ -int SSL_CTX_use_certificate_chain( - SSL_CTX *ctx, char *file, int skipfirst, int (*cb)()) -{ - BIO *bio; - X509 *x509; - unsigned long err; - int n; - - if ((bio = BIO_new(BIO_s_file_internal())) == NULL) - return -1; - if (BIO_read_filename(bio, file) <= 0) { - BIO_free(bio); - return -1; - } - /* optionally skip a leading server certificate */ - if (skipfirst) { -#if SSL_LIBRARY_VERSION < 0x00904000 - if ((x509 = PEM_read_bio_X509(bio, NULL, cb)) == NULL) { -#else - if ((x509 = PEM_read_bio_X509(bio, NULL, cb, NULL)) == NULL) { -#endif - BIO_free(bio); - return -1; - } - X509_free(x509); - } - /* free a perhaps already configured extra chain */ - if (ctx->extra_certs != NULL) { - sk_X509_pop_free(ctx->extra_certs, X509_free); - ctx->extra_certs = NULL; - } - /* create new extra chain by loading the certs */ - n = 0; -#if SSL_LIBRARY_VERSION < 0x00904000 - while ((x509 = PEM_read_bio_X509(bio, NULL, cb)) != NULL) { -#else - while ((x509 = PEM_read_bio_X509(bio, NULL, cb, NULL)) != NULL) { -#endif - if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) { - X509_free(x509); - BIO_free(bio); - return -1; - } - n++; - } - /* Make sure that only the error is just an EOF */ - if ((err = ERR_peek_error()) > 0) { - if (!( ERR_GET_LIB(err) == ERR_LIB_PEM - && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { - BIO_free(bio); - return -1; - } - while (ERR_get_error() > 0) ; - } - BIO_free(bio); - return n; -} - -/* _________________________________________________________________ -** -** Session Stuff -** _________________________________________________________________ -*/ - -char *SSL_SESSION_id2sz(unsigned char *id, int idlen) -{ - static char str[(SSL_MAX_SSL_SESSION_ID_LENGTH+1)*2]; - char *cp; - int n; - - cp = str; - for (n = 0; n < idlen && n < SSL_MAX_SSL_SESSION_ID_LENGTH; n++) { - ap_snprintf(cp, sizeof(str)-(cp-str), "%02X", id[n]); - cp += 2; - } - *cp = NUL; - return str; -} - diff --git a/modules/ssl/ssl_util_ssl.h b/modules/ssl/ssl_util_ssl.h deleted file mode 100644 index 23aaaaa40d..0000000000 --- a/modules/ssl/ssl_util_ssl.h +++ /dev/null @@ -1,115 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_util_ssl.h -** Additional Utility Functions for OpenSSL -*/ - -/* ==================================================================== - * Copyright (c) 1998-2001 Ralf S. Engelschall. 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 - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * 4. The names "mod_ssl" must not be used to endorse or promote - * products derived from this software without prior written - * permission. For written permission, please contact - * rse@engelschall.com. - * - * 5. Products derived from this software may not be called "mod_ssl" - * nor may "mod_ssl" appear in their names without prior - * written permission of Ralf S. Engelschall. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com> for use in the - * mod_ssl project (http://www.modssl.org/)." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``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 RALF S. ENGELSCHALL OR - * HIS 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. - * ==================================================================== - */ - -#ifndef SSL_UTIL_SSL_H -#define SSL_UTIL_SSL_H - -/* - * Determine SSL library version number - */ -#ifdef OPENSSL_VERSION_NUMBER -#define SSL_LIBRARY_VERSION OPENSSL_VERSION_NUMBER -#define SSL_LIBRARY_NAME "OpenSSL" -#define SSL_LIBRARY_TEXT OPENSSL_VERSION_TEXT -#else -#define SSL_LIBRARY_VERSION 0x0000 -#define SSL_LIBRARY_NAME "OtherSSL" -#define SSL_LIBRARY_TEXT "OtherSSL 0.0.0 00 XXX 0000" -#endif - -/* - * Support for retrieving/overriding states - */ -#ifndef SSL_get_state -#define SSL_get_state(ssl) SSL_state(ssl) -#endif -#define SSL_set_state(ssl,val) (ssl)->state = val - -/* - * Maximum length of a DER encoded session. - * FIXME: There is no define in OpenSSL, but OpenSSL uses 1024*10, - * so this value should be ok. Although we have no warm feeling. - */ -#define SSL_SESSION_MAX_DER 1024*10 - -/* - * Additional Functions - */ -int SSL_get_app_data2_idx(void); -void *SSL_get_app_data2(SSL *); -void SSL_set_app_data2(SSL *, void *); -X509 *SSL_read_X509(FILE *, X509 **, int (*)()); -EVP_PKEY *SSL_read_PrivateKey(FILE *, EVP_PKEY **, int (*)()); -int SSL_smart_shutdown(SSL *ssl); -X509_STORE *SSL_X509_STORE_create(char *, char *); -int SSL_X509_STORE_lookup(X509_STORE *, int, X509_NAME *, X509_OBJECT *); -char *SSL_make_ciphersuite(pool *, SSL *); -BOOL SSL_X509_isSGC(X509 *); -BOOL SSL_X509_getBC(X509 *, int *, int *); -BOOL SSL_X509_getCN(pool *, X509 *, char **); -#ifdef SSL_EXPERIMENTAL_PROXY -BOOL SSL_load_CrtAndKeyInfo_file(pool *, STACK_OF(X509_INFO) *, char *); -BOOL SSL_load_CrtAndKeyInfo_path(pool *, STACK_OF(X509_INFO) *, char *); -#endif /* SSL_EXPERIMENTAL_PROXY */ -int SSL_CTX_use_certificate_chain(SSL_CTX *, char *, int, int (*)()); -char *SSL_SESSION_id2sz(unsigned char *, int); - -#endif /* SSL_UTIL_SSL_H */ diff --git a/modules/test/.cvsignore b/modules/test/.cvsignore deleted file mode 100644 index 02736007bd..0000000000 --- a/modules/test/.cvsignore +++ /dev/null @@ -1,7 +0,0 @@ -.deps -Makefile -*.lo -*.so -modules.mk -Debug -Release diff --git a/modules/test/.indent.pro b/modules/test/.indent.pro deleted file mode 100644 index a9fbe9f9a1..0000000000 --- a/modules/test/.indent.pro +++ /dev/null @@ -1,54 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 --TBUFF --TFILE --TTRANS --TUINT4 --T_trans --Tallow_options_t --Tapache_sfio --Tarray_header --Tbool_int --Tbuf_area --Tbuff_struct --Tbuffy --Tcmd_how --Tcmd_parms --Tcommand_rec --Tcommand_struct --Tconn_rec --Tcore_dir_config --Tcore_server_config --Tdir_maker_func --Tevent --Tglobals_s --Thandler_func --Thandler_rec --Tjoblist_s --Tlisten_rec --Tmerger_func --Tmode_t --Tmodule --Tmodule_struct --Tmutex --Tn_long --Tother_child_rec --Toverrides_t --Tparent_score --Tpid_t --Tpiped_log --Tpool --Trequest_rec --Trequire_line --Trlim_t --Tscoreboard --Tsemaphore --Tserver_addr_rec --Tserver_rec --Tserver_rec_chain --Tshort_score --Ttable --Ttable_entry --Tthread --Tu_wide_int --Tvtime_t --Twide_int diff --git a/modules/test/README b/modules/test/README deleted file mode 100644 index c61763c1dd..0000000000 --- a/modules/test/README +++ /dev/null @@ -1,3 +0,0 @@ -This directory is intended to house modules which are used for testing -server functionality. They're unsupported, and not guaranteed to remain -consistant between releases. You're on your own completely with these. diff --git a/modules/test/mod_autoindex.c b/modules/test/mod_autoindex.c deleted file mode 100644 index d875082a85..0000000000 --- a/modules/test/mod_autoindex.c +++ /dev/null @@ -1,1711 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_autoindex.c: Handles the on-the-fly html index generation - * - * Rob McCool - * 3/23/93 - * - * Adapted to Apache by rst. - * - * Version sort added by Martin Pool <mbp@humbug.org.au>. */ - -#include "apr_strings.h" -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_request.h" -#include "http_protocol.h" -#include "http_log.h" -#include "http_main.h" -#include "util_script.h" -#include "apr_fnmatch.h" -#include "apr_strings.h" -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_STRINGS_H -#include <strings.h> -#endif - -module AP_MODULE_DECLARE_DATA autoindex_module; - -/**************************************************************** - * - * Handling configuration directives... - */ - -#define HRULE 1 -#define NO_HRULE 0 -#define FRONT_MATTER 1 -#define END_MATTER 0 - -#define FANCY_INDEXING 1 /* Indexing options */ -#define ICONS_ARE_LINKS 2 -#define SCAN_HTML_TITLES 4 -#define SUPPRESS_LAST_MOD 8 -#define SUPPRESS_SIZE 16 -#define SUPPRESS_DESC 32 -#define SUPPRESS_PREAMBLE 64 -#define SUPPRESS_COLSORT 128 -#define NO_OPTIONS 256 -#define VERSION_SORT 512 - -#define K_PAD 1 -#define K_NOPAD 0 - -#define K_NOADJUST 0 -#define K_ADJUST 1 -#define K_UNSET 2 - -/* - * Define keys for sorting. - */ -#define K_NAME 'N' /* Sort by file name (default) */ -#define K_LAST_MOD 'M' /* Last modification date */ -#define K_SIZE 'S' /* Size (absolute, not as displayed) */ -#define K_DESC 'D' /* Description */ - -#define D_ASCENDING 'A' -#define D_DESCENDING 'D' - -/* - * These are the dimensions of the default icons supplied with Apache. - */ -#define DEFAULT_ICON_WIDTH 20 -#define DEFAULT_ICON_HEIGHT 22 - -/* - * Other default dimensions. - */ -#define DEFAULT_NAME_WIDTH 23 - -struct item { - char *type; - char *apply_to; - char *apply_path; - char *data; -}; - -typedef struct ai_desc_t { - char *pattern; - char *description; - int full_path; - int wildcards; -} ai_desc_t; - -typedef struct autoindex_config_struct { - - char *default_icon; - int opts; - int incremented_opts; - int decremented_opts; - int name_width; - int name_adjust; - int icon_width; - int icon_height; - char *default_order; - - apr_array_header_t *icon_list; - apr_array_header_t *alt_list; - apr_array_header_t *desc_list; - apr_array_header_t *ign_list; - apr_array_header_t *hdr_list; - apr_array_header_t *rdme_list; - -} autoindex_config_rec; - -static char c_by_encoding, c_by_type, c_by_path; - -#define BY_ENCODING &c_by_encoding -#define BY_TYPE &c_by_type -#define BY_PATH &c_by_path - -/* - * Return true if the specified string refers to the parent directory (i.e., - * matches ".." or "../"). Hopefully this one call is significantly less - * expensive than multiple strcmp() calls. - */ -static apr_inline int is_parent(const char *name) -{ - /* - * Now, IFF the first two bytes are dots, and the third byte is either - * EOS (\0) or a slash followed by EOS, we have a match. - */ - if (((name[0] == '.') && (name[1] == '.')) - && ((name[2] == '\0') - || ((name[2] == '/') && (name[3] == '\0')))) { - return 1; - } - return 0; -} - -/* - * This routine puts the standard HTML header at the top of the index page. - * We include the DOCTYPE because we may be using features therefrom (i.e., - * HEIGHT and WIDTH attributes on the icons if we're FancyIndexing). - */ -static void emit_preamble(request_rec *r, char *title) -{ - ap_rvputs(r, DOCTYPE_HTML_3_2, - "<HTML>\n <HEAD>\n <TITLE>Index of ", title, - "</TITLE>\n </HEAD>\n <BODY>\n", NULL); -} - -static void push_item(apr_array_header_t *arr, char *type, const char *to, - const char *path, const char *data) -{ - struct item *p = (struct item *) apr_array_push(arr); - - if (!to) { - to = ""; - } - if (!path) { - path = ""; - } - - p->type = type; - p->data = data ? apr_pstrdup(arr->cont, data) : NULL; - p->apply_path = apr_pstrcat(arr->cont, path, "*", NULL); - - if ((type == BY_PATH) && (!ap_is_matchexp(to))) { - p->apply_to = apr_pstrcat(arr->cont, "*", to, NULL); - } - else if (to) { - p->apply_to = apr_pstrdup(arr->cont, to); - } - else { - p->apply_to = NULL; - } -} - -static const char *add_alt(cmd_parms *cmd, void *d, const char *alt, - const char *to) -{ - if (cmd->info == BY_PATH) { - if (!strcmp(to, "**DIRECTORY**")) { - to = "^^DIRECTORY^^"; - } - } - if (cmd->info == BY_ENCODING) { - char *tmp = apr_pstrdup(cmd->pool, to); - ap_str_tolower(tmp); - to = tmp; - } - - push_item(((autoindex_config_rec *) d)->alt_list, cmd->info, to, - cmd->path, alt); - return NULL; -} - -static const char *add_icon(cmd_parms *cmd, void *d, const char *icon, - const char *to) -{ - char *iconbak = apr_pstrdup(cmd->pool, icon); - - if (icon[0] == '(') { - char *alt; - char *cl = strchr(iconbak, ')'); - - if (cl == NULL) { - return "missing closing paren"; - } - alt = ap_getword_nc(cmd->pool, &iconbak, ','); - *cl = '\0'; /* Lose closing paren */ - add_alt(cmd, d, &alt[1], to); - } - if (cmd->info == BY_PATH) { - if (!strcmp(to, "**DIRECTORY**")) { - to = "^^DIRECTORY^^"; - } - } - if (cmd->info == BY_ENCODING) { - char *tmp = apr_pstrdup(cmd->pool, to); - ap_str_tolower(tmp); - to = tmp; - } - - push_item(((autoindex_config_rec *) d)->icon_list, cmd->info, to, - cmd->path, iconbak); - return NULL; -} - -/* - * Add description text for a filename pattern. If the pattern has - * wildcards already (or we need to add them), add leading and - * trailing wildcards to it to ensure substring processing. If the - * pattern contains a '/' anywhere, force wildcard matching mode, - * add a slash to the prefix so that "bar/bletch" won't be matched - * by "foobar/bletch", and make a note that there's a delimiter; - * the matching routine simplifies to just the actual filename - * whenever it can. This allows definitions in parent directories - * to be made for files in subordinate ones using relative paths. - */ - -/* - * Absent a strcasestr() function, we have to force wildcards on - * systems for which "AAA" and "aaa" mean the same file. - */ -#ifdef CASE_BLIND_FILESYSTEM -#define WILDCARDS_REQUIRED 1 -#else -#define WILDCARDS_REQUIRED 0 -#endif - -static const char *add_desc(cmd_parms *cmd, void *d, const char *desc, - const char *to) -{ - autoindex_config_rec *dcfg = (autoindex_config_rec *) d; - ai_desc_t *desc_entry; - char *prefix = ""; - - desc_entry = (ai_desc_t *) apr_array_push(dcfg->desc_list); - desc_entry->full_path = (ap_strchr_c(to, '/') == NULL) ? 0 : 1; - desc_entry->wildcards = (WILDCARDS_REQUIRED - || desc_entry->full_path - || apr_is_fnmatch(to)); - if (desc_entry->wildcards) { - prefix = desc_entry->full_path ? "*/" : "*"; - desc_entry->pattern = apr_pstrcat(dcfg->desc_list->cont, - prefix, to, "*", NULL); - } - else { - desc_entry->pattern = apr_pstrdup(dcfg->desc_list->cont, to); - } - desc_entry->description = apr_pstrdup(dcfg->desc_list->cont, desc); - return NULL; -} - -static const char *add_ignore(cmd_parms *cmd, void *d, const char *ext) -{ - push_item(((autoindex_config_rec *) d)->ign_list, 0, ext, cmd->path, NULL); - return NULL; -} - -static const char *add_header(cmd_parms *cmd, void *d, const char *name) -{ - push_item(((autoindex_config_rec *) d)->hdr_list, 0, NULL, cmd->path, - name); - return NULL; -} - -static const char *add_readme(cmd_parms *cmd, void *d, const char *name) -{ - push_item(((autoindex_config_rec *) d)->rdme_list, 0, NULL, cmd->path, - name); - return NULL; -} - -/* A legacy directive, FancyIndexing is superseded by the IndexOptions - * keyword. But for compatibility.. - */ -static const char *fancy_indexing(cmd_parms *cmd, void *d, int arg) -{ - int curopts; - int newopts; - autoindex_config_rec *cfg; - - cfg = (autoindex_config_rec *) d; - curopts = cfg->opts; - if (curopts & NO_OPTIONS) { - return "FancyIndexing directive conflicts with existing " - "IndexOptions None"; - } - newopts = (arg ? (curopts | FANCY_INDEXING) : (curopts & ~FANCY_INDEXING)); - cfg->opts = newopts; - return NULL; -} - -static const char *add_opts(cmd_parms *cmd, void *d, const char *optstr) -{ - char *w; - int opts; - int opts_add; - int opts_remove; - char action; - autoindex_config_rec *d_cfg = (autoindex_config_rec *) d; - - opts = d_cfg->opts; - opts_add = d_cfg->incremented_opts; - opts_remove = d_cfg->decremented_opts; - while (optstr[0]) { - int option = 0; - - w = ap_getword_conf(cmd->pool, &optstr); - if ((*w == '+') || (*w == '-')) { - action = *(w++); - } - else { - action = '\0'; - } - if (!strcasecmp(w, "FancyIndexing")) { - option = FANCY_INDEXING; - } - else if (!strcasecmp(w, "IconsAreLinks")) { - option = ICONS_ARE_LINKS; - } - else if (!strcasecmp(w, "ScanHTMLTitles")) { - option = SCAN_HTML_TITLES; - } - else if (!strcasecmp(w, "SuppressLastModified")) { - option = SUPPRESS_LAST_MOD; - } - else if (!strcasecmp(w, "SuppressSize")) { - option = SUPPRESS_SIZE; - } - else if (!strcasecmp(w, "SuppressDescription")) { - option = SUPPRESS_DESC; - } - else if (!strcasecmp(w, "SuppressHTMLPreamble")) { - option = SUPPRESS_PREAMBLE; - } - else if (!strcasecmp(w, "SuppressColumnSorting")) { - option = SUPPRESS_COLSORT; - } - else if (!strcasecmp(w, "VersionSort")) { - option = VERSION_SORT; - } - else if (!strcasecmp(w, "None")) { - if (action != '\0') { - return "Cannot combine '+' or '-' with 'None' keyword"; - } - opts = NO_OPTIONS; - opts_add = 0; - opts_remove = 0; - } - else if (!strcasecmp(w, "IconWidth")) { - if (action != '-') { - d_cfg->icon_width = DEFAULT_ICON_WIDTH; - } - else { - d_cfg->icon_width = 0; - } - } - else if (!strncasecmp(w, "IconWidth=", 10)) { - if (action == '-') { - return "Cannot combine '-' with IconWidth=n"; - } - d_cfg->icon_width = atoi(&w[10]); - } - else if (!strcasecmp(w, "IconHeight")) { - if (action != '-') { - d_cfg->icon_height = DEFAULT_ICON_HEIGHT; - } - else { - d_cfg->icon_height = 0; - } - } - else if (!strncasecmp(w, "IconHeight=", 11)) { - if (action == '-') { - return "Cannot combine '-' with IconHeight=n"; - } - d_cfg->icon_height = atoi(&w[11]); - } - else if (!strcasecmp(w, "NameWidth")) { - if (action != '-') { - return "NameWidth with no value may only appear as " - "'-NameWidth'"; - } - d_cfg->name_width = DEFAULT_NAME_WIDTH; - d_cfg->name_adjust = K_NOADJUST; - } - else if (!strncasecmp(w, "NameWidth=", 10)) { - if (action == '-') { - return "Cannot combine '-' with NameWidth=n"; - } - if (w[10] == '*') { - d_cfg->name_adjust = K_ADJUST; - } - else { - int width = atoi(&w[10]); - - if (width < 5) { - return "NameWidth value must be greater than 5"; - } - d_cfg->name_width = width; - d_cfg->name_adjust = K_NOADJUST; - } - } - else { - return "Invalid directory indexing option"; - } - if (action == '\0') { - opts |= option; - opts_add = 0; - opts_remove = 0; - } - else if (action == '+') { - opts_add |= option; - opts_remove &= ~option; - } - else { - opts_remove |= option; - opts_add &= ~option; - } - } - if ((opts & NO_OPTIONS) && (opts & ~NO_OPTIONS)) { - return "Cannot combine other IndexOptions keywords with 'None'"; - } - d_cfg->incremented_opts = opts_add; - d_cfg->decremented_opts = opts_remove; - d_cfg->opts = opts; - return NULL; -} - -static const char *set_default_order(cmd_parms *cmd, void *m, const char *direction, - const char *key) -{ - char temp[4]; - autoindex_config_rec *d_cfg = (autoindex_config_rec *) m; - - apr_cpystrn(temp, "k=d", sizeof(temp)); - if (!strcasecmp(direction, "Ascending")) { - temp[2] = D_ASCENDING; - } - else if (!strcasecmp(direction, "Descending")) { - temp[2] = D_DESCENDING; - } - else { - return "First keyword must be 'Ascending' or 'Descending'"; - } - - if (!strcasecmp(key, "Name")) { - temp[0] = K_NAME; - } - else if (!strcasecmp(key, "Date")) { - temp[0] = K_LAST_MOD; - } - else if (!strcasecmp(key, "Size")) { - temp[0] = K_SIZE; - } - else if (!strcasecmp(key, "Description")) { - temp[0] = K_DESC; - } - else { - return "Second keyword must be 'Name', 'Date', 'Size', or " - "'Description'"; - } - - if (d_cfg->default_order == NULL) { - d_cfg->default_order = apr_palloc(cmd->pool, 4); - d_cfg->default_order[3] = '\0'; - } - apr_cpystrn(d_cfg->default_order, temp, sizeof(temp)); - return NULL; -} - -#define DIR_CMD_PERMS OR_INDEXES - -static const command_rec autoindex_cmds[] = -{ - AP_INIT_ITERATE2("AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS, - "an icon URL followed by one or more filenames"), - AP_INIT_ITERATE2("AddIconByType", add_icon, BY_TYPE, DIR_CMD_PERMS, - "an icon URL followed by one or more MIME types"), - AP_INIT_ITERATE2("AddIconByEncoding", add_icon, BY_ENCODING, DIR_CMD_PERMS, - "an icon URL followed by one or more content encodings"), - AP_INIT_ITERATE2("AddAlt", add_alt, BY_PATH, DIR_CMD_PERMS, - "alternate descriptive text followed by one or more filenames"), - AP_INIT_ITERATE2("AddAltByType", add_alt, BY_TYPE, DIR_CMD_PERMS, - "alternate descriptive text followed by one or more MIME types"), - AP_INIT_ITERATE2("AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS, - "alternate descriptive text followed by one or more content encodings"), - AP_INIT_RAW_ARGS("IndexOptions", add_opts, NULL, DIR_CMD_PERMS, - "one or more index options"), - AP_INIT_TAKE2("IndexOrderDefault", set_default_order, NULL, DIR_CMD_PERMS, - "{Ascending,Descending} {Name,Size,Description,Date}"), - AP_INIT_ITERATE("IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS, - "one or more file extensions"), - AP_INIT_ITERATE2("AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS, - "Descriptive text followed by one or more filenames"), - AP_INIT_TAKE1("HeaderName", add_header, NULL, DIR_CMD_PERMS, - "a filename"), - AP_INIT_TAKE1("ReadmeName", add_readme, NULL, DIR_CMD_PERMS, - "a filename"), - AP_INIT_FLAG("FancyIndexing", fancy_indexing, NULL, DIR_CMD_PERMS, - "Limited to 'on' or 'off' (superseded by IndexOptions FancyIndexing)"), - AP_INIT_TAKE1("DefaultIcon", ap_set_string_slot, - (void *) XtOffsetOf(autoindex_config_rec, default_icon), - DIR_CMD_PERMS, "an icon URL"), - {NULL} -}; - -static void *create_autoindex_config(apr_pool_t *p, char *dummy) -{ - autoindex_config_rec *new = - (autoindex_config_rec *) apr_pcalloc(p, sizeof(autoindex_config_rec)); - - new->icon_width = 0; - new->icon_height = 0; - new->name_width = DEFAULT_NAME_WIDTH; - new->name_adjust = K_UNSET; - new->icon_list = apr_array_make(p, 4, sizeof(struct item)); - new->alt_list = apr_array_make(p, 4, sizeof(struct item)); - new->desc_list = apr_array_make(p, 4, sizeof(ai_desc_t)); - new->ign_list = apr_array_make(p, 4, sizeof(struct item)); - new->hdr_list = apr_array_make(p, 4, sizeof(struct item)); - new->rdme_list = apr_array_make(p, 4, sizeof(struct item)); - new->opts = 0; - new->incremented_opts = 0; - new->decremented_opts = 0; - new->default_order = NULL; - - return (void *) new; -} - -static void *merge_autoindex_configs(apr_pool_t *p, void *basev, void *addv) -{ - autoindex_config_rec *new; - autoindex_config_rec *base = (autoindex_config_rec *) basev; - autoindex_config_rec *add = (autoindex_config_rec *) addv; - - new = (autoindex_config_rec *) apr_pcalloc(p, sizeof(autoindex_config_rec)); - new->default_icon = add->default_icon ? add->default_icon - : base->default_icon; - new->icon_height = add->icon_height ? add->icon_height : base->icon_height; - new->icon_width = add->icon_width ? add->icon_width : base->icon_width; - - new->alt_list = apr_array_append(p, add->alt_list, base->alt_list); - new->ign_list = apr_array_append(p, add->ign_list, base->ign_list); - new->hdr_list = apr_array_append(p, add->hdr_list, base->hdr_list); - new->desc_list = apr_array_append(p, add->desc_list, base->desc_list); - new->icon_list = apr_array_append(p, add->icon_list, base->icon_list); - new->rdme_list = apr_array_append(p, add->rdme_list, base->rdme_list); - if (add->opts & NO_OPTIONS) { - /* - * If the current directory says 'no options' then we also - * clear any incremental mods from being inheritable further down. - */ - new->opts = NO_OPTIONS; - new->incremented_opts = 0; - new->decremented_opts = 0; - } - else { - /* - * If there were any nonincremental options selected for - * this directory, they dominate and we don't inherit *anything.* - * Contrariwise, we *do* inherit if the only settings here are - * incremental ones. - */ - if (add->opts == 0) { - new->incremented_opts = (base->incremented_opts - | add->incremented_opts) - & ~add->decremented_opts; - new->decremented_opts = (base->decremented_opts - | add->decremented_opts); - /* - * We may have incremental settings, so make sure we don't - * inadvertently inherit an IndexOptions None from above. - */ - new->opts = (base->opts & ~NO_OPTIONS); - } - else { - /* - * There are local nonincremental settings, which clear - * all inheritance from above. They *are* the new base settings. - */ - new->opts = add->opts;; - } - /* - * We're guaranteed that there'll be no overlap between - * the add-options and the remove-options. - */ - new->opts |= new->incremented_opts; - new->opts &= ~new->decremented_opts; - } - /* - * Inherit the NameWidth settings if there aren't any specific to - * the new location; otherwise we'll end up using the defaults set in the - * config-rec creation routine. - */ - if (add->name_adjust == K_UNSET) { - new->name_width = base->name_width; - new->name_adjust = base->name_adjust; - } - else { - new->name_width = add->name_width; - new->name_adjust = add->name_adjust; - } - - new->default_order = (add->default_order != NULL) - ? add->default_order : base->default_order; - return new; -} - -/**************************************************************** - * - * Looking things up in config entries... - */ - -/* Structure used to hold entries when we're actually building an index */ - -struct ent { - char *name; - char *icon; - char *alt; - char *desc; - off_t size; - apr_time_t lm; - struct ent *next; - int ascending, version_sort; - char key; -}; - -static char *find_item(request_rec *r, apr_array_header_t *list, int path_only) -{ - const char *content_type = ap_field_noparam(r->pool, r->content_type); - const char *content_encoding = r->content_encoding; - char *path = r->filename; - - struct item *items = (struct item *) list->elts; - int i; - - for (i = 0; i < list->nelts; ++i) { - struct item *p = &items[i]; - - /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */ - if ((path[0] == '^') || (!ap_strcmp_match(path, p->apply_path))) { - if (!*(p->apply_to)) { - return p->data; - } - else if (p->type == BY_PATH || path[0] == '^') { - if (!ap_strcmp_match(path, p->apply_to)) { - return p->data; - } - } - else if (!path_only) { - if (!content_encoding) { - if (p->type == BY_TYPE) { - if (content_type - && !ap_strcasecmp_match(content_type, - p->apply_to)) { - return p->data; - } - } - } - else { - if (p->type == BY_ENCODING) { - if (!ap_strcasecmp_match(content_encoding, - p->apply_to)) { - return p->data; - } - } - } - } - } - } - return NULL; -} - -#define find_icon(d,p,t) find_item(p,d->icon_list,t) -#define find_alt(d,p,t) find_item(p,d->alt_list,t) -#define find_header(d,p) find_item(p,d->hdr_list,0) -#define find_readme(d,p) find_item(p,d->rdme_list,0) - -static char *find_default_icon(autoindex_config_rec *d, char *bogus_name) -{ - request_rec r; - - /* Bleah. I tried to clean up find_item, and it lead to this bit - * of ugliness. Note that the fields initialized are precisely - * those that find_item looks at... - */ - - r.filename = bogus_name; - r.content_type = r.content_encoding = NULL; - - return find_item(&r, d->icon_list, 1); -} - -/* - * Look through the list of pattern/description pairs and return the first one - * if any) that matches the filename in the request. If multiple patterns - * match, only the first one is used; since the order in the array is the - * same as the order in which directives were processed, earlier matching - * directives will dominate. - */ - -#ifdef CASE_BLIND_FILESYSTEM -#define MATCH_FLAGS FNM_CASE_BLIND -#else -#define MATCH_FLAGS 0 -#endif - -static char *find_desc(autoindex_config_rec *dcfg, request_rec *r) -{ - int i; - ai_desc_t *list = (ai_desc_t *) dcfg->desc_list->elts; - const char *filename_full = r->filename; - const char *filename_only; - const char *filename; - - /* - * If the filename includes a path, extract just the name itself - * for the simple matches. - */ - if ((filename_only = ap_strrchr_c(filename_full, '/')) == NULL) { - filename_only = filename_full; - } - else { - filename_only++; - } - for (i = 0; i < dcfg->desc_list->nelts; ++i) { - ai_desc_t *tuple = &list[i]; - int found; - - /* - * Only use the full-path filename if the pattern contains '/'s. - */ - filename = (tuple->full_path) ? filename_full : filename_only; - /* - * Make the comparison using the cheapest method; only do - * wildcard checking if we must. - */ - if (tuple->wildcards) { - found = (apr_fnmatch(tuple->pattern, filename, MATCH_FLAGS) == 0); - } - else { - found = (ap_strstr_c(filename, tuple->pattern) != NULL); - } - if (found) { - return tuple->description; - } - } - return NULL; -} - -static int ignore_entry(autoindex_config_rec *d, char *path) -{ - apr_array_header_t *list = d->ign_list; - struct item *items = (struct item *) list->elts; - char *tt; - int i; - - if ((tt = strrchr(path, '/')) == NULL) { - tt = path; - } - else { - tt++; - } - - for (i = 0; i < list->nelts; ++i) { - struct item *p = &items[i]; - char *ap; - - if ((ap = strrchr(p->apply_to, '/')) == NULL) { - ap = p->apply_to; - } - else { - ap++; - } - -#ifndef CASE_BLIND_FILESYSTEM - if (!ap_strcmp_match(path, p->apply_path) - && !ap_strcmp_match(tt, ap)) { - return 1; - } -#else /* !CASE_BLIND_FILESYSTEM */ - /* - * On some platforms, the match must be case-blind. This is really - * a factor of the filesystem involved, but we can't detect that - * reliably - so we have to granularise at the OS level. - */ - if (!ap_strcasecmp_match(path, p->apply_path) - && !ap_strcasecmp_match(tt, ap)) { - return 1; - } -#endif /* !CASE_BLIND_FILESYSTEM */ - } - return 0; -} - -/***************************************************************** - * - * Actually generating output - */ - -/* - * Elements of the emitted document: - * Preamble - * Emitted unless SUPPRESS_PREAMBLE is set AND ap_run_sub_req - * succeeds for the (content_type == text/html) header file. - * Header file - * Emitted if found (and able). - * H1 tag line - * Emitted if a header file is NOT emitted. - * Directory stuff - * Always emitted. - * HR - * Emitted if FANCY_INDEXING is set. - * Readme file - * Emitted if found (and able). - * ServerSig - * Emitted if ServerSignature is not Off AND a readme file - * is NOT emitted. - * Postamble - * Emitted unless SUPPRESS_PREAMBLE is set AND ap_run_sub_req - * succeeds for the (content_type == text/html) readme file. - */ - - -/* - * emit a plain text file - */ -static void do_emit_plain(request_rec *r, apr_file_t *f) -{ - char buf[AP_IOBUFSIZE + 1]; - int i, c, ch; - apr_size_t n; - apr_status_t stat; - - ap_rputs("<PRE>\n", r); - while (!apr_file_eof(f)) { - do { - n = sizeof(char) * AP_IOBUFSIZE; - stat = apr_file_read(f, buf, &n); - } - while (stat != APR_SUCCESS && APR_STATUS_IS_EINTR(stat)); - if (n == -1 || n == 0) { - break; - } - buf[n] = '\0'; - c = 0; - while (c < n) { - for (i = c; i < n; i++) { - if (buf[i] == '<' || buf[i] == '>' || buf[i] == '&') { - break; - } - } - ch = buf[i]; - buf[i] = '\0'; - ap_rputs(&buf[c], r); - if (ch == '<') { - ap_rputs("<", r); - } - else if (ch == '>') { - ap_rputs(">", r); - } - else if (ch == '&') { - ap_rputs("&", r); - } - c = i + 1; - } - } - ap_rputs("</PRE>\n", r); -} - -/* - * Handle the preamble through the H1 tag line, inclusive. Locate - * the file with a subrequests. Process text/html documents by actually - * running the subrequest; text/xxx documents get copied verbatim, - * and any other content type is ignored. This means that a non-text - * document (such as HEADER.gif) might get multiviewed as the result - * instead of a text document, meaning nothing will be displayed, but - * oh well. - */ -static void emit_head(request_rec *r, char *header_fname, int suppress_amble, - char *title) -{ - apr_file_t *f = NULL; - request_rec *rr = NULL; - int emit_amble = 1; - int emit_H1 = 1; - - /* - * If there's a header file, send a subrequest to look for it. If it's - * found and a text file, handle it -- otherwise fall through and - * pretend there's nothing there. - */ - if ((header_fname != NULL) - && (rr = ap_sub_req_lookup_uri(header_fname, r, NULL)) - && (rr->status == HTTP_OK) - && (rr->filename != NULL) - && rr->finfo.filetype == APR_REG) { - /* - * Check for the two specific cases we allow: text/html and - * text/anything-else. The former is allowed to be processed for - * SSIs. - */ - if (rr->content_type != NULL) { - if (!strcasecmp(ap_field_noparam(r->pool, rr->content_type), - "text/html")) { - /* Hope everything will work... */ - emit_amble = 0; - emit_H1 = 0; - - if (! suppress_amble) { - emit_preamble(r, title); - } - /* - * If there's a problem running the subrequest, display the - * preamble if we didn't do it before -- the header file - * didn't get displayed. - */ - if (ap_run_sub_req(rr) != OK) { - /* It didn't work */ - emit_amble = suppress_amble; - emit_H1 = 1; - } - } - else if (!strncasecmp("text/", rr->content_type, 5)) { - /* - * If we can open the file, prefix it with the preamble - * regardless; since we'll be sending a <PRE> block around - * the file's contents, any HTML header it had won't end up - * where it belongs. - */ - if (apr_file_open(&f, rr->filename, APR_READ, - APR_OS_DEFAULT, r->pool) == APR_SUCCESS) { - emit_preamble(r, title); - emit_amble = 0; - do_emit_plain(r, f); - apr_file_close(f); - emit_H1 = 0; - } - } - } - } - - if (emit_amble) { - emit_preamble(r, title); - } - if (emit_H1) { - ap_rvputs(r, "<H1>Index of ", title, "</H1>\n", NULL); - } - if (rr != NULL) { - ap_destroy_sub_req(rr); - } -} - - -/* - * Handle the Readme file through the postamble, inclusive. Locate - * the file with a subrequests. Process text/html documents by actually - * running the subrequest; text/xxx documents get copied verbatim, - * and any other content type is ignored. This means that a non-text - * document (such as FOOTER.gif) might get multiviewed as the result - * instead of a text document, meaning nothing will be displayed, but - * oh well. - */ -static void emit_tail(request_rec *r, char *readme_fname, int suppress_amble) -{ - apr_file_t *f = NULL; - request_rec *rr = NULL; - int suppress_post = 0; - int suppress_sig = 0; - - /* - * If there's a readme file, send a subrequest to look for it. If it's - * found and a text file, handle it -- otherwise fall through and - * pretend there's nothing there. - */ - if ((readme_fname != NULL) - && (rr = ap_sub_req_lookup_uri(readme_fname, r, NULL)) - && (rr->status == HTTP_OK) - && (rr->filename != NULL) - && rr->finfo.filetype == APR_REG) { - /* - * Check for the two specific cases we allow: text/html and - * text/anything-else. The former is allowed to be processed for - * SSIs. - */ - if (rr->content_type != NULL) { - if (!strcasecmp(ap_field_noparam(r->pool, rr->content_type), - "text/html")) { - if (ap_run_sub_req(rr) == OK) { - /* worked... */ - suppress_sig = 1; - suppress_post = suppress_amble; - } - } - else if (!strncasecmp("text/", rr->content_type, 5)) { - /* - * If we can open the file, suppress the signature. - */ - if (apr_file_open(&f, rr->filename, APR_READ, - APR_OS_DEFAULT, r->pool) == APR_SUCCESS) { - do_emit_plain(r, f); - apr_file_close(f); - suppress_sig = 1; - } - } - } - } - - if (!suppress_sig) { - ap_rputs(ap_psignature("", r), r); - } - if (!suppress_post) { - ap_rputs("</BODY></HTML>\n", r); - } - if (rr != NULL) { - ap_destroy_sub_req(rr); - } -} - - -static char *find_title(request_rec *r) -{ - char titlebuf[MAX_STRING_LEN], *find = "<TITLE>"; - apr_file_t *thefile = NULL; - int x, y, p; - apr_size_t n; - - if (r->status != HTTP_OK) { - return NULL; - } - if ((r->content_type != NULL) - && (!strcasecmp(ap_field_noparam(r->pool, r->content_type), - "text/html") - || !strcmp(r->content_type, INCLUDES_MAGIC_TYPE)) - && !r->content_encoding) { - if (apr_file_open(&thefile, r->filename, APR_READ, - APR_OS_DEFAULT, r->pool) != APR_SUCCESS) { - return NULL; - } - n = sizeof(char) * (MAX_STRING_LEN - 1); - apr_file_read(thefile, titlebuf, &n); - if (n <= 0) { - apr_file_close(thefile); - return NULL; - } - titlebuf[n] = '\0'; - for (x = 0, p = 0; titlebuf[x]; x++) { - if (apr_toupper(titlebuf[x]) == find[p]) { - if (!find[++p]) { - if ((p = ap_ind(&titlebuf[++x], '<')) != -1) { - titlebuf[x + p] = '\0'; - } - /* Scan for line breaks for Tanmoy's secretary */ - for (y = x; titlebuf[y]; y++) { - if ((titlebuf[y] == CR) || (titlebuf[y] == LF)) { - if (y == x) { - x++; - } - else { - titlebuf[y] = ' '; - } - } - } - apr_file_close(thefile); - return apr_pstrdup(r->pool, &titlebuf[x]); - } - } - else { - p = 0; - } - } - apr_file_close(thefile); - } - return NULL; -} - -static struct ent *make_autoindex_entry(const char *name, int autoindex_opts, - autoindex_config_rec *d, - request_rec *r, char keyid, - char direction) -{ - struct ent *p; - - if ((name[0] == '.') && (!name[1])) { - return (NULL); - } - - if (ignore_entry(d, ap_make_full_path(r->pool, r->filename, name))) { - return (NULL); - } - - p = (struct ent *) apr_pcalloc(r->pool, sizeof(struct ent)); - p->name = apr_pstrdup(r->pool, name); - p->size = -1; - p->icon = NULL; - p->alt = NULL; - p->desc = NULL; - p->lm = -1; - p->key = apr_toupper(keyid); - p->ascending = (apr_toupper(direction) == D_ASCENDING); - p->version_sort = autoindex_opts & VERSION_SORT; - - if (autoindex_opts & FANCY_INDEXING) { - request_rec *rr = ap_sub_req_lookup_file(name, r, NULL); - - if (rr->finfo.filetype != 0) { - p->lm = rr->finfo.mtime; - if (rr->finfo.filetype == APR_DIR) { - if (!(p->icon = find_icon(d, rr, 1))) { - p->icon = find_default_icon(d, "^^DIRECTORY^^"); - } - if (!(p->alt = find_alt(d, rr, 1))) { - p->alt = "DIR"; - } - p->size = -1; - p->name = apr_pstrcat(r->pool, name, "/", NULL); - } - else { - p->icon = find_icon(d, rr, 0); - p->alt = find_alt(d, rr, 0); - p->size = rr->finfo.size; - } - } - - p->desc = find_desc(d, rr); - - if ((!p->desc) && (autoindex_opts & SCAN_HTML_TITLES)) { - p->desc = apr_pstrdup(r->pool, find_title(rr)); - } - - ap_destroy_sub_req(rr); - } - /* - * We don't need to take any special action for the file size key. If - * we did, it would go here. - */ - if (keyid == K_LAST_MOD) { - if (p->lm < 0) { - p->lm = 0; - } - } - return (p); -} - -static char *terminate_description(autoindex_config_rec *d, char *desc, - int autoindex_opts) -{ - int maxsize = 23; - register int x; - - if (autoindex_opts & SUPPRESS_LAST_MOD) { - maxsize += 19; - } - if (autoindex_opts & SUPPRESS_SIZE) { - maxsize += 7; - } - - for (x = 0; desc[x] && (maxsize > 0 || desc[x]=='<'); x++) { - if (desc[x] == '<') { - while (desc[x] != '>') { - if (!desc[x]) { - maxsize = 0; - break; - } - ++x; - } - } - else if (desc[x] == '&') { - /* entities like ä count as one character */ - --maxsize; - for ( ; desc[x] != ';'; ++x) { - if (desc[x] == '\0') { - maxsize = 0; - break; - } - } - } - else { - --maxsize; - } - } - if (!maxsize && desc[x] != '\0') { - desc[x - 1] = '>'; /* Grump. */ - desc[x] = '\0'; /* Double Grump! */ - } - return desc; -} - -/* - * Emit the anchor for the specified field. If a field is the key for the - * current request, the link changes its meaning to reverse the order when - * selected again. Non-active fields always start in ascending order. - */ -static void emit_link(request_rec *r, char *anchor, char fname, char curkey, - char curdirection, int nosort) -{ - char qvalue[5]; - int reverse; - - if (!nosort) { - qvalue[0] = '?'; - qvalue[1] = fname; - qvalue[2] = '='; - qvalue[4] = '\0'; - reverse = ((curkey == fname) && (curdirection == D_ASCENDING)); - qvalue[3] = reverse ? D_DESCENDING : D_ASCENDING; - ap_rvputs(r, "<A HREF=\"", qvalue, "\">", anchor, "</A>", NULL); - } - else { - ap_rputs(anchor, r); - } -} - -static void output_directories(struct ent **ar, int n, - autoindex_config_rec *d, request_rec *r, - int autoindex_opts, char keyid, char direction) -{ - int x; - apr_size_t rv; - char *name = r->uri; - char *tp; - int static_columns = (autoindex_opts & SUPPRESS_COLSORT); - apr_pool_t *scratch; - int name_width; - char *name_scratch; - char *pad_scratch; - - apr_pool_create(&scratch, r->pool); - if (name[0] == '\0') { - name = "/"; - } - - name_width = d->name_width; - if (d->name_adjust == K_ADJUST) { - for (x = 0; x < n; x++) { - int t = strlen(ar[x]->name); - if (t > name_width) { - name_width = t; - } - } - } - name_scratch = apr_palloc(r->pool, name_width + 1); - pad_scratch = apr_palloc(r->pool, name_width + 1); - memset(pad_scratch, ' ', name_width); - pad_scratch[name_width] = '\0'; - - if (autoindex_opts & FANCY_INDEXING) { - ap_rputs("<PRE>", r); - if ((tp = find_default_icon(d, "^^BLANKICON^^"))) { - ap_rvputs(r, "<IMG SRC=\"", ap_escape_html(scratch, tp), - "\" ALT=\" \"", NULL); - if (d->icon_width && d->icon_height) { - ap_rprintf - ( - r, - " HEIGHT=\"%d\" WIDTH=\"%d\"", - d->icon_height, - d->icon_width - ); - } - ap_rputs("> ", r); - } - emit_link(r, "Name", K_NAME, keyid, direction, static_columns); - ap_rputs(pad_scratch + 4, r); - /* - * Emit the guaranteed-at-least-one-space-between-columns byte. - */ - ap_rputs(" ", r); - if (!(autoindex_opts & SUPPRESS_LAST_MOD)) { - emit_link(r, "Last modified", K_LAST_MOD, keyid, direction, - static_columns); - ap_rputs(" ", r); - } - if (!(autoindex_opts & SUPPRESS_SIZE)) { - emit_link(r, "Size", K_SIZE, keyid, direction, static_columns); - ap_rputs(" ", r); - } - if (!(autoindex_opts & SUPPRESS_DESC)) { - emit_link(r, "Description", K_DESC, keyid, direction, - static_columns); - } - ap_rputs("\n<HR>\n", r); - } - else { - ap_rputs("<UL>", r); - } - - for (x = 0; x < n; x++) { - char *anchor, *t, *t2; - int nwidth; - - apr_pool_clear(scratch); - - if (is_parent(ar[x]->name)) { - t = ap_make_full_path(scratch, name, "../"); - ap_getparents(t); - if (t[0] == '\0') { - t = "/"; - } - t2 = "Parent Directory"; - anchor = ap_escape_html(scratch, ap_os_escape_path(scratch, t, 0)); - } - else { - t = ar[x]->name; - t2 = t; - anchor = ap_escape_html(scratch, ap_os_escape_path(scratch, t, 0)); - } - - if (autoindex_opts & FANCY_INDEXING) { - if (autoindex_opts & ICONS_ARE_LINKS) { - ap_rvputs(r, "<A HREF=\"", anchor, "\">", NULL); - } - if ((ar[x]->icon) || d->default_icon) { - ap_rvputs(r, "<IMG SRC=\"", - ap_escape_html(scratch, - ar[x]->icon ? ar[x]->icon - : d->default_icon), - "\" ALT=\"[", (ar[x]->alt ? ar[x]->alt : " "), - "]\"", NULL); - if (d->icon_width && d->icon_height) { - ap_rprintf(r, " HEIGHT=\"%d\" WIDTH=\"%d\"", - d->icon_height, d->icon_width); - } - ap_rputs(">", r); - } - if (autoindex_opts & ICONS_ARE_LINKS) { - ap_rputs("</A>", r); - } - - nwidth = strlen(t2); - if (nwidth > name_width) { - memcpy(name_scratch, t2, name_width - 3); - name_scratch[name_width - 3] = '.'; - name_scratch[name_width - 2] = '.'; - name_scratch[name_width - 1] = '>'; - name_scratch[name_width] = 0; - t2 = name_scratch; - nwidth = name_width; - } - ap_rvputs(r, " <A HREF=\"", anchor, "\">", - ap_escape_html(scratch, t2), "</A>", pad_scratch + nwidth, - NULL); - /* - * The blank before the storm.. er, before the next field. - */ - ap_rputs(" ", r); - if (!(autoindex_opts & SUPPRESS_LAST_MOD)) { - if (ar[x]->lm != -1) { - char time_str[MAX_STRING_LEN]; - apr_exploded_time_t ts; - apr_explode_localtime(&ts, ar[x]->lm); - apr_strftime(time_str, &rv, MAX_STRING_LEN, - "%d-%b-%Y %H:%M ", &ts); - ap_rputs(time_str, r); - } - else { - /*Length="22-Feb-1998 23:42 " (see 4 lines above) */ - ap_rputs(" ", r); - } - } - if (!(autoindex_opts & SUPPRESS_SIZE)) { - ap_send_size(ar[x]->size, r); - ap_rputs(" ", r); - } - if (!(autoindex_opts & SUPPRESS_DESC)) { - if (ar[x]->desc) { - ap_rputs(terminate_description(d, ar[x]->desc, - autoindex_opts), r); - } - } - } - else { - ap_rvputs(r, "<LI><A HREF=\"", anchor, "\"> ", t2, - "</A>", NULL); - } - ap_rputc('\n', r); - } - if (autoindex_opts & FANCY_INDEXING) { - ap_rputs("</PRE>", r); - } - else { - ap_rputs("</UL>", r); - } -} - -/* - * Compare two file entries according to the sort criteria. The return - * is essentially a signum function value. - */ - -static int dsortf(struct ent **e1, struct ent **e2) -{ - struct ent *c1; - struct ent *c2; - int result = 0; - - /* - * First, see if either of the entries is for the parent directory. - * If so, that *always* sorts lower than anything else. - */ - if (is_parent((*e1)->name)) { - return -1; - } - if (is_parent((*e2)->name)) { - return 1; - } - /* - * All of our comparisons will be of the c1 entry against the c2 one, - * so assign them appropriately to take care of the ordering. - */ - if ((*e1)->ascending) { - c1 = *e1; - c2 = *e2; - } - else { - c1 = *e2; - c2 = *e1; - } - - switch (c1->key) { - case K_LAST_MOD: - if (c1->lm > c2->lm) { - return 1; - } - else if (c1->lm < c2->lm) { - return -1; - } - break; - case K_SIZE: - if (c1->size > c2->size) { - return 1; - } - else if (c1->size < c2->size) { - return -1; - } - break; - case K_DESC: - if (c1->version_sort) - result = apr_strnatcmp(c1->desc ? c1->desc : "", c2->desc ? c2->desc : ""); - else - result = strcmp(c1->desc ? c1->desc : "", c2->desc ? c2->desc : ""); - if (result) { - return result; - } - break; - } - if (c1->version_sort) - return apr_strnatcmp(c1->name, c2->name); - else - return strcmp(c1->name, c2->name); -} - - -static int index_directory(request_rec *r, - autoindex_config_rec *autoindex_conf) -{ - char *title_name = ap_escape_html(r->pool, r->uri); - char *title_endp; - char *name = r->filename; - apr_finfo_t dirent; - apr_dir_t *thedir; - apr_status_t status; - int num_ent = 0, x; - struct ent *head, *p; - struct ent **ar = NULL; - const char *qstring; - int autoindex_opts = autoindex_conf->opts; - char keyid; - char direction; - - if ((status = apr_dir_open(&thedir, name, r->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, - "Can't open directory for index: %s", r->filename); - return HTTP_FORBIDDEN; - } - -#if APR_HAS_UNICODE_FS - r->content_type = "text/html;charset=utf-8"; -#else - r->content_type = "text/html"; -#endif - ap_update_mtime(r, r->finfo.mtime); - ap_set_last_modified(r); - ap_set_etag(r); - - if (r->header_only) { - apr_dir_close(thedir); - return 0; - } - - /* Spew HTML preamble */ - - title_endp = title_name + strlen(title_name) - 1; - - while (title_endp > title_name && *title_endp == '/') { - *title_endp-- = '\0'; - } - - emit_head(r, find_header(autoindex_conf, r), - autoindex_opts & SUPPRESS_PREAMBLE, title_name); - - /* - * Figure out what sort of indexing (if any) we're supposed to use. - * - * If no QUERY_STRING was specified or column sorting has been - * explicitly disabled, we use the default specified by the - * IndexOrderDefault directive (if there is one); otherwise, - * we fall back to ascending by name. - */ - qstring = r->args; - if ((autoindex_opts & SUPPRESS_COLSORT) - || ((qstring == NULL) || (*qstring == '\0'))) { - qstring = autoindex_conf->default_order; - } - /* - * If there is no specific ordering defined for this directory, - * default to ascending by filename. - */ - if ((qstring == NULL) || (*qstring == '\0')) { - keyid = K_NAME; - direction = D_ASCENDING; - } - else { - keyid = *qstring; - ap_getword(r->pool, &qstring, '='); - if (qstring != '\0') { - direction = *qstring; - } - else { - direction = D_ASCENDING; - } - } - - /* - * Since we don't know how many dir. entries there are, put them into a - * linked list and then arrayificate them so qsort can use them. - */ - head = NULL; - while (apr_dir_read(&dirent, APR_FINFO_DIRENT, thedir) == APR_SUCCESS) { - p = make_autoindex_entry(dirent.name, autoindex_opts, - autoindex_conf, r, keyid, direction); - if (p != NULL) { - p->next = head; - head = p; - num_ent++; - } - } - if (num_ent > 0) { - ar = (struct ent **) apr_palloc(r->pool, - num_ent * sizeof(struct ent *)); - p = head; - x = 0; - while (p) { - ar[x++] = p; - p = p->next; - } - - qsort((void *) ar, num_ent, sizeof(struct ent *), - (int (*)(const void *, const void *)) dsortf); - } - output_directories(ar, num_ent, autoindex_conf, r, autoindex_opts, keyid, - direction); - apr_dir_close(thedir); - - if (autoindex_opts & FANCY_INDEXING) { - ap_rputs("<HR>\n", r); - } - emit_tail(r, find_readme(autoindex_conf, r), - autoindex_opts & SUPPRESS_PREAMBLE); - - return 0; -} - -/* The formal handler... */ - -static int handle_autoindex(request_rec *r) -{ - autoindex_config_rec *d; - int allow_opts; - - if(strcmp(r->handler,DIR_MAGIC_TYPE)) - return DECLINED; - - allow_opts = ap_allow_options(r); - - d = (autoindex_config_rec *) ap_get_module_config(r->per_dir_config, - &autoindex_module); - - r->allowed |= (1 << M_GET); - if (r->method_number != M_GET) { - return DECLINED; - } - - /* OK, nothing easy. Trot out the heavy artillery... */ - - if (allow_opts & OPT_INDEXES) { - /* KLUDGE --- make the sub_req lookups happen in the right directory. - * Fixing this in the sub_req_lookup functions themselves is difficult, - * and would probably break virtual includes... - */ - - if (r->filename[strlen(r->filename) - 1] != '/') { - r->filename = apr_pstrcat(r->pool, r->filename, "/", NULL); - } - return index_directory(r, d); - } - else { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Directory index forbidden by rule: %s", r->filename); - return HTTP_FORBIDDEN; - } -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_handler(handle_autoindex,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA autoindex_module = -{ - STANDARD20_MODULE_STUFF, - create_autoindex_config, /* dir config creater */ - merge_autoindex_configs, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - autoindex_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/test/mod_autoindex.exp b/modules/test/mod_autoindex.exp deleted file mode 100644 index 90f4057e9c..0000000000 --- a/modules/test/mod_autoindex.exp +++ /dev/null @@ -1 +0,0 @@ -autoindex_module diff --git a/modules/test/mod_optional_fn_export.c b/modules/test/mod_optional_fn_export.c deleted file mode 100644 index b214a36621..0000000000 --- a/modules/test/mod_optional_fn_export.c +++ /dev/null @@ -1,86 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "mod_optional_fn_export.h" - -/* The alert will note a strange mirror-image style resemblance to - * mod_generic_hook_import.c. Yes, I _did_ mean import. Think about it. - */ - -static int TestOptionalFn(const char *szStr) -{ - ap_log_error(APLOG_MARK,APLOG_ERR,OK,NULL, - "Optional function test said: %s",szStr); - - return OK; -} - -static void ExportRegisterHooks(apr_pool_t *p) -{ - APR_REGISTER_OPTIONAL_FN(TestOptionalFn); -} - -module optional_fn_export_module= -{ - STANDARD20_MODULE_STUFF, - NULL, - NULL, - NULL, - NULL, - NULL, - ExportRegisterHooks -}; diff --git a/modules/test/mod_optional_fn_export.h b/modules/test/mod_optional_fn_export.h deleted file mode 100644 index a1950f373b..0000000000 --- a/modules/test/mod_optional_fn_export.h +++ /dev/null @@ -1,3 +0,0 @@ -#include "apr_optional.h" - -APR_DECLARE_OPTIONAL_FN(int,TestOptionalFn,(const char *)); diff --git a/modules/test/mod_optional_fn_import.c b/modules/test/mod_optional_fn_import.c deleted file mode 100644 index 3be3b6be6d..0000000000 --- a/modules/test/mod_optional_fn_import.c +++ /dev/null @@ -1,93 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "httpd.h" -#include "http_config.h" -#include "mod_optional_fn_export.h" -#include "http_protocol.h" - -/* The alert will note a strange mirror-image style resemblance to - * mod_generic_hook_export.c. Yes, I _did_ mean export. Think about it. - */ - -static APR_OPTIONAL_FN_TYPE(TestOptionalFn) *pfn; - -static int ImportLogTransaction(request_rec *r) -{ - if(pfn) - return pfn(r->the_request); - return DECLINED; -} - -static void ImportFnRetrieve(void) -{ - pfn=APR_RETRIEVE_OPTIONAL_FN(TestOptionalFn); -} - -static void ImportRegisterHooks(apr_pool_t *p) -{ - ap_hook_log_transaction(ImportLogTransaction,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_optional_fn_retrieve(ImportFnRetrieve,NULL,NULL,APR_HOOK_MIDDLE); -} - -module optional_fn_import_module = -{ - STANDARD20_MODULE_STUFF, - NULL, - NULL, - NULL, - NULL, - NULL, - ImportRegisterHooks -}; diff --git a/modules/test/mod_rndchunk.c b/modules/test/mod_rndchunk.c deleted file mode 100644 index 6eeae175ac..0000000000 --- a/modules/test/mod_rndchunk.c +++ /dev/null @@ -1,179 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * This module is intended to be used for testing chunked encoding. It - * generates a whole whack of output using ap_bputc() and ap_bputs(). It - * also exercises start_chunk() and end_chunk() in buff.c. To use it - * you should use a tool like netcat and the src/test/check_chunked - * tool. Add something like this to your access.conf file: - * - * <Location /rndchunk> - * SetHandler rndchunk - * </Location> - * - * Then fake requests such as: - * - * GET /rndchunk?0,1000000 HTTP/1.1 - * Host: localhost - * - * The first arg is the random seed, the second is the number of - * "things" to do. You should try a few seeds. - * - * You should also edit main/buff.c and change DEFAULT_BUFSIZE (and - * CHUNK_HEADER_SIZE). Small values are particularly useful for - * finding bugs. Try a few different values. - * - * -djg - */ - -#include "httpd.h" -#include "http_protocol.h" -#include "http_config.h" -#include "http_main.h" - -#define MAX_SEGMENT 32 -#define ONE_WEIGHT (256-32) - -static int send_rndchunk(request_rec *r) -{ - const char *args; - char *endptr; - unsigned int seed; - unsigned int count; - int i; - char buf[MAX_SEGMENT + 1]; - unsigned int len; - - r->allowed |= (1 << M_GET); - if (r->method_number != M_GET) - return DECLINED; - - r->content_type = "text/html"; - if(r->header_only) { - return 0; - } - ap_hard_timeout("send_rndchunk", r); - - if (!r->chunked) { - ap_rputs("Not chunked!", r); - ap_kill_timeout(r); - return 0; - } - - args = r->args; - if (!args) { -error: - ap_rputs("Must include args! ... of the form <code>?seed,count</code>", r); - ap_kill_timeout(r); - return 0; - } - seed = strtol(args, &endptr, 0); - if (!endptr || *endptr != ',') { - goto error; - } - ++endptr; - count = strtol(endptr, &endptr, 0); - - srandom(seed); - for (i = 0; i < count; ++i) { - len = random() % (MAX_SEGMENT + ONE_WEIGHT); - if (len >= MAX_SEGMENT) { - ap_rputc((i & 1) ? '0' : '1', r); - } - else if (len == 0) { - /* not a really nice thing to do, but we need to test - * beginning/ending chunks as well - */ - ap_bsetflag(r->connection->client, B_CHUNK, 0); - ap_bsetflag(r->connection->client, B_CHUNK, 1); - } - else { - memset(buf, '2' + len, len); - buf[len] = 0; - ap_rputs(buf, r); - } - } - ap_kill_timeout(r); - return 0; -} - -static const handler_rec rndchunk_handlers[] = -{ - {"rndchunk", send_rndchunk}, - {NULL} -}; - -module rndchunk_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - NULL, /* command apr_table_t */ - rndchunk_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 */ -}; diff --git a/modules/test/mod_test_util_uri.c b/modules/test/mod_test_util_uri.c deleted file mode 100644 index 5472243568..0000000000 --- a/modules/test/mod_test_util_uri.c +++ /dev/null @@ -1,354 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * This module is intended to test the util_uri routines by parsing a - * bunch of urls and comparing the results with what we expect to - * see. - * - * Usage: - * - * <Location /test-util-uri> - * SetHandler test-util-uri - * </Location> - * - * Then make a request to /test-util-uri. An html apr_table_t of errors will - * be output... and a total count of errors. - */ - -#include "httpd.h" -#include "http_protocol.h" -#include "http_config.h" -#include "http_main.h" - -typedef struct { - const char *scheme; - const char *user; - const char *password; - const char *hostname; - const char *port_str; - const char *path; - const char *query; - const char *fragment; -} test_uri_t; - -#define T_scheme 0x01 -#define T_user 0x02 -#define T_password 0x04 -#define T_hostname 0x08 -#define T_port_str 0x10 -#define T_path 0x20 -#define T_query 0x40 -#define T_fragment 0x80 -#define T_MAX 0x100 - -/* The idea is that we list here a bunch of url pieces that we want - * stitched together in every way that's valid. - */ -static const test_uri_t uri_tests[] = { - { "http", "userid", "passwd", "hostname.goes.here", "80", "/path/goes/here", "query-here", "frag-here" }, - { "http", "", "passwd", "hostname.goes.here", "80", "/path/goes/here", "query-here", "frag-here" }, - { "http", "userid", "", "hostname.goes.here", "80", "/path/goes/here", "query-here", "frag-here" }, - { "http", "userid", "passwd", "", "80", "/path/goes/here", "query-here", "frag-here" }, - { "http", "userid", "passwd", "hostname.goes.here", "", "/path/goes/here", "query-here", "frag-here" }, -#if 0 - /* An empty path means two different things depending on whether this is a - * relative or an absolute uri... consider <a href="#frag"> versus "GET - * http://hostname HTTP/1.1". So this is why parse_uri_components returns - * a NULL for path when it doesn't find one, instead of returning an empty - * string. - * - * We don't really need to test it explicitly since path has no explicit - * character that indicates its precense, and so we test empty paths all - * the time by varying T_path in the loop. It would just cost us extra - * code to special case the empty path string... - */ - { "http", "userid", "passwd", "hostname.goes.here", "80", "", "query-here", "frag-here" }, -#endif - { "http", "userid", "passwd", "hostname.goes.here", "80", "/path/goes/here", "", "frag-here" }, - { "http", "userid", "passwd", "hostname.goes.here", "80", "/path/goes/here", "query-here", "" }, - { "https", "user@d", "pa:swd", "hostname.goes.here.", "", "/~path/goes/here", "query&query?crud", "frag-here?baby" } - -}; - -static char *my_stpcpy(char *d, const char *s) -{ - while((*d = *s)) { - ++d; - ++s; - } - return d; -} - -/* return the number of failures */ -static unsigned iterate_pieces(request_rec *r, const test_uri_t *pieces, int row) -{ - unsigned u; - apr_pool_t *sub; - char *input_uri; - char *strp; - uri_components result; - unsigned expect; - int status; - unsigned failures; - - failures = 0; - - input_uri = apr_palloc(r->pool, - strlen(pieces->scheme) + 3 - + strlen(pieces->user) + 1 - + strlen(pieces->password) + 1 - + strlen(pieces->hostname) + 1 - + strlen(pieces->port_str) + 1 - + strlen(pieces->path) + - + strlen(pieces->query) + 1 - + strlen(pieces->fragment) + 1 - + 1); - - for (u = 0; u < T_MAX; ++u) { - strp = input_uri; - expect = 0; - - /* a scheme requires a hostinfo and vice versa */ - /* a hostinfo requires a hostname */ - if (u & (T_scheme|T_user|T_password|T_hostname|T_port_str)) { - expect |= T_scheme; - strp = my_stpcpy(strp, pieces->scheme); - *strp++ = ':'; - *strp++ = '/'; - *strp++ = '/'; - /* can't have password without user */ - if (u & (T_user|T_password)) { - expect |= T_user; - strp = my_stpcpy(strp, pieces->user); - if (u & T_password) { - expect |= T_password; - *strp++ = ':'; - strp = my_stpcpy(strp, pieces->password); - } - *strp++ = '@'; - } - expect |= T_hostname; - strp = my_stpcpy(strp, pieces->hostname); - if (u & T_port_str) { - expect |= T_port_str; - *strp++ = ':'; - strp = my_stpcpy(strp, pieces->port_str); - } - } - if (u & T_path) { - expect |= T_path; - strp = my_stpcpy(strp, pieces->path); - } - if (u & T_query) { - expect |= T_query; - *strp++ = '?'; - strp = my_stpcpy(strp, pieces->query); - } - if (u & T_fragment) { - expect |= T_fragment; - *strp++ = '#'; - strp = my_stpcpy(strp, pieces->fragment); - } - *strp = 0; - - sub = apr_pool_sub_make(r->pool); - status = ap_parse_uri_components(sub, input_uri, &result); - if (status == HTTP_OK) { -#define CHECK(f) \ - if ((expect & T_##f) \ - && (result.f == NULL || strcmp(result.f, pieces->f))) { \ - status = HTTP_INTERNAL_SERVER_ERROR; \ - } \ - else if (!(expect & T_##f) && result.f != NULL) { \ - status = HTTP_INTERNAL_SERVER_ERROR; \ - } - CHECK(scheme) - CHECK(user) - CHECK(password) - CHECK(hostname) - CHECK(port_str) - CHECK(path) - CHECK(query) - CHECK(fragment) -#undef CHECK - } - if (status != HTTP_OK) { - ap_rprintf(r, "<tr><td>%d</td><td>0x%02x</td><td>0x%02x</td><td>%d</td><td>\"%s\"</td>", row, u, expect, status, input_uri); -#define DUMP(f) \ - if (result.f) { \ - ap_rvputs(r, "<td>\"", result.f, "\"<br>", NULL); \ - } \ - else { \ - ap_rputs("<td>NULL<br>", r); \ - } \ - if (expect & T_##f) { \ - ap_rvputs(r, "\"", pieces->f, "\"</td>", NULL); \ - } \ - else { \ - ap_rputs("NULL</td>", r); \ - } - DUMP(scheme); - DUMP(user); - DUMP(password); - DUMP(hostname); - DUMP(port_str); - DUMP(path); - DUMP(query); - DUMP(fragment); -#undef DUMP - ap_rputs("</tr>\n", r); - ++failures; - } - apr_pool_destroy(sub); - } - return failures; -} - -static int test_util_uri(request_rec *r) -{ - unsigned total_failures; - int i; - - r->allowed |= (1 << M_GET); - if (r->method_number != M_GET) - return DECLINED; - - r->content_type = "text/html"; - if(r->header_only) { - return 0; - } - ap_hard_timeout("test_util_uri", r); - - ap_rputs( -DOCTYPE_HTML_2_0 " -<html><body> -<p>Key: -<dl> -<dt>row -<dd>entry number in the uri_tests array -<dt>u -<dd>fields under test -<dt>expected -<dd>fields expected in the result -<dt>status -<dd>response from parse_uri_components, or 500 if unexpected results -<dt>input uri -<dd>the uri given to parse_uri_components -</dl> -<p>The remaining fields are the pieces returned from parse_uri_components, and -the values we expected for each piece (resp.). -<p>Only failures are displayed. -<p> -<table><tr><th>row</th><th>u</th><th>expect</th><th>status</th><th>input uri</th>", r); -#define HEADER(f) ap_rprintf(r, "<th>" #f "<br>0x%02x</th>", T_##f) - HEADER(scheme); - HEADER(user); - HEADER(password); - HEADER(hostname); - HEADER(port_str); - HEADER(path); - HEADER(query); - HEADER(fragment); -#undef HEADER - - if (r->args) { - i = atoi(r->args); - total_failures = iterate_pieces(r, &uri_tests[i], i); - } - else { - total_failures = 0; - for (i = 0; i < sizeof(uri_tests) / sizeof(uri_tests[0]); ++i) { - total_failures += iterate_pieces(r, &uri_tests[i], i); - if (total_failures > 256) { - ap_rprintf(r, "</table>\n<b>Stopped early to save your browser " - "from certain death!</b>\nTOTAL FAILURES = %u\n", - total_failures); - return OK; - } - } - } - ap_rprintf(r, "</table>\nTOTAL FAILURES = %u\n", total_failures); - - return OK; -} - -static const handler_rec test_util_uri_handlers[] = -{ - {"test-util-uri", test_util_uri}, - {NULL} -}; - -module test_util_uri_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - NULL, /* command apr_table_t */ - test_util_uri_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 */ -}; diff --git a/modules/tls/.cvsignore b/modules/tls/.cvsignore deleted file mode 100644 index 239bc29765..0000000000 --- a/modules/tls/.cvsignore +++ /dev/null @@ -1,6 +0,0 @@ -.libs -.deps -Makefile -modules.mk -*.lo -*.la diff --git a/modules/tls/Makefile.in b/modules/tls/Makefile.in deleted file mode 100644 index d8187ddf06..0000000000 --- a/modules/tls/Makefile.in +++ /dev/null @@ -1,2 +0,0 @@ -include $(top_srcdir)/build/special.mk - diff --git a/modules/tls/README b/modules/tls/README deleted file mode 100644 index 064ce839fe..0000000000 --- a/modules/tls/README +++ /dev/null @@ -1,20 +0,0 @@ -This currently won't work with Apache unaided. The manual things I -have to do to make it work are: - -To configure this module you must use: - ---enable-tls ---with-ssl=/path/to/ssl/library - -For example: - ---enable-tls ---with-ssl=/home/rbb/openssl-0.9.6 - -NOTE: You must be using OpenSSL 0.9.6 or later in order for this to work. - -Then all you need is "TLSFilter on" and "TLSCertificateFile <file>" in -your config, and you are away (note that the cert file must also -contain the private key at present). - -Ben Laurie, 11 Feb 2001. diff --git a/modules/tls/config.m4 b/modules/tls/config.m4 deleted file mode 100644 index 2ecee966e0..0000000000 --- a/modules/tls/config.m4 +++ /dev/null @@ -1,43 +0,0 @@ -AC_MSG_CHECKING(for SSL library) -APACHE_MODPATH_INIT(tls) - -tls_objs="mod_tls.lo openssl_state_machine.lo" - -APACHE_MODULE(tls, TLS/SSL support, $tls_objs, , no, [ - AC_ARG_WITH(ssl, [ --with-ssl use a specific SSL library installation ], - [ - searchfile="$withval/inc/ssl.h" - if test -f $searchfile ; then - APR_ADDTO(INCLUDES, [-I$withval/inc]) - APR_ADDTO(LIBS, [-L$withval -lsslc]) - ssl_lib="SSLC" - else - searchfile="$withval/ssl/ssl.h" - if test -f $searchfile ; then - APR_ADDTO(INCLUDES, [-I$withval/include]) - APR_ADDTO(LIBS, [-L$withval -lssl -lcrypto]) - ssl_lib="OpenSSL" - else - searchfile="$withval/openssl/ssl.h" - if test -f $searchfile ; then - APR_ADDTO(INCLUDES, [-I$withval/openssl]) - APR_ADDTO(LIBS, [-L$withval -lssl -lcrypto]) - ssl_lib="OpenSSL" - else - searchfile="$withval/include/openssl/ssl.h" - if test -f $searchfile ; then - APR_ADDTO(INCLUDES, [-I$withval/include]) - APR_ADDTO(LIBS, [-L$withval/lib -lssl -lcrypto]) - ssl_lib="OpenSSL" - else - AC_MSG_ERROR(no - Unable to locate $withval/inc/ssl.h) - fi - fi - fi - fi - AC_MSG_RESULT(found $ssl_lib) - ],[ - AC_MSG_ERROR(--with-ssl not given) - ] ) ] ) - -APACHE_MODPATH_FINISH diff --git a/modules/tls/mod_tls.c b/modules/tls/mod_tls.c deleted file mode 100644 index 2fd8cc75d3..0000000000 --- a/modules/tls/mod_tls.c +++ /dev/null @@ -1,417 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "httpd.h" -#include "http_config.h" -#include "util_filter.h" -#include "http_connection.h" -#include "openssl_state_machine.h" -#include "apr_strings.h" -#include "http_protocol.h" -#include "http_log.h" - -/* temp */ -#include <assert.h> - -module AP_MODULE_DECLARE_DATA tls_module; -static const char s_szTLSFilterName[]="TLSFilter"; -typedef struct -{ - int bEnabled; - const char *szCertificateFile; - const char *szKeyFile; -} TLSServerConfig; - -typedef struct -{ - SSLStateMachine *pStateMachine; - ap_filter_t *pInputFilter; - ap_filter_t *pOutputFilter; - apr_bucket_brigade *pbbInput; /* encrypted input */ - apr_bucket_brigade *pbbPendingInput; /* decrypted input */ -} TLSFilterCtx; - -static void *create_tls_server_config(apr_pool_t *p, server_rec *s) -{ - TLSServerConfig *pConfig = apr_pcalloc(p, sizeof *pConfig); - - pConfig->bEnabled = 0; - pConfig->szCertificateFile = pConfig->szKeyFile = NULL; - - return pConfig; -} - -static const char *tls_on(cmd_parms *cmd, void *dummy, int arg) -{ - TLSServerConfig *pConfig = ap_get_module_config(cmd->server->module_config, - &tls_module); - pConfig->bEnabled = arg; - - return NULL; -} - -static const char *tls_cert_file(cmd_parms *cmd, void *dummy, const char *arg) -{ - TLSServerConfig *pConfig = ap_get_module_config(cmd->server->module_config, - &tls_module); - pConfig->szCertificateFile = ap_server_root_relative(cmd->pool, arg); - - /* temp */ - pConfig->szKeyFile=pConfig->szCertificateFile; - - return NULL; -} - -static int tls_filter_inserter(conn_rec *c) -{ - TLSServerConfig *pConfig = - ap_get_module_config(c->base_server->module_config, - &tls_module); - TLSFilterCtx *pCtx; - - if (!pConfig->bEnabled) - return DECLINED; - - pCtx=apr_pcalloc(c->pool,sizeof *pCtx); - pCtx->pStateMachine=SSLStateMachine_new(pConfig->szCertificateFile, - pConfig->szKeyFile); - - pCtx->pInputFilter=ap_add_input_filter(s_szTLSFilterName,pCtx,NULL,c); - pCtx->pOutputFilter=ap_add_output_filter(s_szTLSFilterName,pCtx,NULL,c); - pCtx->pbbInput=apr_brigade_create(c->pool); - pCtx->pbbPendingInput=apr_brigade_create(c->pool); - - return OK; -} - -static apr_status_t churn_output(TLSFilterCtx *pCtx) -{ - apr_bucket_brigade *pbbOutput=NULL; - int done; - - do { - char buf[1024]; - int n; - apr_bucket *pbkt; - - done=0; - - if(SSLStateMachine_write_can_extract(pCtx->pStateMachine)) { - n=SSLStateMachine_write_extract(pCtx->pStateMachine,buf, - sizeof buf); - if(n > 0) { - char *pbuf; - - if(!pbbOutput) - pbbOutput=apr_brigade_create(pCtx->pOutputFilter->c->pool); - - pbuf=apr_pmemdup(pCtx->pOutputFilter->c->pool,buf,n); - pbkt=apr_bucket_pool_create(pbuf,n, - pCtx->pOutputFilter->c->pool); - APR_BRIGADE_INSERT_TAIL(pbbOutput,pbkt); - done=1; - /* } else if(n == 0) { - apr_bucket *pbktEOS=apr_bucket_create_eos(); - APR_BRIGADE_INSERT_TAIL(pbbOutput,pbktEOS);*/ - } - assert(n > 0); - } - } while(done); - - /* XXX: check for errors */ - if(pbbOutput) { - apr_bucket *pbkt; - - /* XXX: it may be possible to not always flush */ - pbkt=apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(pbbOutput,pbkt); - ap_pass_brigade(pCtx->pOutputFilter->next,pbbOutput); - } - - return APR_SUCCESS; -} - -static apr_status_t churn(TLSFilterCtx *pCtx,apr_read_type_e eReadType,apr_size_t *readbytes) -{ - ap_input_mode_t eMode=eReadType == APR_BLOCK_READ ? AP_MODE_BLOCKING - : AP_MODE_NONBLOCKING; - apr_bucket *pbktIn; - - if(APR_BRIGADE_EMPTY(pCtx->pbbInput)) { - ap_get_brigade(pCtx->pInputFilter->next,pCtx->pbbInput,eMode,readbytes); - if(APR_BRIGADE_EMPTY(pCtx->pbbInput)) - return APR_EOF; - } - - APR_BRIGADE_FOREACH(pbktIn,pCtx->pbbInput) { - const char *data; - apr_size_t len; - int n; - char buf[1024]; - apr_status_t ret; - - if(APR_BUCKET_IS_EOS(pbktIn)) { - /* XXX: why can't I reuse pbktIn??? */ - /* Write eof! */ - break; - } - - /* read filter */ - ret=apr_bucket_read(pbktIn,&data,&len,eReadType); - - APR_BUCKET_REMOVE(pbktIn); - - if(ret == APR_SUCCESS && len == 0 && eReadType == APR_BLOCK_READ) - ret=APR_EOF; - - if(len == 0) { - /* Lazy frickin browsers just reset instead of shutting down. */ - if(ret == APR_EOF || ret == APR_ECONNRESET) { - if(APR_BRIGADE_EMPTY(pCtx->pbbPendingInput)) - return APR_EOF; - else - /* Next time around, the incoming brigade will be empty, - * so we'll return EOF then - */ - return APR_SUCCESS; - } - - if(eReadType != APR_NONBLOCK_READ) - ap_log_error(APLOG_MARK,APLOG_ERR,ret,NULL, - "Read failed in tls_in_filter"); - assert(eReadType == APR_NONBLOCK_READ); - assert(ret == APR_SUCCESS || APR_STATUS_IS_EAGAIN(ret)); - /* In this case, we have data in the output bucket, or we were - * non-blocking, so returning nothing is fine. - */ - return APR_SUCCESS; - } - - assert(len > 0); - - /* write SSL */ - SSLStateMachine_read_inject(pCtx->pStateMachine,data,len); - - n=SSLStateMachine_read_extract(pCtx->pStateMachine,buf,sizeof buf); - if(n > 0) { - apr_bucket *pbktOut; - char *pbuf; - - pbuf=apr_pmemdup(pCtx->pInputFilter->c->pool,buf,n); - /* XXX: should we use a heap bucket instead? Or a transient (in - * which case we need a separate brigade for each bucket)? - */ - pbktOut=apr_bucket_pool_create(pbuf,n,pCtx->pInputFilter->c->pool); - APR_BRIGADE_INSERT_TAIL(pCtx->pbbPendingInput,pbktOut); - - /* Once we've read something, we can move to non-blocking mode (if - * we weren't already). - */ - eReadType=APR_NONBLOCK_READ; - - /* XXX: deal with EOF! */ - /* } else if(n == 0) { - apr_bucket *pbktEOS=apr_bucket_create_eos(); - APR_BRIGADE_INSERT_TAIL(pbbInput,pbktEOS);*/ - } - assert(n >= 0); - - ret=churn_output(pCtx); - if(ret != APR_SUCCESS) - return ret; - } - - return churn_output(pCtx); -} - -static apr_status_t tls_out_filter(ap_filter_t *f,apr_bucket_brigade *pbbIn) -{ - TLSFilterCtx *pCtx=f->ctx; - apr_bucket *pbktIn; - apr_size_t zero = 0; - - APR_BRIGADE_FOREACH(pbktIn,pbbIn) { - const char *data; - apr_size_t len; - apr_status_t ret; - - if(APR_BUCKET_IS_EOS(pbktIn)) { - /* XXX: demote to debug */ - ap_log_error(APLOG_MARK,APLOG_ERR,0,NULL,"Got EOS on output"); - SSLStateMachine_write_close(pCtx->pStateMachine); - /* XXX: dubious - does this always terminate? Does it return the right thing? */ - for( ; ; ) { - ret=churn_output(pCtx); - if(ret != APR_SUCCESS) - return ret; - ret=churn(pCtx,APR_NONBLOCK_READ,&zero); - if(ret != APR_SUCCESS) { - if(ret == APR_EOF) - return APR_SUCCESS; - else - return ret; - } - } - break; - } - - if(APR_BUCKET_IS_FLUSH(pbktIn)) { - /* assume that churn will flush (or already has) if there's output */ - ret=churn(pCtx,APR_NONBLOCK_READ,&zero); - if(ret != APR_SUCCESS) - return ret; - continue; - } - - /* read filter */ - apr_bucket_read(pbktIn,&data,&len,APR_BLOCK_READ); - - /* write SSL */ - SSLStateMachine_write_inject(pCtx->pStateMachine,data,len); - - /* churn the state machine */ - ret=churn_output(pCtx); - if(ret != APR_SUCCESS) - return ret; - } - - return APR_SUCCESS; -} - -static apr_status_t tls_in_filter(ap_filter_t *f,apr_bucket_brigade *pbbOut, - ap_input_mode_t eMode, apr_size_t *readbytes) -{ - TLSFilterCtx *pCtx=f->ctx; - apr_read_type_e eReadType=eMode == AP_MODE_BLOCKING ? APR_BLOCK_READ : - APR_NONBLOCK_READ; - apr_status_t ret; - - /* XXX: we don't currently support peek */ - assert(eMode != AP_MODE_PEEK); - - /* churn the state machine */ - ret=churn(pCtx,eReadType,readbytes); - if(ret != APR_SUCCESS) - return ret; - - /* XXX: shame that APR_BRIGADE_FOREACH doesn't work here */ - while(!APR_BRIGADE_EMPTY(pCtx->pbbPendingInput)) { - apr_bucket *pbktIn=APR_BRIGADE_FIRST(pCtx->pbbPendingInput); - APR_BUCKET_REMOVE(pbktIn); - APR_BRIGADE_INSERT_TAIL(pbbOut,pbktIn); - } - - return APR_SUCCESS; -} - -static const char *tls_method(const request_rec *r) -{ - TLSServerConfig *pConfig = - ap_get_module_config(r->connection->base_server->module_config, - &tls_module); - - if (!pConfig->bEnabled) - return NULL; - - return "https"; -} - -static unsigned short tls_port(const request_rec *r) -{ - TLSServerConfig *pConfig = - ap_get_module_config(r->connection->base_server->module_config, - &tls_module); - - if (!pConfig->bEnabled) - return 0; - - return 443; -} - -static const command_rec tls_cmds[] = -{ - /* XXX: We should be able to add the filter using AddOutputFilter */ - AP_INIT_FLAG("TLSFilter", tls_on, NULL, RSRC_CONF, - "Run TLS/SSL on this host"), - AP_INIT_TAKE1("TLSCertificateFile", tls_cert_file, NULL, RSRC_CONF, - "Set the certificate file for this host"), - { NULL } -}; - -static void register_hooks(apr_pool_t *p) -{ - SSLStateMachine_init(); - - ap_register_output_filter(s_szTLSFilterName,tls_out_filter, - AP_FTYPE_NETWORK); - ap_register_input_filter(s_szTLSFilterName,tls_in_filter, - AP_FTYPE_NETWORK); - ap_hook_pre_connection(tls_filter_inserter,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_default_port(tls_port,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_http_method(tls_method,NULL,NULL,APR_HOOK_MIDDLE); -} - -module AP_MODULE_DECLARE_DATA tls_module = { - STANDARD20_MODULE_STUFF, - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - create_tls_server_config, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - tls_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/modules/tls/openssl_state_machine.c b/modules/tls/openssl_state_machine.c deleted file mode 100644 index 171a1aa23d..0000000000 --- a/modules/tls/openssl_state_machine.c +++ /dev/null @@ -1,268 +0,0 @@ -/* This is adapted from the OpenSSL state_machine demo */ - -/* ==================================================================== - * Copyright (c) 2000 The OpenSSL Project. 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 OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ - -/* - * Nuron, a leader in hardware encryption technology, generously - * sponsored the development of this demo by Ben Laurie. - * - * See http://www.nuron.com/. - */ - -/* - * the aim of this demo is to provide a fully working state-machine - * style SSL implementation, i.e. one where the main loop acquires - * some data, then converts it from or to SSL by feeding it into the - * SSL state machine. It then does any I/O required by the state machine - * and loops. - * - * In order to keep things as simple as possible, this implementation - * listens on a TCP socket, which it expects to get an SSL connection - * on (for example, from s_client) and from then on writes decrypted - * data to stdout and encrypts anything arriving on stdin. Verbose - * commentary is written to stderr. - * - * This implementation acts as a server, but it can also be done for a client. */ - -#include "apr.h" - -#include <openssl/ssl.h> -#include <assert.h> -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <string.h> -#include <openssl/err.h> -#include "openssl_state_machine.h" - -/* die_unless is intended to work like assert, except that it happens - always, even if NDEBUG is defined. Use assert as a stopgap. */ - -#define die_unless(x) assert(x) - -struct SSLStateMachine - { - SSL_CTX *pCtx; - BIO *pbioRead; - BIO *pbioWrite; - SSL *pSSL; - }; - -void SSLStateMachine_init(void) -{ - static int s_bInitDone; - - if(s_bInitDone) - return; - - SSL_library_init(); - OpenSSL_add_ssl_algorithms(); - SSL_load_error_strings(); - ERR_load_crypto_strings(); - - s_bInitDone=1; -} - -static void SSLStateMachine_print_error(SSLStateMachine *pMachine, - const char *szErr) - { - unsigned long l; - - fprintf(stderr,"%s\n",szErr); - while((l=ERR_get_error())) - { - char buf[1024]; - - ERR_error_string_n(l,buf,sizeof buf); - fprintf(stderr,"Error %lx: %s\n",l,buf); - } - } - -SSLStateMachine *SSLStateMachine_new(const char *szCertificateFile, - const char *szKeyFile) - { - SSLStateMachine *pMachine=malloc(sizeof *pMachine); - int n; - - die_unless(pMachine); - - pMachine->pCtx=SSL_CTX_new(SSLv23_server_method()); - die_unless(pMachine->pCtx); - - n=SSL_CTX_use_certificate_file(pMachine->pCtx,szCertificateFile, - SSL_FILETYPE_PEM); - die_unless(n > 0); - - n=SSL_CTX_use_PrivateKey_file(pMachine->pCtx,szKeyFile,SSL_FILETYPE_PEM); - die_unless(n > 0); - - pMachine->pSSL=SSL_new(pMachine->pCtx); - die_unless(pMachine->pSSL); - - pMachine->pbioRead=BIO_new(BIO_s_mem()); - - pMachine->pbioWrite=BIO_new(BIO_s_mem()); - - SSL_set_bio(pMachine->pSSL,pMachine->pbioRead,pMachine->pbioWrite); - - SSL_set_accept_state(pMachine->pSSL); - - return pMachine; - } - -void SSLStateMachine_read_inject(SSLStateMachine *pMachine, - const unsigned char *aucBuf,int nBuf) - { - int n=BIO_write(pMachine->pbioRead,aucBuf,nBuf); - /* If it turns out this assert fails, then buffer the data here - * and just feed it in in churn instead. Seems to me that it - * should be guaranteed to succeed, though. - */ - assert(n == nBuf); - fprintf(stderr,"%d bytes of encrypted data fed to state machine\n",n); - } - -int SSLStateMachine_read_extract(SSLStateMachine *pMachine, - unsigned char *aucBuf,int nBuf) - { - int n; - - if(!SSL_is_init_finished(pMachine->pSSL)) - { - fprintf(stderr,"Doing SSL_accept\n"); - n=SSL_accept(pMachine->pSSL); - if(n == 0) - fprintf(stderr,"SSL_accept returned zero\n"); - if(n < 0) - { - int err; - - if((err=SSL_get_error(pMachine->pSSL,n)) == SSL_ERROR_WANT_READ) - { - fprintf(stderr,"SSL_accept wants more data\n"); - return 0; - } - - SSLStateMachine_print_error(pMachine,"SSL_accept error"); - exit(7); - } - return 0; - } - - n=SSL_read(pMachine->pSSL,aucBuf,nBuf); - if(n < 0) - { - int err=SSL_get_error(pMachine->pSSL,n); - - if(err == SSL_ERROR_WANT_READ) - { - fprintf(stderr,"SSL_read wants more data\n"); - return 0; - } - SSLStateMachine_print_error(pMachine,"SSL_read error"); - exit(8); - } - - fprintf(stderr,"%d bytes of decrypted data read from state machine\n",n); - return n; - } - -int SSLStateMachine_write_can_extract(SSLStateMachine *pMachine) - { - int n=BIO_pending(pMachine->pbioWrite); - if(n) - fprintf(stderr,"There is encrypted data available to write\n"); - else - fprintf(stderr,"There is no encrypted data available to write\n"); - - return n; - } - -int SSLStateMachine_write_extract(SSLStateMachine *pMachine, - unsigned char *aucBuf,int nBuf) - { - int n; - - n=BIO_read(pMachine->pbioWrite,aucBuf,nBuf); - fprintf(stderr,"%d bytes of encrypted data read from state machine\n",n); - return n; - } - -void SSLStateMachine_write_inject(SSLStateMachine *pMachine, - const unsigned char *aucBuf,int nBuf) - { - int n=SSL_write(pMachine->pSSL,aucBuf,nBuf); - if(n < 0) - { - if(ERR_peek_error() == ERR_PACK(ERR_LIB_SSL,SSL_F_SSL_WRITE, - SSL_R_PROTOCOL_IS_SHUTDOWN)) - { - SSLStateMachine_print_error(pMachine,"SSL_write error (someone wrote after shutdown)"); - return; - } - SSLStateMachine_print_error(pMachine,"SSL_write error"); - } - /* If it turns out this assert fails, then buffer the data here - * and just feed it in in churn instead. Seems to me that it - * should be guaranteed to succeed, though. - */ - assert(n == nBuf); - fprintf(stderr,"%d bytes of unencrypted data fed to state machine\n",n); - } - -void SSLStateMachine_write_close(SSLStateMachine *pMachine) - { - SSL_shutdown(pMachine->pSSL); - } diff --git a/modules/tls/openssl_state_machine.h b/modules/tls/openssl_state_machine.h deleted file mode 100644 index 10be69a3b0..0000000000 --- a/modules/tls/openssl_state_machine.h +++ /dev/null @@ -1,15 +0,0 @@ -typedef struct SSLStateMachine SSLStateMachine; - -void SSLStateMachine_init(void); -SSLStateMachine *SSLStateMachine_new(const char *szCertificateFile, - const char *szKeyFile); -void SSLStateMachine_read_inject(SSLStateMachine *pMachine, - const unsigned char *aucBuf,int nBuf); -int SSLStateMachine_read_extract(SSLStateMachine *pMachine, - unsigned char *aucBuf,int nBuf); -int SSLStateMachine_write_can_extract(SSLStateMachine *pMachine); -int SSLStateMachine_write_extract(SSLStateMachine *pMachine, - unsigned char *aucBuf,int nBuf); -void SSLStateMachine_write_inject(SSLStateMachine *pMachine, - const unsigned char *aucBuf,int nBuf); -void SSLStateMachine_write_close(SSLStateMachine *pMachine); |