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

Last change on this file was 2760, checked in by andersk, 8 years ago
mod_vhost_ldap: Quote configuration arguments for ap_getword_conf
  • Property svn:eol-style set to native
File size: 25.4 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_reslist.h"
35#include "apr_strings.h"
36#include "apr_tables.h"
37#include "util_ldap.h"
38#include "util_script.h"
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
54const char USERDIR[] = "web_scripts";
55
56#define MAX_FAILURES 5
57
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 *home;                         /* HOME */
93    char *directory;                    /* DocumentRoot relative to HOME/web_scripts */
94    char *uid;                          /* Suexec Uid */
95    char *gid;                          /* Suexec Gid */
96} mod_vhost_ldap_request_t;
97
98char *attributes[] =
99  { "scriptsVhostName", "homeDirectory", "scriptsVhostDirectory", "uidNumber", "gidNumber", 0 };
100
101static int total_modules;
102
103#if (APR_MAJOR_VERSION >= 1)
104static APR_OPTIONAL_FN_TYPE(uldap_connection_close) *util_ldap_connection_close;
105static APR_OPTIONAL_FN_TYPE(uldap_connection_find) *util_ldap_connection_find;
106static APR_OPTIONAL_FN_TYPE(uldap_cache_comparedn) *util_ldap_cache_comparedn;
107static APR_OPTIONAL_FN_TYPE(uldap_cache_compare) *util_ldap_cache_compare;
108static APR_OPTIONAL_FN_TYPE(uldap_cache_checkuserid) *util_ldap_cache_checkuserid;
109static APR_OPTIONAL_FN_TYPE(uldap_cache_getuserdn) *util_ldap_cache_getuserdn;
110static APR_OPTIONAL_FN_TYPE(uldap_ssl_supported) *util_ldap_ssl_supported;
111
112static void ImportULDAPOptFn(void)
113{
114    util_ldap_connection_close  = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_close);
115    util_ldap_connection_find   = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_find);
116    util_ldap_cache_comparedn   = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_comparedn);
117    util_ldap_cache_compare     = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_compare);
118    util_ldap_cache_checkuserid = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_checkuserid);
119    util_ldap_cache_getuserdn   = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_getuserdn);
120    util_ldap_ssl_supported     = APR_RETRIEVE_OPTIONAL_FN(uldap_ssl_supported);
121}
122#endif
123
124static int mod_vhost_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
125{
126    module **m;
127   
128    /* Stolen from modules/generators/mod_cgid.c */
129    total_modules = 0;
130    for (m = ap_preloaded_modules; *m != NULL; m++)
131      total_modules++;
132
133    /* make sure that mod_ldap (util_ldap) is loaded */
134    if (ap_find_linked_module("util_ldap.c") == NULL) {
135        ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, s,
136                     "Module mod_ldap missing. Mod_ldap (aka. util_ldap) "
137                     "must be loaded in order for mod_vhost_ldap to function properly");
138        return HTTP_INTERNAL_SERVER_ERROR;
139
140    }
141
142    ap_add_version_component(p, MOD_VHOST_LDAP_VERSION);
143
144    return OK;
145}
146
147static void *
148mod_vhost_ldap_create_server_config (apr_pool_t *p, server_rec *s)
149{
150    mod_vhost_ldap_config_t *conf =
151        (mod_vhost_ldap_config_t *)apr_pcalloc(p, sizeof (mod_vhost_ldap_config_t));
152
153    conf->enabled = MVL_UNSET;
154    conf->have_ldap_url = 0;
155    conf->have_deref = 0;
156    conf->binddn = NULL;
157    conf->bindpw = NULL;
158    conf->deref = always;
159    conf->fallback = NULL;
160
161    return conf;
162}
163
164static void *
165mod_vhost_ldap_merge_server_config(apr_pool_t *p, void *parentv, void *childv)
166{
167    mod_vhost_ldap_config_t *parent = (mod_vhost_ldap_config_t *) parentv;
168    mod_vhost_ldap_config_t *child  = (mod_vhost_ldap_config_t *) childv;
169    mod_vhost_ldap_config_t *conf =
170        (mod_vhost_ldap_config_t *)apr_pcalloc(p, sizeof(mod_vhost_ldap_config_t));
171
172    if (child->enabled == MVL_UNSET) {
173        conf->enabled = parent->enabled;
174    } else {
175        conf->enabled = child->enabled;
176    }
177
178    if (child->have_ldap_url) {
179        conf->have_ldap_url = child->have_ldap_url;
180        conf->url = child->url;
181        conf->host = child->host;
182        conf->port = child->port;
183        conf->basedn = child->basedn;
184        conf->scope = child->scope;
185        conf->filter = child->filter;
186        conf->secure = child->secure;
187    } else {
188        conf->have_ldap_url = parent->have_ldap_url;
189        conf->url = parent->url;
190        conf->host = parent->host;
191        conf->port = parent->port;
192        conf->basedn = parent->basedn;
193        conf->scope = parent->scope;
194        conf->filter = parent->filter;
195        conf->secure = parent->secure;
196    }
197    if (child->have_deref) {
198        conf->have_deref = child->have_deref;
199        conf->deref = child->deref;
200    } else {
201        conf->have_deref = parent->have_deref;
202        conf->deref = parent->deref;
203    }
204
205    conf->binddn = (child->binddn ? child->binddn : parent->binddn);
206    conf->bindpw = (child->bindpw ? child->bindpw : parent->bindpw);
207
208    conf->fallback = (child->fallback ? child->fallback : parent->fallback);
209
210    return conf;
211}
212
213/*
214 * Use the ldap url parsing routines to break up the ldap url into
215 * host and port.
216 */
217static const char *mod_vhost_ldap_parse_url(cmd_parms *cmd, 
218                                            void *dummy,
219                                            const char *url)
220{
221    int result;
222    apr_ldap_url_desc_t *urld;
223#if (APR_MAJOR_VERSION >= 1)
224    apr_ldap_err_t *result_err;
225#endif
226
227    mod_vhost_ldap_config_t *conf =
228        (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
229                                                        &vhost_ldap_module);
230
231    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
232                 cmd->server, "[mod_vhost_ldap.c] url parse: `%s'", 
233                 url);
234   
235#if (APR_MAJOR_VERSION >= 1)    /* for apache >= 2.2 */
236    result = apr_ldap_url_parse(cmd->pool, url, &(urld), &(result_err));
237    if (result != LDAP_SUCCESS) {
238        return result_err->reason;
239    }
240#else
241    result = apr_ldap_url_parse(url, &(urld));
242    if (result != LDAP_SUCCESS) {
243        switch (result) {
244            case LDAP_URL_ERR_NOTLDAP:
245                return "LDAP URL does not begin with ldap://";
246            case LDAP_URL_ERR_NODN:
247                return "LDAP URL does not have a DN";
248            case LDAP_URL_ERR_BADSCOPE:
249                return "LDAP URL has an invalid scope";
250            case LDAP_URL_ERR_MEM:
251                return "Out of memory parsing LDAP URL";
252            default:
253                return "Could not parse LDAP URL";
254        }
255    }
256#endif
257    conf->url = apr_pstrdup(cmd->pool, url);
258
259    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
260                 cmd->server, "[mod_vhost_ldap.c] url parse: Host: %s", urld->lud_host);
261    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
262                 cmd->server, "[mod_vhost_ldap.c] url parse: Port: %d", urld->lud_port);
263    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
264                 cmd->server, "[mod_vhost_ldap.c] url parse: DN: %s", urld->lud_dn);
265    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
266                 cmd->server, "[mod_vhost_ldap.c] url parse: attrib: %s", urld->lud_attrs? urld->lud_attrs[0] : "(null)");
267    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
268                 cmd->server, "[mod_vhost_ldap.c] url parse: scope: %s", 
269                 (urld->lud_scope == LDAP_SCOPE_SUBTREE? "subtree" : 
270                 urld->lud_scope == LDAP_SCOPE_BASE? "base" : 
271                 urld->lud_scope == LDAP_SCOPE_ONELEVEL? "onelevel" : "unknown"));
272    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
273                 cmd->server, "[mod_vhost_ldap.c] url parse: filter: %s", urld->lud_filter);
274
275    /* Set all the values, or at least some sane defaults */
276    if (conf->host) {
277        char *p = apr_palloc(cmd->pool, strlen(conf->host) + strlen(urld->lud_host) + 2);
278        strcpy(p, urld->lud_host);
279        strcat(p, " ");
280        strcat(p, conf->host);
281        conf->host = p;
282    }
283    else {
284        conf->host = urld->lud_host? apr_pstrdup(cmd->pool, urld->lud_host) : "localhost";
285    }
286    conf->basedn = urld->lud_dn? apr_pstrdup(cmd->pool, urld->lud_dn) : "";
287
288    conf->scope = urld->lud_scope == LDAP_SCOPE_ONELEVEL ?
289        LDAP_SCOPE_ONELEVEL : LDAP_SCOPE_SUBTREE;
290
291    if (urld->lud_filter) {
292        if (urld->lud_filter[0] == '(') {
293            /*
294             * Get rid of the surrounding parens; later on when generating the
295             * filter, they'll be put back.
296             */
297            conf->filter = apr_pstrdup(cmd->pool, urld->lud_filter+1);
298            conf->filter[strlen(conf->filter)-1] = '\0';
299        }
300        else {
301            conf->filter = apr_pstrdup(cmd->pool, urld->lud_filter);
302        }
303    }
304    else {
305        conf->filter = "objectClass=scriptsVhost";
306    }
307
308      /* "ldaps" indicates secure ldap connections desired
309      */
310    if (strncasecmp(url, "ldaps", 5) == 0)
311    {
312        conf->secure = 1;
313        conf->port = urld->lud_port? urld->lud_port : LDAPS_PORT;
314        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
315                     "LDAP: vhost_ldap using SSL connections");
316    }
317    else
318    {
319        conf->secure = 0;
320        conf->port = urld->lud_port? urld->lud_port : LDAP_PORT;
321        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server, 
322                     "LDAP: vhost_ldap not using SSL connections");
323    }
324
325    conf->have_ldap_url = 1;
326#if (APR_MAJOR_VERSION < 1) /* free only required for older apr */
327    apr_ldap_free_urldesc(urld);
328#endif
329    return NULL;
330}
331
332static const char *mod_vhost_ldap_set_enabled(cmd_parms *cmd, void *dummy, int enabled)
333{
334    mod_vhost_ldap_config_t *conf =
335        (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
336                                                        &vhost_ldap_module);
337
338    conf->enabled = (enabled) ? MVL_ENABLED : MVL_DISABLED;
339
340    return NULL;
341}
342
343static const char *mod_vhost_ldap_set_binddn(cmd_parms *cmd, void *dummy, const char *binddn)
344{
345    mod_vhost_ldap_config_t *conf =
346        (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
347                                                        &vhost_ldap_module);
348
349    conf->binddn = apr_pstrdup(cmd->pool, binddn);
350    return NULL;
351}
352
353static const char *mod_vhost_ldap_set_bindpw(cmd_parms *cmd, void *dummy, const char *bindpw)
354{
355    mod_vhost_ldap_config_t *conf =
356        (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
357                                                        &vhost_ldap_module);
358
359    conf->bindpw = apr_pstrdup(cmd->pool, bindpw);
360    return NULL;
361}
362
363static const char *mod_vhost_ldap_set_deref(cmd_parms *cmd, void *dummy, const char *deref)
364{
365    mod_vhost_ldap_config_t *conf = 
366        (mod_vhost_ldap_config_t *)ap_get_module_config (cmd->server->module_config,
367                                                         &vhost_ldap_module);
368
369    if (strcmp(deref, "never") == 0 || strcasecmp(deref, "off") == 0) {
370        conf->deref = never;
371        conf->have_deref = 1;
372    }
373    else if (strcmp(deref, "searching") == 0) {
374        conf->deref = searching;
375        conf->have_deref = 1;
376    }
377    else if (strcmp(deref, "finding") == 0) {
378        conf->deref = finding;
379        conf->have_deref = 1;
380    }
381    else if (strcmp(deref, "always") == 0 || strcasecmp(deref, "on") == 0) {
382        conf->deref = always;
383        conf->have_deref = 1;
384    }
385    else {
386        return "Unrecognized value for VhostLDAPAliasDereference directive";
387    }
388    return NULL;
389}
390
391static const char *mod_vhost_ldap_set_fallback(cmd_parms *cmd, void *dummy, const char *fallback)
392{
393    mod_vhost_ldap_config_t *conf =
394        (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
395                                                        &vhost_ldap_module);
396
397    conf->fallback = apr_pstrdup(cmd->pool, fallback);
398    return NULL;
399}
400
401static const char *escape(apr_pool_t *p, const char *input)
402{
403    static const char *const to_escape = "'\\";
404
405    const char *x = input + strcspn(input, to_escape);
406    if (*x == '\0')
407        return input;
408    const char *y = x;
409    size_t extra = 0;
410    while (*y != '\0') {
411        extra++;
412        size_t k = strcspn(y + 1, to_escape) + 1;
413        y += k;
414    }
415
416    char *output = apr_palloc(p, y - input + extra + 1);
417
418    memcpy(output, input, x - input);
419    char *z = output + (x - input);
420    while (*x != '\0') {
421        *z++ = '\\';
422        size_t k = strcspn(x + 1, to_escape) + 1;
423        memcpy(z, x, k);
424        x += k;
425        z += k;
426    }
427    *z = '\0';
428
429    return output;
430}
431
432static int reconfigure_directive(apr_pool_t *p,
433                                 server_rec *s,
434                                 const char *dir,
435                                 const char *args)
436{
437    ap_directive_t dir_s = { .directive = dir, .args = args, .next = NULL,
438                             .line_num = 0, .filename = "VhostLDAPConf" };
439    return ap_process_config_tree(s, &dir_s, p, p);
440}
441
442command_rec mod_vhost_ldap_cmds[] = {
443    AP_INIT_TAKE1("VhostLDAPURL", mod_vhost_ldap_parse_url, NULL, RSRC_CONF,
444                  "URL to define LDAP connection. This should be an RFC 2255 compliant\n"
445                  "URL of the form ldap://host[:port]/basedn[?attrib[?scope[?filter]]].\n"
446                  "<ul>\n"
447                  "<li>Host is the name of the LDAP server. Use a space separated list of hosts \n"
448                  "to specify redundant servers.\n"
449                  "<li>Port is optional, and specifies the port to connect to.\n"
450                  "<li>basedn specifies the base DN to start searches from\n"
451                  "</ul>\n"),
452
453    AP_INIT_TAKE1 ("VhostLDAPBindDN", mod_vhost_ldap_set_binddn, NULL, RSRC_CONF,
454                   "DN to use to bind to LDAP server. If not provided, will do an anonymous bind."),
455   
456    AP_INIT_TAKE1("VhostLDAPBindPassword", mod_vhost_ldap_set_bindpw, NULL, RSRC_CONF,
457                  "Password to use to bind to LDAP server. If not provided, will do an anonymous bind."),
458
459    AP_INIT_FLAG("VhostLDAPEnabled", mod_vhost_ldap_set_enabled, NULL, RSRC_CONF,
460                 "Set to off to disable vhost_ldap, even if it's been enabled in a higher tree"),
461
462    AP_INIT_TAKE1("VhostLDAPDereferenceAliases", mod_vhost_ldap_set_deref, NULL, RSRC_CONF,
463                  "Determines how aliases are handled during a search. Can be one of the"
464                  "values \"never\", \"searching\", \"finding\", or \"always\". "
465                  "Defaults to always."),
466
467    AP_INIT_TAKE1("VhostLDAPFallback", mod_vhost_ldap_set_fallback, NULL, RSRC_CONF,
468                  "Set default virtual host which will be used when requested hostname"
469                  "is not found in LDAP database. This option can be used to display"
470                  "\"virtual host not found\" type of page."),
471
472    {NULL}
473};
474
475#define FILTER_LENGTH MAX_STRING_LEN
476static int mod_vhost_ldap_translate_name(request_rec *r)
477{
478    server_rec *server;
479    const char *error;
480    int code;
481    mod_vhost_ldap_request_t *reqc;
482    int failures = 0;
483    const char **vals = NULL;
484    char filtbuf[FILTER_LENGTH];
485    mod_vhost_ldap_config_t *conf =
486        (mod_vhost_ldap_config_t *)ap_get_module_config(r->server->module_config, &vhost_ldap_module);
487    util_ldap_connection_t *ldc = NULL;
488    int result = 0;
489    const char *dn = NULL;
490    const char *hostname = NULL;
491    int is_fallback = 0;
492    int sleep0 = 0;
493    int sleep1 = 1;
494    int sleep;
495    struct berval hostnamebv, shostnamebv;
496
497    if ((error = ap_init_virtual_host(r->pool, "", r->server, &server)) != NULL) {
498        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r,
499                      "[mod_vhost_ldap.c]: Could not initialize a new VirtualHost: %s",
500                      error);
501        return HTTP_INTERNAL_SERVER_ERROR;
502    }
503
504    reqc =
505        (mod_vhost_ldap_request_t *)apr_pcalloc(r->pool, sizeof(mod_vhost_ldap_request_t));
506    memset(reqc, 0, sizeof(mod_vhost_ldap_request_t)); 
507
508    ap_set_module_config(r->request_config, &vhost_ldap_module, reqc);
509
510    // mod_vhost_ldap is disabled or we don't have LDAP Url
511    if ((conf->enabled != MVL_ENABLED)||(!conf->have_ldap_url)) {
512        return DECLINED;
513    }
514
515start_over:
516
517    if (conf->host) {
518        ldc = util_ldap_connection_find(r, conf->host, conf->port,
519                                        conf->binddn, conf->bindpw, conf->deref,
520                                        conf->secure);
521    }
522    else {
523        ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r, 
524                      "[mod_vhost_ldap.c] translate: no conf->host - weird...?");
525        return HTTP_INTERNAL_SERVER_ERROR;
526    }
527
528    hostname = r->hostname;
529    if (hostname == NULL || hostname[0] == '\0')
530        goto null;
531
532fallback:
533
534    ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
535                  "[mod_vhost_ldap.c]: translating hostname [%s], uri [%s]",
536                  hostname, r->uri);
537
538    ber_str2bv(hostname, 0, 0, &hostnamebv);
539    if (ldap_bv2escaped_filter_value(&hostnamebv, &shostnamebv) != 0)
540        goto null;
541    apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(|(scriptsVhostName=%s)(scriptsVhostAlias=%s)))", conf->filter, shostnamebv.bv_val, shostnamebv.bv_val);
542    ber_memfree(shostnamebv.bv_val);
543
544    result = util_ldap_cache_getuserdn(r, ldc, conf->url, conf->basedn, conf->scope,
545                                       attributes, filtbuf, &dn, &vals);
546
547    util_ldap_connection_close(ldc);
548
549    /* sanity check - if server is down, retry it up to 5 times */
550    if (AP_LDAP_IS_SERVER_DOWN(result) ||
551        (result == LDAP_TIMEOUT) ||
552        (result == LDAP_CONNECT_ERROR)) {
553        sleep = sleep0 + sleep1;
554        ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
555                      "[mod_vhost_ldap.c]: lookup failure, retry number #[%d], sleeping for [%d] seconds",
556                      failures, sleep);
557        if (failures++ < MAX_FAILURES) {
558            /* Back-off exponentially */
559            apr_sleep(apr_time_from_sec(sleep));
560            sleep0 = sleep1;
561            sleep1 = sleep;
562            goto start_over;
563        } else {
564            return HTTP_GATEWAY_TIME_OUT;
565        }
566    }
567
568    if (result == LDAP_NO_SUCH_OBJECT) {
569        if (strcmp(hostname, "*") != 0) {
570            if (strncmp(hostname, "*.", 2) == 0)
571                hostname += 2;
572            hostname += strcspn(hostname, ".");
573            hostname = apr_pstrcat(r->pool, "*", hostname, (const char *)NULL);
574            ap_log_rerror(APLOG_MARK, APLOG_NOTICE|APLOG_NOERRNO, 0, r,
575                          "[mod_vhost_ldap.c] translate: "
576                          "virtual host not found, trying wildcard %s",
577                          hostname);
578            goto fallback;
579        }
580
581null:
582        if (conf->fallback && (is_fallback++ <= 0)) {
583            ap_log_rerror(APLOG_MARK, APLOG_NOTICE|APLOG_NOERRNO, 0, r,
584                          "[mod_vhost_ldap.c] translate: "
585                          "virtual host %s not found, trying fallback %s",
586                          hostname, conf->fallback);
587            hostname = conf->fallback;
588            goto fallback;
589        }
590
591        ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
592                      "[mod_vhost_ldap.c] translate: "
593                      "virtual host %s not found",
594                      hostname);
595
596        return HTTP_BAD_REQUEST;
597    }
598
599    /* handle bind failure */
600    if (result != LDAP_SUCCESS) {
601        ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r, 
602                      "[mod_vhost_ldap.c] translate: "
603                      "translate failed; virtual host %s; URI %s [%s]",
604                      hostname, r->uri, ldap_err2string(result));
605        return HTTP_INTERNAL_SERVER_ERROR;
606    }
607
608    /* mark the user and DN */
609    reqc->dn = apr_pstrdup(r->pool, dn);
610
611    /* Optimize */
612    if (vals) {
613        int i;
614        for (i = 0; attributes[i]; i++) {
615
616            char *val = apr_pstrdup (r->pool, vals[i]);
617            /* These do not correspond to any real directives */
618            if (strcasecmp (attributes[i], "uidNumber") == 0) {
619                reqc->uid = val;
620                continue;
621            }
622            else if (strcasecmp (attributes[i], "gidNumber") == 0) {
623                reqc->gid = val;
624                continue;
625            }
626            else if (strcasecmp (attributes[i], "homeDirectory") == 0) {
627                reqc->home = val;
628                continue;
629            }
630            else if (strcasecmp (attributes[i], "scriptsVhostDirectory") == 0) {
631                reqc->directory = val;
632                continue;
633            }
634            else if (strcasecmp (attributes[i], "scriptsVhostName") == 0) {
635                reqc->name = val;
636                continue;
637            }
638            else {
639                /* This should not actually be reachable, but it's
640                   good to cover all all possible cases */
641                ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
642                              "Unexpected attribute %s encountered", attributes[i]);
643                continue;
644            }
645        }
646    }
647
648    ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
649                  "[mod_vhost_ldap.c]: loaded from ldap: "
650                  "scriptsVhostName: %s, "
651                  "homeDirectory: %s, "
652                  "scriptsVhostDirectory: %s, "
653                  "uidNumber: %s, "
654                  "gidNumber: %s",
655                  reqc->name, reqc->home, reqc->directory, reqc->uid, reqc->gid);
656
657    if (reqc->name == NULL || reqc->home == NULL || reqc->directory == NULL) {
658        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, 
659                      "[mod_vhost_ldap.c] translate: "
660                      "translate failed; ServerName or DocumentRoot not defined");
661        return HTTP_INTERNAL_SERVER_ERROR;
662    }
663
664    if ((code = reconfigure_directive(
665             r->pool, server, "ServerName",
666             apr_pstrcat(r->pool, "'", escape(r->pool, reqc->name), "'", (const char *)NULL))) != 0)
667        return code;
668
669    char *docroot =
670        strcmp(reqc->directory, ".") == 0 ?
671        apr_pstrcat(r->pool, reqc->home, "/web_scripts", (const char *)NULL) :
672        apr_pstrcat(r->pool, reqc->home, "/web_scripts/", reqc->directory, (const char *)NULL);
673    if ((code = reconfigure_directive(
674             r->pool, server, "DocumentRoot",
675             apr_pstrcat(r->pool, "'", escape(r->pool, docroot), "'", (const char *)NULL))) != 0)
676        return code;
677
678    if (reqc->uid != NULL) {
679        char *username;
680        char *userdir_val;
681        uid_t uid = (uid_t) atoll(reqc->uid);
682
683        if ((code = reconfigure_directive(
684                 r->pool, server, "UserDir",
685                 apr_pstrcat(r->pool, "'", escape(r->pool, USERDIR), "'", (const char *)NULL))) != 0)
686            return code;
687
688        /* Deal with ~ expansion */
689        if ((code = reconfigure_directive(r->pool, server, "UserDir", "disabled")) != 0)
690            return code;
691
692        if (apr_uid_name_get(&username, uid, r->pool) != APR_SUCCESS) {
693            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, 
694                          "could not get username for uid %d", uid);
695            return HTTP_INTERNAL_SERVER_ERROR;
696        }
697
698        userdir_val = apr_pstrcat(r->pool, "enabled '", escape(r->pool, username), "'", (const char *)NULL);
699
700        if ((code = reconfigure_directive(r->pool, server, "UserDir", userdir_val)) != 0)
701            return code;
702    }
703
704    ap_fixup_virtual_host(r->pool, r->server, server);
705    r->server = server;
706
707    /* Hack to allow post-processing by other modules (mod_rewrite, mod_alias) */
708    return DECLINED;
709}
710
711#ifdef HAVE_UNIX_SUEXEC
712static ap_unix_identity_t *mod_vhost_ldap_get_suexec_id_doer(const request_rec * r)
713{
714  ap_unix_identity_t *ugid = NULL;
715  mod_vhost_ldap_config_t *conf = 
716      (mod_vhost_ldap_config_t *)ap_get_module_config(r->server->module_config,
717                                                      &vhost_ldap_module);
718  mod_vhost_ldap_request_t *req =
719      (mod_vhost_ldap_request_t *)ap_get_module_config(r->request_config,
720                                                       &vhost_ldap_module);
721
722  uid_t uid = -1;
723  gid_t gid = -1;
724
725  // mod_vhost_ldap is disabled or we don't have LDAP Url
726  if ((conf->enabled != MVL_ENABLED)||(!conf->have_ldap_url)) {
727      return NULL;
728  }
729
730  if ((req == NULL)||(req->uid == NULL)||(req->gid == NULL)) {
731      return NULL;
732  }
733
734  if ((ugid = apr_palloc(r->pool, sizeof(ap_unix_identity_t))) == NULL) {
735      return NULL;
736  }
737
738  uid = (uid_t)atoll(req->uid);
739  gid = (gid_t)atoll(req->gid);
740
741  if ((uid < MIN_UID)||(gid < MIN_GID)) {
742      return NULL;
743  }
744
745  ugid->uid = uid;
746  ugid->gid = gid;
747  ugid->userdir = 0;
748 
749  return ugid;
750}
751#endif
752
753static void
754mod_vhost_ldap_register_hooks (apr_pool_t * p)
755{
756
757    /*
758     * Run before mod_rewrite
759     */
760    static const char * const aszRewrite[]={ "mod_rewrite.c", NULL };
761
762    ap_hook_post_config(mod_vhost_ldap_post_config, NULL, NULL, APR_HOOK_MIDDLE);
763    ap_hook_translate_name(mod_vhost_ldap_translate_name, NULL, aszRewrite, APR_HOOK_FIRST);
764#ifdef HAVE_UNIX_SUEXEC
765    ap_hook_get_suexec_identity(mod_vhost_ldap_get_suexec_id_doer, NULL, NULL, APR_HOOK_MIDDLE);
766#endif
767#if (APR_MAJOR_VERSION >= 1)
768    ap_hook_optional_fn_retrieve(ImportULDAPOptFn,NULL,NULL,APR_HOOK_MIDDLE);
769#endif
770}
771
772module AP_MODULE_DECLARE_DATA vhost_ldap_module = {
773  STANDARD20_MODULE_STUFF,
774  NULL,
775  NULL,
776  mod_vhost_ldap_create_server_config,
777  mod_vhost_ldap_merge_server_config,
778  mod_vhost_ldap_cmds,
779  mod_vhost_ldap_register_hooks,
780};
Note: See TracBrowser for help on using the repository browser.