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