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