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