source: trunk/server/common/oursrc/httpdmods/mod_vhost_ldap.c @ 1604

Last change on this file since 1604 was 1604, checked in by gdb, 14 years ago
Refactor code for processing attributes from LDAP. This patch should not change any behavior. We do this refactoring in preparation for switching to ap_walk_config.
  • Property svn:eol-style set to native
File size: 25.7 KB
RevLine 
[479]1/* ============================================================
2 * Copyright (c) 2003-2004, Ondrej Sury
3 * All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19/*
20 * mod_vhost_ldap.c --- read virtual host config from LDAP directory
21 */
22
23#define CORE_PRIVATE
24
25#include <unistd.h>
26
27#include "httpd.h"
28#include "http_config.h"
29#include "http_core.h"
30#include "http_log.h"
31#include "http_request.h"
32#include "apr_version.h"
33#include "apr_ldap.h"
[1588]34#include "apr_reslist.h"
[479]35#include "apr_strings.h"
[1588]36#include "apr_tables.h"
[479]37#include "util_ldap.h"
[1588]38#include "util_script.h"
[479]39
40#if !defined(APU_HAS_LDAP) && !defined(APR_HAS_LDAP)
41#error mod_vhost_ldap requires APR-util to have LDAP support built in
42#endif
43
44#if !defined(WIN32) && !defined(OS2) && !defined(BEOS) && !defined(NETWARE)
45#define HAVE_UNIX_SUEXEC
46#endif
47
48#ifdef HAVE_UNIX_SUEXEC
49#include "unixd.h"              /* Contains the suexec_identity hook used on Unix */
50#endif
51
52#define MIN_UID 100
53#define MIN_GID 100
[481]54const char USERDIR[] = "web_scripts";
[479]55
[1588]56#define MAX_FAILURES 5
57
[479]58module AP_MODULE_DECLARE_DATA vhost_ldap_module;
59
60typedef enum {
61    MVL_UNSET, MVL_DISABLED, MVL_ENABLED
62} mod_vhost_ldap_status_e;
63
64typedef struct mod_vhost_ldap_config_t {
65    mod_vhost_ldap_status_e enabled;                    /* Is vhost_ldap enabled? */
66
67    /* These parameters are all derived from the VhostLDAPURL directive */
68    char *url;                          /* String representation of LDAP URL */
69
70    char *host;                         /* Name of the LDAP server (or space separated list) */
71    int port;                           /* Port of the LDAP server */
72    char *basedn;                       /* Base DN to do all searches from */
73    int scope;                          /* Scope of the search */
74    char *filter;                       /* Filter to further limit the search  */
75    deref_options deref;                /* how to handle alias dereferening */
76
77    char *binddn;                       /* DN to bind to server (can be NULL) */
78    char *bindpw;                       /* Password to bind to server (can be NULL) */
79
80    int have_deref;                     /* Set if we have found an Deref option */
81    int have_ldap_url;                  /* Set if we have found an LDAP url */
82
83    int secure;                         /* True if SSL connections are requested */
84
85    char *fallback;                     /* Fallback virtual host */
86
87} mod_vhost_ldap_config_t;
88
89typedef struct mod_vhost_ldap_request_t {
90    char *dn;                           /* The saved dn from a successful search */
91    char *name;                         /* ServerName */
92    char *admin;                        /* ServerAdmin */
93    char *docroot;                      /* DocumentRoot */
94    char *cgiroot;                      /* ScriptAlias */
95    char *uid;                          /* Suexec Uid */
96    char *gid;                          /* Suexec Gid */
97} mod_vhost_ldap_request_t;
98
99char *attributes[] =
100  { "apacheServerName", "apacheDocumentRoot", "apacheScriptAlias", "apacheSuexecUid", "apacheSuexecGid", "apacheServerAdmin", 0 };
101
[1463]102static int total_modules;
103
[479]104#if (APR_MAJOR_VERSION >= 1)
105static APR_OPTIONAL_FN_TYPE(uldap_connection_close) *util_ldap_connection_close;
106static APR_OPTIONAL_FN_TYPE(uldap_connection_find) *util_ldap_connection_find;
107static APR_OPTIONAL_FN_TYPE(uldap_cache_comparedn) *util_ldap_cache_comparedn;
108static APR_OPTIONAL_FN_TYPE(uldap_cache_compare) *util_ldap_cache_compare;
109static APR_OPTIONAL_FN_TYPE(uldap_cache_checkuserid) *util_ldap_cache_checkuserid;
110static APR_OPTIONAL_FN_TYPE(uldap_cache_getuserdn) *util_ldap_cache_getuserdn;
111static APR_OPTIONAL_FN_TYPE(uldap_ssl_supported) *util_ldap_ssl_supported;
112
113static void ImportULDAPOptFn(void)
114{
115    util_ldap_connection_close  = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_close);
116    util_ldap_connection_find   = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_find);
117    util_ldap_cache_comparedn   = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_comparedn);
118    util_ldap_cache_compare     = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_compare);
119    util_ldap_cache_checkuserid = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_checkuserid);
120    util_ldap_cache_getuserdn   = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_getuserdn);
121    util_ldap_ssl_supported     = APR_RETRIEVE_OPTIONAL_FN(uldap_ssl_supported);
122}
123#endif
124
125static int mod_vhost_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
126{
[1463]127    module **m;
[1588]128   
[1463]129    /* Stolen from modules/generators/mod_cgid.c */
130    total_modules = 0;
131    for (m = ap_preloaded_modules; *m != NULL; m++)
[1588]132      total_modules++;
[1463]133
[479]134    /* make sure that mod_ldap (util_ldap) is loaded */
135    if (ap_find_linked_module("util_ldap.c") == NULL) {
136        ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, s,
137                     "Module mod_ldap missing. Mod_ldap (aka. util_ldap) "
138                     "must be loaded in order for mod_vhost_ldap to function properly");
139        return HTTP_INTERNAL_SERVER_ERROR;
140
141    }
142
143    ap_add_version_component(p, MOD_VHOST_LDAP_VERSION);
144
145    return OK;
146}
147
148static void *
149mod_vhost_ldap_create_server_config (apr_pool_t *p, server_rec *s)
150{
151    mod_vhost_ldap_config_t *conf =
152        (mod_vhost_ldap_config_t *)apr_pcalloc(p, sizeof (mod_vhost_ldap_config_t));
153
154    conf->enabled = MVL_UNSET;
155    conf->have_ldap_url = 0;
156    conf->have_deref = 0;
157    conf->binddn = NULL;
158    conf->bindpw = NULL;
159    conf->deref = always;
160    conf->fallback = NULL;
161
162    return conf;
163}
164
165static void *
166mod_vhost_ldap_merge_server_config(apr_pool_t *p, void *parentv, void *childv)
167{
168    mod_vhost_ldap_config_t *parent = (mod_vhost_ldap_config_t *) parentv;
169    mod_vhost_ldap_config_t *child  = (mod_vhost_ldap_config_t *) childv;
170    mod_vhost_ldap_config_t *conf =
171        (mod_vhost_ldap_config_t *)apr_pcalloc(p, sizeof(mod_vhost_ldap_config_t));
172
173    if (child->enabled == MVL_UNSET) {
174        conf->enabled = parent->enabled;
175    } else {
176        conf->enabled = child->enabled;
177    }
178
179    if (child->have_ldap_url) {
180        conf->have_ldap_url = child->have_ldap_url;
181        conf->url = child->url;
182        conf->host = child->host;
183        conf->port = child->port;
184        conf->basedn = child->basedn;
185        conf->scope = child->scope;
186        conf->filter = child->filter;
187        conf->secure = child->secure;
188    } else {
189        conf->have_ldap_url = parent->have_ldap_url;
190        conf->url = parent->url;
191        conf->host = parent->host;
192        conf->port = parent->port;
193        conf->basedn = parent->basedn;
194        conf->scope = parent->scope;
195        conf->filter = parent->filter;
196        conf->secure = parent->secure;
197    }
198    if (child->have_deref) {
199        conf->have_deref = child->have_deref;
200        conf->deref = child->deref;
201    } else {
202        conf->have_deref = parent->have_deref;
203        conf->deref = parent->deref;
204    }
205
206    conf->binddn = (child->binddn ? child->binddn : parent->binddn);
207    conf->bindpw = (child->bindpw ? child->bindpw : parent->bindpw);
208
209    conf->fallback = (child->fallback ? child->fallback : parent->fallback);
210
211    return conf;
212}
213
214/*
215 * Use the ldap url parsing routines to break up the ldap url into
216 * host and port.
217 */
218static const char *mod_vhost_ldap_parse_url(cmd_parms *cmd, 
219                                            void *dummy,
220                                            const char *url)
221{
222    int result;
223    apr_ldap_url_desc_t *urld;
224#if (APR_MAJOR_VERSION >= 1)
225    apr_ldap_err_t *result_err;
226#endif
227
228    mod_vhost_ldap_config_t *conf =
229        (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
230                                                        &vhost_ldap_module);
231
232    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
233                 cmd->server, "[mod_vhost_ldap.c] url parse: `%s'", 
234                 url);
235   
236#if (APR_MAJOR_VERSION >= 1)    /* for apache >= 2.2 */
237    result = apr_ldap_url_parse(cmd->pool, url, &(urld), &(result_err));
238    if (result != LDAP_SUCCESS) {
239        return result_err->reason;
240    }
241#else
242    result = apr_ldap_url_parse(url, &(urld));
243    if (result != LDAP_SUCCESS) {
244        switch (result) {
245            case LDAP_URL_ERR_NOTLDAP:
246                return "LDAP URL does not begin with ldap://";
247            case LDAP_URL_ERR_NODN:
248                return "LDAP URL does not have a DN";
249            case LDAP_URL_ERR_BADSCOPE:
250                return "LDAP URL has an invalid scope";
251            case LDAP_URL_ERR_MEM:
252                return "Out of memory parsing LDAP URL";
253            default:
254                return "Could not parse LDAP URL";
255        }
256    }
257#endif
258    conf->url = apr_pstrdup(cmd->pool, url);
259
260    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
261                 cmd->server, "[mod_vhost_ldap.c] url parse: Host: %s", urld->lud_host);
262    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
263                 cmd->server, "[mod_vhost_ldap.c] url parse: Port: %d", urld->lud_port);
264    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
265                 cmd->server, "[mod_vhost_ldap.c] url parse: DN: %s", urld->lud_dn);
266    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
267                 cmd->server, "[mod_vhost_ldap.c] url parse: attrib: %s", urld->lud_attrs? urld->lud_attrs[0] : "(null)");
268    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
269                 cmd->server, "[mod_vhost_ldap.c] url parse: scope: %s", 
270                 (urld->lud_scope == LDAP_SCOPE_SUBTREE? "subtree" : 
271                 urld->lud_scope == LDAP_SCOPE_BASE? "base" : 
272                 urld->lud_scope == LDAP_SCOPE_ONELEVEL? "onelevel" : "unknown"));
273    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
274                 cmd->server, "[mod_vhost_ldap.c] url parse: filter: %s", urld->lud_filter);
275
276    /* Set all the values, or at least some sane defaults */
277    if (conf->host) {
278        char *p = apr_palloc(cmd->pool, strlen(conf->host) + strlen(urld->lud_host) + 2);
279        strcpy(p, urld->lud_host);
280        strcat(p, " ");
281        strcat(p, conf->host);
282        conf->host = p;
283    }
284    else {
285        conf->host = urld->lud_host? apr_pstrdup(cmd->pool, urld->lud_host) : "localhost";
286    }
287    conf->basedn = urld->lud_dn? apr_pstrdup(cmd->pool, urld->lud_dn) : "";
288
289    conf->scope = urld->lud_scope == LDAP_SCOPE_ONELEVEL ?
290        LDAP_SCOPE_ONELEVEL : LDAP_SCOPE_SUBTREE;
291
292    if (urld->lud_filter) {
293        if (urld->lud_filter[0] == '(') {
294            /*
295             * Get rid of the surrounding parens; later on when generating the
296             * filter, they'll be put back.
297             */
298            conf->filter = apr_pstrdup(cmd->pool, urld->lud_filter+1);
299            conf->filter[strlen(conf->filter)-1] = '\0';
300        }
301        else {
302            conf->filter = apr_pstrdup(cmd->pool, urld->lud_filter);
303        }
304    }
305    else {
306        conf->filter = "objectClass=apacheConfig";
307    }
308
309      /* "ldaps" indicates secure ldap connections desired
310      */
311    if (strncasecmp(url, "ldaps", 5) == 0)
312    {
313        conf->secure = 1;
314        conf->port = urld->lud_port? urld->lud_port : LDAPS_PORT;
315        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
316                     "LDAP: vhost_ldap using SSL connections");
317    }
318    else
319    {
320        conf->secure = 0;
321        conf->port = urld->lud_port? urld->lud_port : LDAP_PORT;
322        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server, 
323                     "LDAP: vhost_ldap not using SSL connections");
324    }
325
326    conf->have_ldap_url = 1;
327#if (APR_MAJOR_VERSION < 1) /* free only required for older apr */
328    apr_ldap_free_urldesc(urld);
329#endif
330    return NULL;
331}
332
333static const char *mod_vhost_ldap_set_enabled(cmd_parms *cmd, void *dummy, int enabled)
334{
335    mod_vhost_ldap_config_t *conf =
336        (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
337                                                        &vhost_ldap_module);
338
339    conf->enabled = (enabled) ? MVL_ENABLED : MVL_DISABLED;
340
341    return NULL;
342}
343
344static const char *mod_vhost_ldap_set_binddn(cmd_parms *cmd, void *dummy, const char *binddn)
345{
346    mod_vhost_ldap_config_t *conf =
347        (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
348                                                        &vhost_ldap_module);
349
350    conf->binddn = apr_pstrdup(cmd->pool, binddn);
351    return NULL;
352}
353
354static const char *mod_vhost_ldap_set_bindpw(cmd_parms *cmd, void *dummy, const char *bindpw)
355{
356    mod_vhost_ldap_config_t *conf =
357        (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
358                                                        &vhost_ldap_module);
359
360    conf->bindpw = apr_pstrdup(cmd->pool, bindpw);
361    return NULL;
362}
363
364static const char *mod_vhost_ldap_set_deref(cmd_parms *cmd, void *dummy, const char *deref)
365{
366    mod_vhost_ldap_config_t *conf = 
367        (mod_vhost_ldap_config_t *)ap_get_module_config (cmd->server->module_config,
368                                                         &vhost_ldap_module);
369
370    if (strcmp(deref, "never") == 0 || strcasecmp(deref, "off") == 0) {
371        conf->deref = never;
372        conf->have_deref = 1;
373    }
374    else if (strcmp(deref, "searching") == 0) {
375        conf->deref = searching;
376        conf->have_deref = 1;
377    }
378    else if (strcmp(deref, "finding") == 0) {
379        conf->deref = finding;
380        conf->have_deref = 1;
381    }
382    else if (strcmp(deref, "always") == 0 || strcasecmp(deref, "on") == 0) {
383        conf->deref = always;
384        conf->have_deref = 1;
385    }
386    else {
387        return "Unrecognized value for VhostLDAPAliasDereference directive";
388    }
389    return NULL;
390}
391
392static const char *mod_vhost_ldap_set_fallback(cmd_parms *cmd, void *dummy, const char *fallback)
393{
394    mod_vhost_ldap_config_t *conf =
395        (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
396                                                        &vhost_ldap_module);
397
398    conf->fallback = apr_pstrdup(cmd->pool, fallback);
399    return NULL;
400}
401
402command_rec mod_vhost_ldap_cmds[] = {
403    AP_INIT_TAKE1("VhostLDAPURL", mod_vhost_ldap_parse_url, NULL, RSRC_CONF,
404                  "URL to define LDAP connection. This should be an RFC 2255 compliant\n"
405                  "URL of the form ldap://host[:port]/basedn[?attrib[?scope[?filter]]].\n"
406                  "<ul>\n"
407                  "<li>Host is the name of the LDAP server. Use a space separated list of hosts \n"
408                  "to specify redundant servers.\n"
409                  "<li>Port is optional, and specifies the port to connect to.\n"
410                  "<li>basedn specifies the base DN to start searches from\n"
411                  "</ul>\n"),
412
413    AP_INIT_TAKE1 ("VhostLDAPBindDN", mod_vhost_ldap_set_binddn, NULL, RSRC_CONF,
414                   "DN to use to bind to LDAP server. If not provided, will do an anonymous bind."),
415   
416    AP_INIT_TAKE1("VhostLDAPBindPassword", mod_vhost_ldap_set_bindpw, NULL, RSRC_CONF,
417                  "Password to use to bind to LDAP server. If not provided, will do an anonymous bind."),
418
419    AP_INIT_FLAG("VhostLDAPEnabled", mod_vhost_ldap_set_enabled, NULL, RSRC_CONF,
420                 "Set to off to disable vhost_ldap, even if it's been enabled in a higher tree"),
421
422    AP_INIT_TAKE1("VhostLDAPDereferenceAliases", mod_vhost_ldap_set_deref, NULL, RSRC_CONF,
423                  "Determines how aliases are handled during a search. Can be one of the"
424                  "values \"never\", \"searching\", \"finding\", or \"always\". "
425                  "Defaults to always."),
426
427    AP_INIT_TAKE1("VhostLDAPFallback", mod_vhost_ldap_set_fallback, NULL, RSRC_CONF,
428                  "Set default virtual host which will be used when requested hostname"
429                  "is not found in LDAP database. This option can be used to display"
430                  "\"virtual host not found\" type of page."),
431
432    {NULL}
433};
434
435#define FILTER_LENGTH MAX_STRING_LEN
436static int mod_vhost_ldap_translate_name(request_rec *r)
437{
[1603]438    server_rec *server;
439    const char *error;
[479]440    mod_vhost_ldap_request_t *reqc;
441    int failures = 0;
442    const char **vals = NULL;
443    char filtbuf[FILTER_LENGTH];
444    mod_vhost_ldap_config_t *conf =
445        (mod_vhost_ldap_config_t *)ap_get_module_config(r->server->module_config, &vhost_ldap_module);
[1603]446    core_server_config *core;
[479]447    util_ldap_connection_t *ldc = NULL;
448    int result = 0;
449    const char *dn = NULL;
450    char *cgi;
[688]451    const char *hostname = NULL;
[479]452    int is_fallback = 0;
[1588]453    int sleep0 = 0;
454    int sleep1 = 1;
455    int sleep;
456    struct berval hostnamebv, shostnamebv;
[1589]457    int ret = DECLINED;
[479]458
[1603]459    if ((error = ap_init_virtual_host(r->pool, "", r->server, &server)) != NULL) {
460        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r,
461                      "[mod_vhost_ldap.c]: Could not initialize a new VirtualHost: %s",
462                      error);
463        return HTTP_INTERNAL_SERVER_ERROR;
464    }
465
466    core = core_module.create_server_config(r->pool, server);
467    ap_set_module_config(server->module_config, &core_module, core);
468
[479]469    reqc =
470        (mod_vhost_ldap_request_t *)apr_pcalloc(r->pool, sizeof(mod_vhost_ldap_request_t));
471    memset(reqc, 0, sizeof(mod_vhost_ldap_request_t)); 
472
473    ap_set_module_config(r->request_config, &vhost_ldap_module, reqc);
474
475    // mod_vhost_ldap is disabled or we don't have LDAP Url
476    if ((conf->enabled != MVL_ENABLED)||(!conf->have_ldap_url)) {
477        return DECLINED;
478    }
479
480start_over:
481
482    if (conf->host) {
483        ldc = util_ldap_connection_find(r, conf->host, conf->port,
484                                        conf->binddn, conf->bindpw, conf->deref,
485                                        conf->secure);
486    }
487    else {
488        ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r, 
489                      "[mod_vhost_ldap.c] translate: no conf->host - weird...?");
[1588]490        return HTTP_INTERNAL_SERVER_ERROR;
[479]491    }
492
493    hostname = r->hostname;
[688]494    if (hostname == NULL || hostname[0] == '\0')
[1588]495        goto null;
[479]496
497fallback:
498
499    ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
[1588]500                  "[mod_vhost_ldap.c]: translating hostname [%s], uri [%s]",
501                  hostname, r->uri);
[479]502
[688]503    ber_str2bv(hostname, 0, 0, &hostnamebv);
504    if (ldap_bv2escaped_filter_value(&hostnamebv, &shostnamebv) != 0)
505        goto null;
506    apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(|(apacheServerName=%s)(apacheServerAlias=%s)))", conf->filter, shostnamebv.bv_val, shostnamebv.bv_val);
507    ber_memfree(shostnamebv.bv_val);
[479]508
509    result = util_ldap_cache_getuserdn(r, ldc, conf->url, conf->basedn, conf->scope,
510                                       attributes, filtbuf, &dn, &vals);
511
512    util_ldap_connection_close(ldc);
513
514    /* sanity check - if server is down, retry it up to 5 times */
[1588]515    if (AP_LDAP_IS_SERVER_DOWN(result) ||
516        (result == LDAP_TIMEOUT) ||
517        (result == LDAP_CONNECT_ERROR)) {
518        sleep = sleep0 + sleep1;
519        ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
520                      "[mod_vhost_ldap.c]: lookup failure, retry number #[%d], sleeping for [%d] seconds",
521                      failures, sleep);
522        if (failures++ < MAX_FAILURES) {
523            /* Back-off exponentially */
524            apr_sleep(apr_time_from_sec(sleep));
525            sleep0 = sleep1;
526            sleep1 = sleep;
[479]527            goto start_over;
[1588]528        } else {
529            return HTTP_GATEWAY_TIME_OUT;
530        }
[479]531    }
532
[1588]533    if (result == LDAP_NO_SUCH_OBJECT) {
[680]534        if (strcmp(hostname, "*") != 0) {
535            if (strncmp(hostname, "*.", 2) == 0)
536                hostname += 2;
537            hostname += strcspn(hostname, ".");
538            hostname = apr_pstrcat(r->pool, "*", hostname, NULL);
[675]539            ap_log_rerror(APLOG_MARK, APLOG_NOTICE|APLOG_NOERRNO, 0, r,
540                          "[mod_vhost_ldap.c] translate: "
541                          "virtual host not found, trying wildcard %s",
[680]542                          hostname);
[675]543            goto fallback;
544        }
[679]545
[1588]546null:
[479]547        if (conf->fallback && (is_fallback++ <= 0)) {
548            ap_log_rerror(APLOG_MARK, APLOG_NOTICE|APLOG_NOERRNO, 0, r,
549                          "[mod_vhost_ldap.c] translate: "
550                          "virtual host %s not found, trying fallback %s",
551                          hostname, conf->fallback);
552            hostname = conf->fallback;
553            goto fallback;
554        }
555
556        ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
557                      "[mod_vhost_ldap.c] translate: "
558                      "virtual host %s not found",
559                      hostname);
560
[1588]561        return HTTP_BAD_REQUEST;
[479]562    }
563
564    /* handle bind failure */
565    if (result != LDAP_SUCCESS) {
566        ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r, 
567                      "[mod_vhost_ldap.c] translate: "
568                      "translate failed; virtual host %s; URI %s [%s]",
569                      hostname, r->uri, ldap_err2string(result));
[1588]570        return HTTP_INTERNAL_SERVER_ERROR;
[479]571    }
572
573    /* mark the user and DN */
574    reqc->dn = apr_pstrdup(r->pool, dn);
575
576    /* Optimize */
577    if (vals) {
[1604]578        int i;
579        for (i = 0; attributes[i]; i++) {
[479]580
[1604]581            char *val = apr_pstrdup (r->pool, vals[i]);
[479]582            if (strcasecmp (attributes[i], "apacheServerName") == 0) {
[1604]583                reqc->name = val;
[479]584            }
585            else if (strcasecmp (attributes[i], "apacheServerAdmin") == 0) {
[1604]586                reqc->admin = val;
[479]587            }
588            else if (strcasecmp (attributes[i], "apacheDocumentRoot") == 0) {
[1604]589                reqc->docroot = val;
[479]590            }
591            else if (strcasecmp (attributes[i], "apacheScriptAlias") == 0) {
[1604]592                reqc->cgiroot = val;
[479]593            }
594            else if (strcasecmp (attributes[i], "apacheSuexecUid") == 0) {
[1604]595                reqc->uid = val;
[479]596            }
597            else if (strcasecmp (attributes[i], "apacheSuexecGid") == 0) {
[1604]598                reqc->gid = val;
[479]599            }
600        }
601    }
602
603    ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
604                  "[mod_vhost_ldap.c]: loaded from ldap: "
605                  "apacheServerName: %s, "
606                  "apacheServerAdmin: %s, "
607                  "apacheDocumentRoot: %s, "
608                  "apacheScriptAlias: %s, "
609                  "apacheSuexecUid: %s, "
610                  "apacheSuexecGid: %s",
611                  reqc->name, reqc->admin, reqc->docroot, reqc->cgiroot, reqc->uid, reqc->gid);
612
613    if ((reqc->name == NULL)||(reqc->docroot == NULL)) {
614        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, 
615                      "[mod_vhost_ldap.c] translate: "
616                      "translate failed; ServerName or DocumentRoot not defined");
[1588]617        return HTTP_INTERNAL_SERVER_ERROR;
[479]618    }
619
620    cgi = NULL;
[1588]621
[479]622    if (reqc->cgiroot) {
623        cgi = strstr(r->uri, "cgi-bin/");
624        if (cgi && (cgi != r->uri + strspn(r->uri, "/"))) {
625            cgi = NULL;
626        }
627    }
628    if (cgi) {
[1588]629        /* Set exact filename for CGI script */
630        cgi = apr_pstrcat(r->pool, reqc->cgiroot, cgi + strlen("cgi-bin"), NULL);
631        if ((cgi = ap_server_root_relative(r->pool, cgi))) {
632          ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
633                        "[mod_vhost_ldap.c]: ap_document_root is: %s",
634                        ap_document_root(r));
635          r->filename = cgi;
636          r->handler = "cgi-script";
637          apr_table_setn(r->notes, "alias-forced-type", r->handler);
[1589]638          ret = OK;
[1588]639        }
[1589]640    } else if (strncmp(r->uri, "/~", 2) == 0) {
641        /* This is a quick, dirty hack. I should be shot for taking 6.170
642         * this term and being willing to write a quick, dirty hack. */   
[481]643        char *username;
644        uid_t uid = (uid_t)atoll(reqc->uid);
645        if (apr_uid_name_get(&username, uid, r->pool) != APR_SUCCESS) {
646            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, 
647                          "could not get username for uid %d", uid);
648            return DECLINED;
649        }
650        if (strncmp(r->uri + 2, username, strlen(username)) == 0 &&
[483]651            (r->uri[2 + strlen(username)] == '/' ||
652             r->uri[2 + strlen(username)] == '\0')) {
[481]653            char *homedir;
654            if (apr_uid_homepath_get(&homedir, username, r->pool) != APR_SUCCESS) {
655                ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, 
656                              "could not get home directory for user %s", username);
657                return DECLINED;
658            }
659            r->filename = apr_pstrcat(r->pool, homedir, "/", USERDIR, r->uri + 2 + strlen(username), NULL);
[1589]660            ret = OK;
[481]661        }
[479]662    } else if (r->uri[0] == '/') {
[1588]663        /* we don't set r->filename here, and let other modules do it
664         * this allows other modules (mod_rewrite.c) to work as usual
665         */
666        /* r->filename = apr_pstrcat (r->pool, reqc->docroot, r->uri, NULL); */
[479]667    } else {
[1588]668        /* We don't handle non-file requests here */
[479]669        return DECLINED;
670    }
671
[1603]672    server->server_hostname = reqc->name;
[479]673
674    if (reqc->admin) {
[1603]675        server->server_admin = reqc->admin;
[479]676    }
677
[1588]678    /* Stolen from server/core.c */
[1463]679
[1588]680    /* Make it absolute, relative to ServerRoot */
681    reqc->docroot = ap_server_root_relative(r->pool, reqc->docroot);
[479]682
[1588]683    if (reqc->docroot == NULL) {
684        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, 
685                      "[mod_vhost_ldap.c] set_document_root: DocumentRoot must be a directory");
686
687        return HTTP_INTERNAL_SERVER_ERROR;
688    }
689
690    /* TODO: ap_configtestonly && ap_docrootcheck && */
691    if (apr_filepath_merge((char**)&core->ap_document_root, NULL, reqc->docroot,
692                           APR_FILEPATH_TRUENAME, r->pool) != APR_SUCCESS
693        || !ap_is_directory(r->pool, reqc->docroot)) {
694
695        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
696                      "[mod_vhost_ldap.c] set_document_root: Warning: DocumentRoot [%s] does not exist",
697                      reqc->docroot);
698        core->ap_document_root = reqc->docroot;
699    }
700
[1603]701    ap_fixup_virtual_host(r->pool, r->server, server);
702    r->server = server;
703
[1588]704    /* Hack to allow post-processing by other modules (mod_rewrite, mod_alias) */
[1589]705    return ret;
[479]706}
707
708#ifdef HAVE_UNIX_SUEXEC
709static ap_unix_identity_t *mod_vhost_ldap_get_suexec_id_doer(const request_rec * r)
710{
711  ap_unix_identity_t *ugid = NULL;
712  mod_vhost_ldap_config_t *conf = 
713      (mod_vhost_ldap_config_t *)ap_get_module_config(r->server->module_config,
714                                                      &vhost_ldap_module);
715  mod_vhost_ldap_request_t *req =
716      (mod_vhost_ldap_request_t *)ap_get_module_config(r->request_config,
717                                                       &vhost_ldap_module);
718
719  uid_t uid = -1;
720  gid_t gid = -1;
721
722  // mod_vhost_ldap is disabled or we don't have LDAP Url
723  if ((conf->enabled != MVL_ENABLED)||(!conf->have_ldap_url)) {
724      return NULL;
725  }
726
727  if ((req == NULL)||(req->uid == NULL)||(req->gid == NULL)) {
728      return NULL;
729  }
730
731  if ((ugid = apr_palloc(r->pool, sizeof(ap_unix_identity_t))) == NULL) {
732      return NULL;
733  }
734
735  uid = (uid_t)atoll(req->uid);
736  gid = (gid_t)atoll(req->gid);
737
738  if ((uid < MIN_UID)||(gid < MIN_GID)) {
739      return NULL;
740  }
741
742  ugid->uid = uid;
743  ugid->gid = gid;
744  ugid->userdir = 0;
745 
746  return ugid;
747}
748#endif
749
750static void
751mod_vhost_ldap_register_hooks (apr_pool_t * p)
752{
[1588]753
754    /*
755     * Run before mod_rewrite
756     */
757    static const char * const aszRewrite[]={ "mod_rewrite.c", NULL };
758
[479]759    ap_hook_post_config(mod_vhost_ldap_post_config, NULL, NULL, APR_HOOK_MIDDLE);
[1588]760    ap_hook_translate_name(mod_vhost_ldap_translate_name, NULL, aszRewrite, APR_HOOK_FIRST);
[479]761#ifdef HAVE_UNIX_SUEXEC
762    ap_hook_get_suexec_identity(mod_vhost_ldap_get_suexec_id_doer, NULL, NULL, APR_HOOK_MIDDLE);
763#endif
764#if (APR_MAJOR_VERSION >= 1)
765    ap_hook_optional_fn_retrieve(ImportULDAPOptFn,NULL,NULL,APR_HOOK_MIDDLE);
766#endif
767}
768
769module AP_MODULE_DECLARE_DATA vhost_ldap_module = {
770  STANDARD20_MODULE_STUFF,
771  NULL,
772  NULL,
773  mod_vhost_ldap_create_server_config,
774  mod_vhost_ldap_merge_server_config,
775  mod_vhost_ldap_cmds,
776  mod_vhost_ldap_register_hooks,
777};
Note: See TracBrowser for help on using the repository browser.