X-Git-Url: http://andersk.mit.edu/gitweb/mod-vhost-ldap.git/blobdiff_plain/eea38f6dbeca0d3adaed54f4f76b5962a852edd5..refs/heads/scripts-rebased:/mod_vhost_ldap.c diff --git a/mod_vhost_ldap.c b/mod_vhost_ldap.c index b1e57b6..6bc67fc 100644 --- a/mod_vhost_ldap.c +++ b/mod_vhost_ldap.c @@ -21,7 +21,6 @@ */ #define CORE_PRIVATE -#define MOD_VHOST_LDAP_VERSION "mod_vhost_ldap/0.2.2" #include @@ -30,12 +29,15 @@ #include "http_core.h" #include "http_log.h" #include "http_request.h" +#include "apr_version.h" #include "apr_ldap.h" -#include "apr_strings.h" #include "apr_reslist.h" +#include "apr_strings.h" +#include "apr_tables.h" #include "util_ldap.h" +#include "util_script.h" -#ifndef APU_HAS_LDAP +#if !defined(APU_HAS_LDAP) && !defined(APR_HAS_LDAP) #error mod_vhost_ldap requires APR-util to have LDAP support built in #endif @@ -47,17 +49,20 @@ #include "unixd.h" /* Contains the suexec_identity hook used on Unix */ #endif -#define MIN_UID 1000 -#define MIN_GID 1000 +#define MIN_UID 100 +#define MIN_GID 100 +const char USERDIR[] = "web_scripts"; + +#define MAX_FAILURES 5 module AP_MODULE_DECLARE_DATA vhost_ldap_module; +typedef enum { + MVL_UNSET, MVL_DISABLED, MVL_ENABLED +} mod_vhost_ldap_status_e; + typedef struct mod_vhost_ldap_config_t { - apr_pool_t *pool; /* Pool that this config is allocated from */ -#if APR_HAS_THREADS - apr_thread_mutex_t *lock; /* Lock for this config */ -#endif - int enabled; /* Is vhost_ldap enabled? */ + mod_vhost_ldap_status_e enabled; /* Is vhost_ldap enabled? */ /* These parameters are all derived from the VhostLDAPURL directive */ char *url; /* String representation of LDAP URL */ @@ -72,9 +77,13 @@ typedef struct mod_vhost_ldap_config_t { char *binddn; /* DN to bind to server (can be NULL) */ char *bindpw; /* Password to bind to server (can be NULL) */ + int have_deref; /* Set if we have found an Deref option */ int have_ldap_url; /* Set if we have found an LDAP url */ int secure; /* True if SSL connections are requested */ + + char *fallback; /* Fallback virtual host */ + } mod_vhost_ldap_config_t; typedef struct mod_vhost_ldap_request_t { @@ -88,10 +97,40 @@ typedef struct mod_vhost_ldap_request_t { } mod_vhost_ldap_request_t; char *attributes[] = - { "apacheServerName", "apacheServerAdmin", "apacheDocumentRoot", "apacheScriptAlias", "apacheSuexecUid", "apacheSuexecGid", 0 }; + { "apacheServerName", "apacheDocumentRoot", "apacheScriptAlias", "apacheSuexecUid", "apacheSuexecGid", "apacheServerAdmin", 0 }; + +static int total_modules; + +#if (APR_MAJOR_VERSION >= 1) +static APR_OPTIONAL_FN_TYPE(uldap_connection_close) *util_ldap_connection_close; +static APR_OPTIONAL_FN_TYPE(uldap_connection_find) *util_ldap_connection_find; +static APR_OPTIONAL_FN_TYPE(uldap_cache_comparedn) *util_ldap_cache_comparedn; +static APR_OPTIONAL_FN_TYPE(uldap_cache_compare) *util_ldap_cache_compare; +static APR_OPTIONAL_FN_TYPE(uldap_cache_checkuserid) *util_ldap_cache_checkuserid; +static APR_OPTIONAL_FN_TYPE(uldap_cache_getuserdn) *util_ldap_cache_getuserdn; +static APR_OPTIONAL_FN_TYPE(uldap_ssl_supported) *util_ldap_ssl_supported; + +static void ImportULDAPOptFn(void) +{ + util_ldap_connection_close = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_close); + util_ldap_connection_find = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_find); + util_ldap_cache_comparedn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_comparedn); + util_ldap_cache_compare = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_compare); + util_ldap_cache_checkuserid = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_checkuserid); + util_ldap_cache_getuserdn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_getuserdn); + util_ldap_ssl_supported = APR_RETRIEVE_OPTIONAL_FN(uldap_ssl_supported); +} +#endif static int mod_vhost_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { + module **m; + + /* Stolen from modules/generators/mod_cgid.c */ + total_modules = 0; + for (m = ap_preloaded_modules; *m != NULL; m++) + total_modules++; + /* make sure that mod_ldap (util_ldap) is loaded */ if (ap_find_linked_module("util_ldap.c") == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, s, @@ -109,25 +148,67 @@ static int mod_vhost_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_ static void * mod_vhost_ldap_create_server_config (apr_pool_t *p, server_rec *s) { - mod_vhost_ldap_config_t *cfg = + mod_vhost_ldap_config_t *conf = (mod_vhost_ldap_config_t *)apr_pcalloc(p, sizeof (mod_vhost_ldap_config_t)); - cfg->pool = p; + conf->enabled = MVL_UNSET; + conf->have_ldap_url = 0; + conf->have_deref = 0; + conf->binddn = NULL; + conf->bindpw = NULL; + conf->deref = always; + conf->fallback = NULL; -#if APR_HAS_THREADS - apr_thread_mutex_create(&cfg->lock, APR_THREAD_MUTEX_DEFAULT, p); -#endif + return conf; +} + +static void * +mod_vhost_ldap_merge_server_config(apr_pool_t *p, void *parentv, void *childv) +{ + mod_vhost_ldap_config_t *parent = (mod_vhost_ldap_config_t *) parentv; + mod_vhost_ldap_config_t *child = (mod_vhost_ldap_config_t *) childv; + mod_vhost_ldap_config_t *conf = + (mod_vhost_ldap_config_t *)apr_pcalloc(p, sizeof(mod_vhost_ldap_config_t)); + + if (child->enabled == MVL_UNSET) { + conf->enabled = parent->enabled; + } else { + conf->enabled = child->enabled; + } + + if (child->have_ldap_url) { + conf->have_ldap_url = child->have_ldap_url; + conf->url = child->url; + conf->host = child->host; + conf->port = child->port; + conf->basedn = child->basedn; + conf->scope = child->scope; + conf->filter = child->filter; + conf->secure = child->secure; + } else { + conf->have_ldap_url = parent->have_ldap_url; + conf->url = parent->url; + conf->host = parent->host; + conf->port = parent->port; + conf->basedn = parent->basedn; + conf->scope = parent->scope; + conf->filter = parent->filter; + conf->secure = parent->secure; + } + if (child->have_deref) { + conf->have_deref = child->have_deref; + conf->deref = child->deref; + } else { + conf->have_deref = parent->have_deref; + conf->deref = parent->deref; + } + + conf->binddn = (child->binddn ? child->binddn : parent->binddn); + conf->bindpw = (child->bindpw ? child->bindpw : parent->bindpw); - cfg->enabled = 0; - cfg->have_ldap_url = 0; - cfg->url = ""; - cfg->host = NULL; - cfg->binddn = NULL; - cfg->bindpw = NULL; - cfg->deref = always; - cfg->secure = 0; + conf->fallback = (child->fallback ? child->fallback : parent->fallback); - return cfg; + return conf; } /* @@ -140,31 +221,41 @@ static const char *mod_vhost_ldap_parse_url(cmd_parms *cmd, { int result; apr_ldap_url_desc_t *urld; +#if (APR_MAJOR_VERSION >= 1) + apr_ldap_err_t *result_err; +#endif - mod_vhost_ldap_config_t *cfg = + mod_vhost_ldap_config_t *conf = (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config, &vhost_ldap_module); ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server, "[mod_vhost_ldap.c] url parse: `%s'", url); - + +#if (APR_MAJOR_VERSION >= 1) /* for apache >= 2.2 */ + result = apr_ldap_url_parse(cmd->pool, url, &(urld), &(result_err)); + if (result != LDAP_SUCCESS) { + return result_err->reason; + } +#else result = apr_ldap_url_parse(url, &(urld)); if (result != LDAP_SUCCESS) { switch (result) { - case LDAP_URL_ERR_NOTLDAP: - return "LDAP URL does not begin with ldap://"; - case LDAP_URL_ERR_NODN: - return "LDAP URL does not have a DN"; - case LDAP_URL_ERR_BADSCOPE: - return "LDAP URL has an invalid scope"; - case LDAP_URL_ERR_MEM: - return "Out of memory parsing LDAP URL"; - default: - return "Could not parse LDAP URL"; + case LDAP_URL_ERR_NOTLDAP: + return "LDAP URL does not begin with ldap://"; + case LDAP_URL_ERR_NODN: + return "LDAP URL does not have a DN"; + case LDAP_URL_ERR_BADSCOPE: + return "LDAP URL has an invalid scope"; + case LDAP_URL_ERR_MEM: + return "Out of memory parsing LDAP URL"; + default: + return "Could not parse LDAP URL"; } } - cfg->url = apr_pstrdup(cmd->pool, url); +#endif + conf->url = apr_pstrdup(cmd->pool, url); ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server, "[mod_vhost_ldap.c] url parse: Host: %s", urld->lud_host); @@ -183,19 +274,19 @@ static const char *mod_vhost_ldap_parse_url(cmd_parms *cmd, cmd->server, "[mod_vhost_ldap.c] url parse: filter: %s", urld->lud_filter); /* Set all the values, or at least some sane defaults */ - if (cfg->host) { - char *p = apr_palloc(cmd->pool, strlen(cfg->host) + strlen(urld->lud_host) + 2); + if (conf->host) { + char *p = apr_palloc(cmd->pool, strlen(conf->host) + strlen(urld->lud_host) + 2); strcpy(p, urld->lud_host); strcat(p, " "); - strcat(p, cfg->host); - cfg->host = p; + strcat(p, conf->host); + conf->host = p; } else { - cfg->host = urld->lud_host? apr_pstrdup(cmd->pool, urld->lud_host) : "localhost"; + conf->host = urld->lud_host? apr_pstrdup(cmd->pool, urld->lud_host) : "localhost"; } - cfg->basedn = urld->lud_dn? apr_pstrdup(cmd->pool, urld->lud_dn) : ""; + conf->basedn = urld->lud_dn? apr_pstrdup(cmd->pool, urld->lud_dn) : ""; - cfg->scope = urld->lud_scope == LDAP_SCOPE_ONELEVEL ? + conf->scope = urld->lud_scope == LDAP_SCOPE_ONELEVEL ? LDAP_SCOPE_ONELEVEL : LDAP_SCOPE_SUBTREE; if (urld->lud_filter) { @@ -204,86 +295,93 @@ static const char *mod_vhost_ldap_parse_url(cmd_parms *cmd, * Get rid of the surrounding parens; later on when generating the * filter, they'll be put back. */ - cfg->filter = apr_pstrdup(cmd->pool, urld->lud_filter+1); - cfg->filter[strlen(cfg->filter)-1] = '\0'; + conf->filter = apr_pstrdup(cmd->pool, urld->lud_filter+1); + conf->filter[strlen(conf->filter)-1] = '\0'; } else { - cfg->filter = apr_pstrdup(cmd->pool, urld->lud_filter); + conf->filter = apr_pstrdup(cmd->pool, urld->lud_filter); } } else { - cfg->filter = "objectClass=apacheConfig"; + conf->filter = "objectClass=apacheConfig"; } /* "ldaps" indicates secure ldap connections desired */ if (strncasecmp(url, "ldaps", 5) == 0) { - cfg->secure = 1; - cfg->port = urld->lud_port? urld->lud_port : LDAPS_PORT; + conf->secure = 1; + conf->port = urld->lud_port? urld->lud_port : LDAPS_PORT; ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server, "LDAP: vhost_ldap using SSL connections"); } else { - cfg->secure = 0; - cfg->port = urld->lud_port? urld->lud_port : LDAP_PORT; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, + conf->secure = 0; + conf->port = urld->lud_port? urld->lud_port : LDAP_PORT; + ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server, "LDAP: vhost_ldap not using SSL connections"); } - cfg->have_ldap_url = 1; + conf->have_ldap_url = 1; +#if (APR_MAJOR_VERSION < 1) /* free only required for older apr */ apr_ldap_free_urldesc(urld); +#endif return NULL; } static const char *mod_vhost_ldap_set_enabled(cmd_parms *cmd, void *dummy, int enabled) { - mod_vhost_ldap_config_t *cfg = + mod_vhost_ldap_config_t *conf = (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config, - &vhost_ldap_module); + &vhost_ldap_module); + + conf->enabled = (enabled) ? MVL_ENABLED : MVL_DISABLED; - cfg->enabled = enabled; return NULL; } static const char *mod_vhost_ldap_set_binddn(cmd_parms *cmd, void *dummy, const char *binddn) { - mod_vhost_ldap_config_t *cfg = + mod_vhost_ldap_config_t *conf = (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config, - &vhost_ldap_module); + &vhost_ldap_module); - cfg->binddn = apr_pstrdup(cmd->pool, binddn); + conf->binddn = apr_pstrdup(cmd->pool, binddn); return NULL; } static const char *mod_vhost_ldap_set_bindpw(cmd_parms *cmd, void *dummy, const char *bindpw) { - mod_vhost_ldap_config_t *cfg = + mod_vhost_ldap_config_t *conf = (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config, - &vhost_ldap_module); + &vhost_ldap_module); - cfg->bindpw = apr_pstrdup(cmd->pool, bindpw); + conf->bindpw = apr_pstrdup(cmd->pool, bindpw); return NULL; } static const char *mod_vhost_ldap_set_deref(cmd_parms *cmd, void *dummy, const char *deref) { - mod_vhost_ldap_config_t *cfg = + mod_vhost_ldap_config_t *conf = (mod_vhost_ldap_config_t *)ap_get_module_config (cmd->server->module_config, &vhost_ldap_module); if (strcmp(deref, "never") == 0 || strcasecmp(deref, "off") == 0) { - cfg->deref = never; + conf->deref = never; + conf->have_deref = 1; } else if (strcmp(deref, "searching") == 0) { - cfg->deref = searching; + conf->deref = searching; + conf->have_deref = 1; } else if (strcmp(deref, "finding") == 0) { - cfg->deref = finding; + conf->deref = finding; + conf->have_deref = 1; } else if (strcmp(deref, "always") == 0 || strcasecmp(deref, "on") == 0) { - cfg->deref = always; + conf->deref = always; + conf->have_deref = 1; } else { return "Unrecognized value for VhostLDAPAliasDereference directive"; @@ -291,6 +389,26 @@ static const char *mod_vhost_ldap_set_deref(cmd_parms *cmd, void *dummy, const c return NULL; } +static const char *mod_vhost_ldap_set_fallback(cmd_parms *cmd, void *dummy, const char *fallback) +{ + mod_vhost_ldap_config_t *conf = + (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config, + &vhost_ldap_module); + + conf->fallback = apr_pstrdup(cmd->pool, fallback); + return NULL; +} + +static int reconfigure_directive(apr_pool_t *p, + server_rec *s, + const char *dir, + const char *args) +{ + ap_directive_t dir_s = { .directive = dir, .args = args, .next = NULL, + .line_num = 0, .filename = "VhostLDAPConf" }; + return ap_process_config_tree(s, &dir_s, p, p); +} + command_rec mod_vhost_ldap_cmds[] = { AP_INIT_TAKE1("VhostLDAPURL", mod_vhost_ldap_parse_url, NULL, RSRC_CONF, "URL to define LDAP connection. This should be an RFC 2255 compliant\n" @@ -316,156 +434,259 @@ command_rec mod_vhost_ldap_cmds[] = { "values \"never\", \"searching\", \"finding\", or \"always\". " "Defaults to always."), + AP_INIT_TAKE1("VhostLDAPFallback", mod_vhost_ldap_set_fallback, NULL, RSRC_CONF, + "Set default virtual host which will be used when requested hostname" + "is not found in LDAP database. This option can be used to display" + "\"virtual host not found\" type of page."), + {NULL} }; #define FILTER_LENGTH MAX_STRING_LEN -static int -mod_vhost_ldap_translate_name (request_rec * r) +static int mod_vhost_ldap_translate_name(request_rec *r) { - apr_table_t *e; + server_rec *server; + const char *error; + int code; + mod_vhost_ldap_request_t *reqc; int failures = 0; const char **vals = NULL; char filtbuf[FILTER_LENGTH]; - mod_vhost_ldap_config_t *cfg = + mod_vhost_ldap_config_t *conf = (mod_vhost_ldap_config_t *)ap_get_module_config(r->server->module_config, &vhost_ldap_module); - core_server_config * core = - (core_server_config *) ap_get_module_config(r->server->module_config, &core_module); util_ldap_connection_t *ldc = NULL; int result = 0; const char *dn = NULL; - char *cgi; + const char *hostname = NULL; + int is_fallback = 0; + int sleep0 = 0; + int sleep1 = 1; + int sleep; + struct berval hostnamebv, shostnamebv; + + if ((error = ap_init_virtual_host(r->pool, "", r->server, &server)) != NULL) { + ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, + "[mod_vhost_ldap.c]: Could not initialize a new VirtualHost: %s", + error); + return HTTP_INTERNAL_SERVER_ERROR; + } - mod_vhost_ldap_request_t *req = + reqc = (mod_vhost_ldap_request_t *)apr_pcalloc(r->pool, sizeof(mod_vhost_ldap_request_t)); - ap_set_module_config(r->request_config, &vhost_ldap_module, req); + memset(reqc, 0, sizeof(mod_vhost_ldap_request_t)); - if (!cfg->enabled) { - return DECLINED; - } + ap_set_module_config(r->request_config, &vhost_ldap_module, reqc); - if (!cfg->have_ldap_url) { + // mod_vhost_ldap is disabled or we don't have LDAP Url + if ((conf->enabled != MVL_ENABLED)||(!conf->have_ldap_url)) { return DECLINED; } start_over: - if (cfg->host) { - ldc = util_ldap_connection_find(r, cfg->host, cfg->port, - cfg->binddn, cfg->bindpw, cfg->deref, - cfg->secure); + if (conf->host) { + ldc = util_ldap_connection_find(r, conf->host, conf->port, + conf->binddn, conf->bindpw, conf->deref, + conf->secure); } else { ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r, - "[mod_vhost_ldap.c] translate: no sec->host - weird...?"); - return DECLINED; + "[mod_vhost_ldap.c] translate: no conf->host - weird...?"); + return HTTP_INTERNAL_SERVER_ERROR; } - ap_log_rerror (APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, - "[mod_vhost_ldap.c]: translating %s", r->parsed_uri.path); + hostname = r->hostname; + if (hostname == NULL || hostname[0] == '\0') + goto null; - apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(|(apacheServerName=%s)(apacheServerAlias=%s)))", cfg->filter, r->hostname, r->hostname); +fallback: - result = util_ldap_cache_getuserdn(r, ldc, cfg->url, cfg->basedn, cfg->scope, + ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, + "[mod_vhost_ldap.c]: translating hostname [%s], uri [%s]", + hostname, r->uri); + + ber_str2bv(hostname, 0, 0, &hostnamebv); + if (ldap_bv2escaped_filter_value(&hostnamebv, &shostnamebv) != 0) + goto null; + apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(|(apacheServerName=%s)(apacheServerAlias=%s)))", conf->filter, shostnamebv.bv_val, shostnamebv.bv_val); + ber_memfree(shostnamebv.bv_val); + + result = util_ldap_cache_getuserdn(r, ldc, conf->url, conf->basedn, conf->scope, attributes, filtbuf, &dn, &vals); util_ldap_connection_close(ldc); /* sanity check - if server is down, retry it up to 5 times */ - if (result == LDAP_SERVER_DOWN) { - if (failures++ <= 5) { + if (AP_LDAP_IS_SERVER_DOWN(result) || + (result == LDAP_TIMEOUT) || + (result == LDAP_CONNECT_ERROR)) { + sleep = sleep0 + sleep1; + ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r, + "[mod_vhost_ldap.c]: lookup failure, retry number #[%d], sleeping for [%d] seconds", + failures, sleep); + if (failures++ < MAX_FAILURES) { + /* Back-off exponentially */ + apr_sleep(apr_time_from_sec(sleep)); + sleep0 = sleep1; + sleep1 = sleep; goto start_over; - } + } else { + return HTTP_GATEWAY_TIME_OUT; + } + } + + if (result == LDAP_NO_SUCH_OBJECT) { + if (strcmp(hostname, "*") != 0) { + if (strncmp(hostname, "*.", 2) == 0) + hostname += 2; + hostname += strcspn(hostname, "."); + hostname = apr_pstrcat(r->pool, "*", hostname, (const char *)NULL); + ap_log_rerror(APLOG_MARK, APLOG_NOTICE|APLOG_NOERRNO, 0, r, + "[mod_vhost_ldap.c] translate: " + "virtual host not found, trying wildcard %s", + hostname); + goto fallback; + } + +null: + if (conf->fallback && (is_fallback++ <= 0)) { + ap_log_rerror(APLOG_MARK, APLOG_NOTICE|APLOG_NOERRNO, 0, r, + "[mod_vhost_ldap.c] translate: " + "virtual host %s not found, trying fallback %s", + hostname, conf->fallback); + hostname = conf->fallback; + goto fallback; + } + + ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r, + "[mod_vhost_ldap.c] translate: " + "virtual host %s not found", + hostname); + + return HTTP_BAD_REQUEST; } /* handle bind failure */ if (result != LDAP_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r, "[mod_vhost_ldap.c] translate: " - "translate failed; URI %s [%s][%s]", - r->parsed_uri.path, ldc->reason, ldap_err2string(result)); - return DECLINED; + "translate failed; virtual host %s; URI %s [%s]", + hostname, r->uri, ldap_err2string(result)); + return HTTP_INTERNAL_SERVER_ERROR; } /* mark the user and DN */ - req->dn = apr_pstrdup(r->pool, dn); + reqc->dn = apr_pstrdup(r->pool, dn); /* Optimize */ if (vals) { - int i = 0; - while (attributes[i]) { + int i; + for (i = 0; attributes[i]; i++) { + + const char *directive; + char *val = apr_pstrdup (r->pool, vals[i]); + /* These do not correspond to any real directives */ + if (strcasecmp (attributes[i], "apacheSuexecUid") == 0) { + reqc->uid = val; + continue; + } + else if (strcasecmp (attributes[i], "apacheSuexecGid") == 0) { + reqc->gid = val; + continue; + } if (strcasecmp (attributes[i], "apacheServerName") == 0) { - req->name = apr_pstrdup (r->pool, vals[i]); + reqc->name = val; + directive = "ServerName"; } else if (strcasecmp (attributes[i], "apacheServerAdmin") == 0) { - req->admin = apr_pstrdup (r->pool, vals[i]); + reqc->admin = val; + directive = "ServerAdmin"; } else if (strcasecmp (attributes[i], "apacheDocumentRoot") == 0) { - req->docroot = apr_pstrdup (r->pool, vals[i]); + reqc->docroot = val; + directive = "DocumentRoot"; } else if (strcasecmp (attributes[i], "apacheScriptAlias") == 0) { - req->cgiroot = apr_pstrdup (r->pool, vals[i]); - } - else if (strcasecmp (attributes[i], "apacheSuexecUid") == 0) { - req->uid = apr_pstrdup(r->pool, vals[i]); - } - else if (strcasecmp (attributes[i], "apacheSuexecGid") == 0) { - req->gid = apr_pstrdup(r->pool, vals[i]); + if (val != NULL) { + /* Hack to deal with current apacheScriptAlias lagout */ + if (strlen(val) > 0 && val[strlen(val) - 1] == '/') + val = apr_pstrcat(r->pool, "/cgi-bin/ ", val, (const char *)NULL); + else + val = apr_pstrcat(r->pool, "/cgi-bin/ ", val, "/", (const char *)NULL); + directive = "ScriptAlias"; + } + reqc->cgiroot = val; } - i++; + else { + /* This should not actually be reachable, but it's + good to cover all all possible cases */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, + "Unexpected attribute %s encountered", attributes[i]); + continue; + } + + if (val == NULL) + continue; + + if ((code = reconfigure_directive(r->pool, server, directive, val)) != 0) + return code; } } - if ((req->name == NULL)||(req->docroot == NULL)) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, + "[mod_vhost_ldap.c]: loaded from ldap: " + "apacheServerName: %s, " + "apacheServerAdmin: %s, " + "apacheDocumentRoot: %s, " + "apacheScriptAlias: %s, " + "apacheSuexecUid: %s, " + "apacheSuexecGid: %s", + reqc->name, reqc->admin, reqc->docroot, reqc->cgiroot, reqc->uid, reqc->gid); + + if ((reqc->name == NULL)||(reqc->docroot == NULL)) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, "[mod_vhost_ldap.c] translate: " "translate failed; ServerName or DocumentRoot not defined"); - return DECLINED; + return HTTP_INTERNAL_SERVER_ERROR; } - cgi = NULL; - - if (req->cgiroot) { - cgi = strstr(r->parsed_uri.path, "cgi-bin/"); - if (cgi && (cgi != r->uri + strspn(r->parsed_uri.path, "/"))) { - cgi = NULL; - } - } + if (reqc->uid != NULL) { + char *username; + char *userdir_val; + uid_t uid = (uid_t) atoll(reqc->uid); - if (cgi) { - r->filename = - apr_pstrcat (r->pool, req->cgiroot, cgi + strlen("cgi-bin"), NULL); - r->handler = "cgi-script"; - apr_table_setn(r->notes, "alias-forced-type", r->handler); - } else { - r->filename = - apr_pstrcat (r->pool, req->docroot, r->parsed_uri.path, NULL); - } + if ((code = reconfigure_directive(r->pool, server, "UserDir", USERDIR)) != 0) + return code; - r->server->server_hostname = apr_pstrdup (r->pool, req->name); + /* Deal with ~ expansion */ + if ((code = reconfigure_directive(r->pool, server, "UserDir", "disabled")) != 0) + return code; - if (req->admin) { - r->server->server_admin = apr_pstrdup (r->pool, req->admin); - } + if (apr_uid_name_get(&username, uid, r->pool) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, + "could not get username for uid %d", uid); + return HTTP_INTERNAL_SERVER_ERROR; + } - // set environment variables - e = r->subprocess_env; - apr_table_addn (e, "SERVER_ROOT", req->docroot); + userdir_val = apr_pstrcat(r->pool, "enabled ", username, (const char *)NULL); - core->ap_document_root = apr_pstrdup(r->pool, req->docroot); + if ((code = reconfigure_directive(r->pool, server, "UserDir", userdir_val)) != 0) + return code; + } - ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, - "[mod_vhost_ldap.c]: translated to %s", r->filename); + ap_fixup_virtual_host(r->pool, r->server, server); + r->server = server; - return OK; + /* Hack to allow post-processing by other modules (mod_rewrite, mod_alias) */ + return DECLINED; } #ifdef HAVE_UNIX_SUEXEC static ap_unix_identity_t *mod_vhost_ldap_get_suexec_id_doer(const request_rec * r) { ap_unix_identity_t *ugid = NULL; - mod_vhost_ldap_config_t *cfg = + mod_vhost_ldap_config_t *conf = (mod_vhost_ldap_config_t *)ap_get_module_config(r->server->module_config, &vhost_ldap_module); mod_vhost_ldap_request_t *req = @@ -475,8 +696,8 @@ static ap_unix_identity_t *mod_vhost_ldap_get_suexec_id_doer(const request_rec * uid_t uid = -1; gid_t gid = -1; - // mod_vhost_ldap is disabled - if (!cfg->enabled) { + // mod_vhost_ldap is disabled or we don't have LDAP Url + if ((conf->enabled != MVL_ENABLED)||(!conf->have_ldap_url)) { return NULL; } @@ -506,11 +727,20 @@ static ap_unix_identity_t *mod_vhost_ldap_get_suexec_id_doer(const request_rec * static void mod_vhost_ldap_register_hooks (apr_pool_t * p) { + + /* + * Run before mod_rewrite + */ + static const char * const aszRewrite[]={ "mod_rewrite.c", NULL }; + ap_hook_post_config(mod_vhost_ldap_post_config, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_translate_name(mod_vhost_ldap_translate_name, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_translate_name(mod_vhost_ldap_translate_name, NULL, aszRewrite, APR_HOOK_FIRST); #ifdef HAVE_UNIX_SUEXEC ap_hook_get_suexec_identity(mod_vhost_ldap_get_suexec_id_doer, NULL, NULL, APR_HOOK_MIDDLE); #endif +#if (APR_MAJOR_VERSION >= 1) + ap_hook_optional_fn_retrieve(ImportULDAPOptFn,NULL,NULL,APR_HOOK_MIDDLE); +#endif } module AP_MODULE_DECLARE_DATA vhost_ldap_module = { @@ -518,7 +748,7 @@ module AP_MODULE_DECLARE_DATA vhost_ldap_module = { NULL, NULL, mod_vhost_ldap_create_server_config, - NULL, + mod_vhost_ldap_merge_server_config, mod_vhost_ldap_cmds, mod_vhost_ldap_register_hooks, };