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