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