source: server/common/oursrc/httpdmods/mod_vhost_ldap.c @ 679

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