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