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