]> andersk Git - mod-vhost-ldap.git/blob - mod_vhost_ldap.c
022dda1ffc3086785ff45e17ccce17a626a2e2e4
[mod-vhost-ldap.git] / mod_vhost_ldap.c
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
54
55 #define MAX_FAILURES 5
56
57 module AP_MODULE_DECLARE_DATA vhost_ldap_module;
58
59 typedef enum {
60     MVL_UNSET, MVL_DISABLED, MVL_ENABLED
61 } mod_vhost_ldap_status_e;
62
63 typedef struct mod_vhost_ldap_config_t {
64     mod_vhost_ldap_status_e enabled;                    /* Is vhost_ldap enabled? */
65
66     /* These parameters are all derived from the VhostLDAPURL directive */
67     char *url;                          /* String representation of LDAP URL */
68
69     char *host;                         /* Name of the LDAP server (or space separated list) */
70     int port;                           /* Port of the LDAP server */
71     char *basedn;                       /* Base DN to do all searches from */
72     int scope;                          /* Scope of the search */
73     char *filter;                       /* Filter to further limit the search  */
74     deref_options deref;                /* how to handle alias dereferening */
75
76     char *binddn;                       /* DN to bind to server (can be NULL) */
77     char *bindpw;                       /* Password to bind to server (can be NULL) */
78
79     int have_deref;                     /* Set if we have found an Deref option */
80     int have_ldap_url;                  /* Set if we have found an LDAP url */
81
82     int secure;                         /* True if SSL connections are requested */
83
84     char *fallback;                     /* Fallback virtual host */
85
86 } mod_vhost_ldap_config_t;
87
88 typedef struct mod_vhost_ldap_request_t {
89     char *dn;                           /* The saved dn from a successful search */
90     char *name;                         /* ServerName */
91     char *admin;                        /* ServerAdmin */
92     char *docroot;                      /* DocumentRoot */
93     char *cgiroot;                      /* ScriptAlias */
94     char *uid;                          /* Suexec Uid */
95     char *gid;                          /* Suexec Gid */
96 } mod_vhost_ldap_request_t;
97
98 char *attributes[] =
99   { "apacheServerName", "apacheDocumentRoot", "apacheScriptAlias", "apacheSuexecUid", "apacheSuexecGid", "apacheServerAdmin", 0 };
100
101 static int total_modules;
102
103 #if (APR_MAJOR_VERSION >= 1)
104 static APR_OPTIONAL_FN_TYPE(uldap_connection_close) *util_ldap_connection_close;
105 static APR_OPTIONAL_FN_TYPE(uldap_connection_find) *util_ldap_connection_find;
106 static APR_OPTIONAL_FN_TYPE(uldap_cache_comparedn) *util_ldap_cache_comparedn;
107 static APR_OPTIONAL_FN_TYPE(uldap_cache_compare) *util_ldap_cache_compare;
108 static APR_OPTIONAL_FN_TYPE(uldap_cache_checkuserid) *util_ldap_cache_checkuserid;
109 static APR_OPTIONAL_FN_TYPE(uldap_cache_getuserdn) *util_ldap_cache_getuserdn;
110 static APR_OPTIONAL_FN_TYPE(uldap_ssl_supported) *util_ldap_ssl_supported;
111
112 static 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
124 static 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
147 static void *
148 mod_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
164 static void *
165 mod_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  */
217 static 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=apacheConfig";
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
332 static 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
343 static 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
353 static 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
363 static 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
391 static 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
401 command_rec mod_vhost_ldap_cmds[] = {
402     AP_INIT_TAKE1("VhostLDAPURL", mod_vhost_ldap_parse_url, NULL, RSRC_CONF,
403                   "URL to define LDAP connection. This should be an RFC 2255 compliant\n"
404                   "URL of the form ldap://host[:port]/basedn[?attrib[?scope[?filter]]].\n"
405                   "<ul>\n"
406                   "<li>Host is the name of the LDAP server. Use a space separated list of hosts \n"
407                   "to specify redundant servers.\n"
408                   "<li>Port is optional, and specifies the port to connect to.\n"
409                   "<li>basedn specifies the base DN to start searches from\n"
410                   "</ul>\n"),
411
412     AP_INIT_TAKE1 ("VhostLDAPBindDN", mod_vhost_ldap_set_binddn, NULL, RSRC_CONF,
413                    "DN to use to bind to LDAP server. If not provided, will do an anonymous bind."),
414     
415     AP_INIT_TAKE1("VhostLDAPBindPassword", mod_vhost_ldap_set_bindpw, NULL, RSRC_CONF,
416                   "Password to use to bind to LDAP server. If not provided, will do an anonymous bind."),
417
418     AP_INIT_FLAG("VhostLDAPEnabled", mod_vhost_ldap_set_enabled, NULL, RSRC_CONF,
419                  "Set to off to disable vhost_ldap, even if it's been enabled in a higher tree"),
420
421     AP_INIT_TAKE1("VhostLDAPDereferenceAliases", mod_vhost_ldap_set_deref, NULL, RSRC_CONF,
422                   "Determines how aliases are handled during a search. Can be one of the"
423                   "values \"never\", \"searching\", \"finding\", or \"always\". "
424                   "Defaults to always."),
425
426     AP_INIT_TAKE1("VhostLDAPFallback", mod_vhost_ldap_set_fallback, NULL, RSRC_CONF,
427                   "Set default virtual host which will be used when requested hostname"
428                   "is not found in LDAP database. This option can be used to display"
429                   "\"virtual host not found\" type of page."),
430
431     {NULL}
432 };
433
434 #define FILTER_LENGTH MAX_STRING_LEN
435 static int mod_vhost_ldap_translate_name(request_rec *r)
436 {
437     mod_vhost_ldap_request_t *reqc;
438     int failures = 0;
439     const char **vals = NULL;
440     char filtbuf[FILTER_LENGTH];
441     mod_vhost_ldap_config_t *conf =
442         (mod_vhost_ldap_config_t *)ap_get_module_config(r->server->module_config, &vhost_ldap_module);
443     core_server_config *core =
444         (core_server_config *)ap_get_module_config(r->server->module_config, &core_module);
445     util_ldap_connection_t *ldc = NULL;
446     int result = 0;
447     const char *dn = NULL;
448     char *cgi;
449     const char *hostname = NULL;
450     int is_fallback = 0;
451     int sleep0 = 0;
452     int sleep1 = 1;
453     int sleep;
454     struct berval hostnamebv, shostnamebv;
455     int ret = DECLINED;
456
457     reqc =
458         (mod_vhost_ldap_request_t *)apr_pcalloc(r->pool, sizeof(mod_vhost_ldap_request_t));
459     memset(reqc, 0, sizeof(mod_vhost_ldap_request_t)); 
460
461     ap_set_module_config(r->request_config, &vhost_ldap_module, reqc);
462
463     // mod_vhost_ldap is disabled or we don't have LDAP Url
464     if ((conf->enabled != MVL_ENABLED)||(!conf->have_ldap_url)) {
465         return DECLINED;
466     }
467
468 start_over:
469
470     if (conf->host) {
471         ldc = util_ldap_connection_find(r, conf->host, conf->port,
472                                         conf->binddn, conf->bindpw, conf->deref,
473                                         conf->secure);
474     }
475     else {
476         ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r, 
477                       "[mod_vhost_ldap.c] translate: no conf->host - weird...?");
478         return HTTP_INTERNAL_SERVER_ERROR;
479     }
480
481     hostname = r->hostname;
482     if (hostname == NULL || hostname[0] == '\0')
483         goto null;
484
485 fallback:
486
487     ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
488                   "[mod_vhost_ldap.c]: translating hostname [%s], uri [%s]",
489                   hostname, r->uri);
490
491     ber_str2bv(hostname, 0, 0, &hostnamebv);
492     if (ldap_bv2escaped_filter_value(&hostnamebv, &shostnamebv) != 0)
493         goto null;
494     apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(|(apacheServerName=%s)(apacheServerAlias=%s)))", conf->filter, shostnamebv.bv_val, shostnamebv.bv_val);
495     ber_memfree(shostnamebv.bv_val);
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 (AP_LDAP_IS_SERVER_DOWN(result) ||
504         (result == LDAP_TIMEOUT) ||
505         (result == LDAP_CONNECT_ERROR)) {
506         sleep = sleep0 + sleep1;
507         ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
508                       "[mod_vhost_ldap.c]: lookup failure, retry number #[%d], sleeping for [%d] seconds",
509                       failures, sleep);
510         if (failures++ < MAX_FAILURES) {
511             /* Back-off exponentially */
512             apr_sleep(apr_time_from_sec(sleep));
513             sleep0 = sleep1;
514             sleep1 = sleep;
515             goto start_over;
516         } else {
517             return HTTP_GATEWAY_TIME_OUT;
518         }
519     }
520
521     if (result == LDAP_NO_SUCH_OBJECT) {
522         if (strcmp(hostname, "*") != 0) {
523             if (strncmp(hostname, "*.", 2) == 0)
524                 hostname += 2;
525             hostname += strcspn(hostname, ".");
526             hostname = apr_pstrcat(r->pool, "*", hostname, NULL);
527             ap_log_rerror(APLOG_MARK, APLOG_NOTICE|APLOG_NOERRNO, 0, r,
528                           "[mod_vhost_ldap.c] translate: "
529                           "virtual host not found, trying wildcard %s",
530                           hostname);
531             goto fallback;
532         }
533
534 null:
535         if (conf->fallback && (is_fallback++ <= 0)) {
536             ap_log_rerror(APLOG_MARK, APLOG_NOTICE|APLOG_NOERRNO, 0, r,
537                           "[mod_vhost_ldap.c] translate: "
538                           "virtual host %s not found, trying fallback %s",
539                           hostname, conf->fallback);
540             hostname = conf->fallback;
541             goto fallback;
542         }
543
544         ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
545                       "[mod_vhost_ldap.c] translate: "
546                       "virtual host %s not found",
547                       hostname);
548
549         return HTTP_BAD_REQUEST;
550     }
551
552     /* handle bind failure */
553     if (result != LDAP_SUCCESS) {
554         ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r, 
555                       "[mod_vhost_ldap.c] translate: "
556                       "translate failed; virtual host %s; URI %s [%s]",
557                       hostname, r->uri, ldap_err2string(result));
558         return HTTP_INTERNAL_SERVER_ERROR;
559     }
560
561     /* mark the user and DN */
562     reqc->dn = apr_pstrdup(r->pool, dn);
563
564     /* Optimize */
565     if (vals) {
566         int i = 0;
567         while (attributes[i]) {
568
569             if (strcasecmp (attributes[i], "apacheServerName") == 0) {
570                 reqc->name = apr_pstrdup (r->pool, vals[i]);
571             }
572             else if (strcasecmp (attributes[i], "apacheServerAdmin") == 0) {
573                 reqc->admin = apr_pstrdup (r->pool, vals[i]);
574             }
575             else if (strcasecmp (attributes[i], "apacheDocumentRoot") == 0) {
576                 reqc->docroot = apr_pstrdup (r->pool, vals[i]);
577             }
578             else if (strcasecmp (attributes[i], "apacheScriptAlias") == 0) {
579                 reqc->cgiroot = apr_pstrdup (r->pool, vals[i]);
580             }
581             else if (strcasecmp (attributes[i], "apacheSuexecUid") == 0) {
582                 reqc->uid = apr_pstrdup(r->pool, vals[i]);
583             }
584             else if (strcasecmp (attributes[i], "apacheSuexecGid") == 0) {
585                 reqc->gid = apr_pstrdup(r->pool, vals[i]);
586             }
587             i++;
588         }
589     }
590
591     ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
592                   "[mod_vhost_ldap.c]: loaded from ldap: "
593                   "apacheServerName: %s, "
594                   "apacheServerAdmin: %s, "
595                   "apacheDocumentRoot: %s, "
596                   "apacheScriptAlias: %s, "
597                   "apacheSuexecUid: %s, "
598                   "apacheSuexecGid: %s",
599                   reqc->name, reqc->admin, reqc->docroot, reqc->cgiroot, reqc->uid, reqc->gid);
600
601     if ((reqc->name == NULL)||(reqc->docroot == NULL)) {
602         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, 
603                       "[mod_vhost_ldap.c] translate: "
604                       "translate failed; ServerName or DocumentRoot not defined");
605         return HTTP_INTERNAL_SERVER_ERROR;
606     }
607
608     cgi = NULL;
609
610     if (reqc->cgiroot) {
611         cgi = strstr(r->uri, "cgi-bin/");
612         if (cgi && (cgi != r->uri + strspn(r->uri, "/"))) {
613             cgi = NULL;
614         }
615     }
616     if (cgi) {
617         /* Set exact filename for CGI script */
618         cgi = apr_pstrcat(r->pool, reqc->cgiroot, cgi + strlen("cgi-bin"), NULL);
619         if ((cgi = ap_server_root_relative(r->pool, cgi))) {
620           ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
621                         "[mod_vhost_ldap.c]: ap_document_root is: %s",
622                         ap_document_root(r));
623           r->filename = cgi;
624           r->handler = "cgi-script";
625           apr_table_setn(r->notes, "alias-forced-type", r->handler);
626           ret = OK;
627         }
628     } else if (r->uri[0] == '/') {
629         /* we don't set r->filename here, and let other modules do it
630          * this allows other modules (mod_rewrite.c) to work as usual
631          */
632         /* r->filename = apr_pstrcat (r->pool, reqc->docroot, r->uri, NULL); */
633     } else {
634         /* We don't handle non-file requests here */
635         return DECLINED;
636     }
637
638     if ((r->server = apr_pmemdup(r->pool, r->server, sizeof(*r->server))) == NULL) {
639         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, 
640                       "[mod_vhost_ldap.c] translate: "
641                       "translate failed; Unable to copy r->server structure");
642         return HTTP_INTERNAL_SERVER_ERROR;
643     }
644
645     r->server->server_hostname = reqc->name;
646
647     if (reqc->admin) {
648         r->server->server_admin = reqc->admin;
649     }
650
651     if ((r->server->module_config = apr_pmemdup(r->pool, r->server->module_config,
652                                                 sizeof(void *) *
653                                                 (total_modules + DYNAMIC_MODULE_LIMIT))) == NULL) {
654         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, 
655                       "[mod_vhost_ldap.c] translate: "
656                       "translate failed; Unable to copy r->server->module_config structure");
657         return HTTP_INTERNAL_SERVER_ERROR;
658     }
659
660     if ((core = apr_pmemdup(r->pool, core, sizeof(*core))) == NULL) {
661         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, 
662                       "[mod_vhost_ldap.c] translate: "
663                       "translate failed; Unable to copy r->core structure");
664         return HTTP_INTERNAL_SERVER_ERROR;
665     }
666     ap_set_module_config(r->server->module_config, &core_module, core);
667
668     /* Stolen from server/core.c */
669
670     /* Make it absolute, relative to ServerRoot */
671     reqc->docroot = ap_server_root_relative(r->pool, reqc->docroot);
672
673     if (reqc->docroot == NULL) {
674         ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, 
675                       "[mod_vhost_ldap.c] set_document_root: DocumentRoot must be a directory");
676
677         return HTTP_INTERNAL_SERVER_ERROR;
678     }
679
680     /* TODO: ap_configtestonly && ap_docrootcheck && */
681     if (apr_filepath_merge((char**)&core->ap_document_root, NULL, reqc->docroot,
682                            APR_FILEPATH_TRUENAME, r->pool) != APR_SUCCESS
683         || !ap_is_directory(r->pool, reqc->docroot)) {
684
685         ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
686                       "[mod_vhost_ldap.c] set_document_root: Warning: DocumentRoot [%s] does not exist",
687                       reqc->docroot);
688         core->ap_document_root = reqc->docroot;
689     }
690
691     /* Hack to allow post-processing by other modules (mod_rewrite, mod_alias) */
692     return ret;
693 }
694
695 #ifdef HAVE_UNIX_SUEXEC
696 static ap_unix_identity_t *mod_vhost_ldap_get_suexec_id_doer(const request_rec * r)
697 {
698   ap_unix_identity_t *ugid = NULL;
699   mod_vhost_ldap_config_t *conf = 
700       (mod_vhost_ldap_config_t *)ap_get_module_config(r->server->module_config,
701                                                       &vhost_ldap_module);
702   mod_vhost_ldap_request_t *req =
703       (mod_vhost_ldap_request_t *)ap_get_module_config(r->request_config,
704                                                        &vhost_ldap_module);
705
706   uid_t uid = -1;
707   gid_t gid = -1;
708
709   // mod_vhost_ldap is disabled or we don't have LDAP Url
710   if ((conf->enabled != MVL_ENABLED)||(!conf->have_ldap_url)) {
711       return NULL;
712   }
713
714   if ((req == NULL)||(req->uid == NULL)||(req->gid == NULL)) {
715       return NULL;
716   }
717
718   if ((ugid = apr_palloc(r->pool, sizeof(ap_unix_identity_t))) == NULL) {
719       return NULL;
720   }
721
722   uid = (uid_t)atoll(req->uid);
723   gid = (gid_t)atoll(req->gid);
724
725   if ((uid < MIN_UID)||(gid < MIN_GID)) {
726       return NULL;
727   }
728
729   ugid->uid = uid;
730   ugid->gid = gid;
731   ugid->userdir = 0;
732   
733   return ugid;
734 }
735 #endif
736
737 static void
738 mod_vhost_ldap_register_hooks (apr_pool_t * p)
739 {
740
741     /*
742      * Run before mod_rewrite
743      */
744     static const char * const aszRewrite[]={ "mod_rewrite.c", NULL };
745
746     ap_hook_post_config(mod_vhost_ldap_post_config, NULL, NULL, APR_HOOK_MIDDLE);
747     ap_hook_translate_name(mod_vhost_ldap_translate_name, NULL, aszRewrite, APR_HOOK_FIRST);
748 #ifdef HAVE_UNIX_SUEXEC
749     ap_hook_get_suexec_identity(mod_vhost_ldap_get_suexec_id_doer, NULL, NULL, APR_HOOK_MIDDLE);
750 #endif
751 #if (APR_MAJOR_VERSION >= 1)
752     ap_hook_optional_fn_retrieve(ImportULDAPOptFn,NULL,NULL,APR_HOOK_MIDDLE);
753 #endif
754 }
755
756 module AP_MODULE_DECLARE_DATA vhost_ldap_module = {
757   STANDARD20_MODULE_STUFF,
758   NULL,
759   NULL,
760   mod_vhost_ldap_create_server_config,
761   mod_vhost_ldap_merge_server_config,
762   mod_vhost_ldap_cmds,
763   mod_vhost_ldap_register_hooks,
764 };
This page took 0.292797 seconds and 3 git commands to generate.