1 /* ============================================================
2 * Copyright (c) 2003-2004, Ondrej Sury
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * mod_vhost_ldap.c --- read virtual host config from LDAP directory
28 #include "http_config.h"
29 #include "http_core.h"
31 #include "http_request.h"
32 #include "apr_version.h"
34 #include "apr_strings.h"
35 #include "apr_reslist.h"
36 #include "util_ldap.h"
38 #if !defined(APU_HAS_LDAP) && !defined(APR_HAS_LDAP)
39 #error mod_vhost_ldap requires APR-util to have LDAP support built in
42 #if !defined(WIN32) && !defined(OS2) && !defined(BEOS) && !defined(NETWARE)
43 #define HAVE_UNIX_SUEXEC
46 #ifdef HAVE_UNIX_SUEXEC
47 #include "unixd.h" /* Contains the suexec_identity hook used on Unix */
53 module AP_MODULE_DECLARE_DATA vhost_ldap_module;
56 MVL_UNSET, MVL_DISABLED, MVL_ENABLED
57 } mod_vhost_ldap_status_e;
59 typedef struct mod_vhost_ldap_config_t {
60 mod_vhost_ldap_status_e enabled; /* Is vhost_ldap enabled? */
62 /* These parameters are all derived from the VhostLDAPURL directive */
63 char *url; /* String representation of LDAP URL */
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 */
72 char *binddn; /* DN to bind to server (can be NULL) */
73 char *bindpw; /* Password to bind to server (can be NULL) */
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 */
78 int secure; /* True if SSL connections are requested */
80 char *fallback; /* Fallback virtual host */
82 } mod_vhost_ldap_config_t;
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 } mod_vhost_ldap_request_t;
95 { "apacheServerName", "apacheDocumentRoot", "apacheScriptAlias", "apacheSuexecUid", "apacheSuexecGid", "apacheServerAdmin", 0 };
97 #if (APR_MAJOR_VERSION >= 1)
98 static APR_OPTIONAL_FN_TYPE(uldap_connection_close) *util_ldap_connection_close;
99 static APR_OPTIONAL_FN_TYPE(uldap_connection_find) *util_ldap_connection_find;
100 static APR_OPTIONAL_FN_TYPE(uldap_cache_comparedn) *util_ldap_cache_comparedn;
101 static APR_OPTIONAL_FN_TYPE(uldap_cache_compare) *util_ldap_cache_compare;
102 static APR_OPTIONAL_FN_TYPE(uldap_cache_checkuserid) *util_ldap_cache_checkuserid;
103 static APR_OPTIONAL_FN_TYPE(uldap_cache_getuserdn) *util_ldap_cache_getuserdn;
104 static APR_OPTIONAL_FN_TYPE(uldap_ssl_supported) *util_ldap_ssl_supported;
106 static void ImportULDAPOptFn(void)
108 util_ldap_connection_close = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_close);
109 util_ldap_connection_find = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_find);
110 util_ldap_cache_comparedn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_comparedn);
111 util_ldap_cache_compare = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_compare);
112 util_ldap_cache_checkuserid = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_checkuserid);
113 util_ldap_cache_getuserdn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_getuserdn);
114 util_ldap_ssl_supported = APR_RETRIEVE_OPTIONAL_FN(uldap_ssl_supported);
118 static int mod_vhost_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
120 /* make sure that mod_ldap (util_ldap) is loaded */
121 if (ap_find_linked_module("util_ldap.c") == NULL) {
122 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, s,
123 "Module mod_ldap missing. Mod_ldap (aka. util_ldap) "
124 "must be loaded in order for mod_vhost_ldap to function properly");
125 return HTTP_INTERNAL_SERVER_ERROR;
129 ap_add_version_component(p, MOD_VHOST_LDAP_VERSION);
135 mod_vhost_ldap_create_server_config (apr_pool_t *p, server_rec *s)
137 mod_vhost_ldap_config_t *conf =
138 (mod_vhost_ldap_config_t *)apr_pcalloc(p, sizeof (mod_vhost_ldap_config_t));
140 conf->enabled = MVL_UNSET;
141 conf->have_ldap_url = 0;
142 conf->have_deref = 0;
145 conf->deref = always;
146 conf->fallback = NULL;
152 mod_vhost_ldap_merge_server_config(apr_pool_t *p, void *parentv, void *childv)
154 mod_vhost_ldap_config_t *parent = (mod_vhost_ldap_config_t *) parentv;
155 mod_vhost_ldap_config_t *child = (mod_vhost_ldap_config_t *) childv;
156 mod_vhost_ldap_config_t *conf =
157 (mod_vhost_ldap_config_t *)apr_pcalloc(p, sizeof(mod_vhost_ldap_config_t));
159 if (child->enabled == MVL_UNSET) {
160 conf->enabled = parent->enabled;
162 conf->enabled = child->enabled;
165 if (child->have_ldap_url) {
166 conf->have_ldap_url = child->have_ldap_url;
167 conf->url = child->url;
168 conf->host = child->host;
169 conf->port = child->port;
170 conf->basedn = child->basedn;
171 conf->scope = child->scope;
172 conf->filter = child->filter;
173 conf->secure = child->secure;
175 conf->have_ldap_url = parent->have_ldap_url;
176 conf->url = parent->url;
177 conf->host = parent->host;
178 conf->port = parent->port;
179 conf->basedn = parent->basedn;
180 conf->scope = parent->scope;
181 conf->filter = parent->filter;
182 conf->secure = parent->secure;
184 if (child->have_deref) {
185 conf->have_deref = child->have_deref;
186 conf->deref = child->deref;
188 conf->have_deref = parent->have_deref;
189 conf->deref = parent->deref;
192 conf->binddn = (child->binddn ? child->binddn : parent->binddn);
193 conf->bindpw = (child->bindpw ? child->bindpw : parent->bindpw);
195 conf->fallback = (child->fallback ? child->fallback : parent->fallback);
201 * Use the ldap url parsing routines to break up the ldap url into
204 static const char *mod_vhost_ldap_parse_url(cmd_parms *cmd,
209 apr_ldap_url_desc_t *urld;
210 #if (APR_MAJOR_VERSION >= 1)
211 apr_ldap_err_t *result_err;
214 mod_vhost_ldap_config_t *conf =
215 (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
218 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
219 cmd->server, "[mod_vhost_ldap.c] url parse: `%s'",
222 #if (APR_MAJOR_VERSION >= 1) /* for apache >= 2.2 */
223 result = apr_ldap_url_parse(cmd->pool, url, &(urld), &(result_err));
224 if (result != LDAP_SUCCESS) {
225 return result_err->reason;
228 result = apr_ldap_url_parse(url, &(urld));
229 if (result != LDAP_SUCCESS) {
231 case LDAP_URL_ERR_NOTLDAP:
232 return "LDAP URL does not begin with ldap://";
233 case LDAP_URL_ERR_NODN:
234 return "LDAP URL does not have a DN";
235 case LDAP_URL_ERR_BADSCOPE:
236 return "LDAP URL has an invalid scope";
237 case LDAP_URL_ERR_MEM:
238 return "Out of memory parsing LDAP URL";
240 return "Could not parse LDAP URL";
244 conf->url = apr_pstrdup(cmd->pool, url);
246 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
247 cmd->server, "[mod_vhost_ldap.c] url parse: Host: %s", urld->lud_host);
248 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
249 cmd->server, "[mod_vhost_ldap.c] url parse: Port: %d", urld->lud_port);
250 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
251 cmd->server, "[mod_vhost_ldap.c] url parse: DN: %s", urld->lud_dn);
252 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
253 cmd->server, "[mod_vhost_ldap.c] url parse: attrib: %s", urld->lud_attrs? urld->lud_attrs[0] : "(null)");
254 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
255 cmd->server, "[mod_vhost_ldap.c] url parse: scope: %s",
256 (urld->lud_scope == LDAP_SCOPE_SUBTREE? "subtree" :
257 urld->lud_scope == LDAP_SCOPE_BASE? "base" :
258 urld->lud_scope == LDAP_SCOPE_ONELEVEL? "onelevel" : "unknown"));
259 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
260 cmd->server, "[mod_vhost_ldap.c] url parse: filter: %s", urld->lud_filter);
262 /* Set all the values, or at least some sane defaults */
264 char *p = apr_palloc(cmd->pool, strlen(conf->host) + strlen(urld->lud_host) + 2);
265 strcpy(p, urld->lud_host);
267 strcat(p, conf->host);
271 conf->host = urld->lud_host? apr_pstrdup(cmd->pool, urld->lud_host) : "localhost";
273 conf->basedn = urld->lud_dn? apr_pstrdup(cmd->pool, urld->lud_dn) : "";
275 conf->scope = urld->lud_scope == LDAP_SCOPE_ONELEVEL ?
276 LDAP_SCOPE_ONELEVEL : LDAP_SCOPE_SUBTREE;
278 if (urld->lud_filter) {
279 if (urld->lud_filter[0] == '(') {
281 * Get rid of the surrounding parens; later on when generating the
282 * filter, they'll be put back.
284 conf->filter = apr_pstrdup(cmd->pool, urld->lud_filter+1);
285 conf->filter[strlen(conf->filter)-1] = '\0';
288 conf->filter = apr_pstrdup(cmd->pool, urld->lud_filter);
292 conf->filter = "objectClass=apacheConfig";
295 /* "ldaps" indicates secure ldap connections desired
297 if (strncasecmp(url, "ldaps", 5) == 0)
300 conf->port = urld->lud_port? urld->lud_port : LDAPS_PORT;
301 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
302 "LDAP: vhost_ldap using SSL connections");
307 conf->port = urld->lud_port? urld->lud_port : LDAP_PORT;
308 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
309 "LDAP: vhost_ldap not using SSL connections");
312 conf->have_ldap_url = 1;
313 #if (APR_MAJOR_VERSION < 1) /* free only required for older apr */
314 apr_ldap_free_urldesc(urld);
319 static const char *mod_vhost_ldap_set_enabled(cmd_parms *cmd, void *dummy, int enabled)
321 mod_vhost_ldap_config_t *conf =
322 (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
325 conf->enabled = (enabled) ? MVL_ENABLED : MVL_DISABLED;
330 static const char *mod_vhost_ldap_set_binddn(cmd_parms *cmd, void *dummy, const char *binddn)
332 mod_vhost_ldap_config_t *conf =
333 (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
336 conf->binddn = apr_pstrdup(cmd->pool, binddn);
340 static const char *mod_vhost_ldap_set_bindpw(cmd_parms *cmd, void *dummy, const char *bindpw)
342 mod_vhost_ldap_config_t *conf =
343 (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
346 conf->bindpw = apr_pstrdup(cmd->pool, bindpw);
350 static const char *mod_vhost_ldap_set_deref(cmd_parms *cmd, void *dummy, const char *deref)
352 mod_vhost_ldap_config_t *conf =
353 (mod_vhost_ldap_config_t *)ap_get_module_config (cmd->server->module_config,
356 if (strcmp(deref, "never") == 0 || strcasecmp(deref, "off") == 0) {
358 conf->have_deref = 1;
360 else if (strcmp(deref, "searching") == 0) {
361 conf->deref = searching;
362 conf->have_deref = 1;
364 else if (strcmp(deref, "finding") == 0) {
365 conf->deref = finding;
366 conf->have_deref = 1;
368 else if (strcmp(deref, "always") == 0 || strcasecmp(deref, "on") == 0) {
369 conf->deref = always;
370 conf->have_deref = 1;
373 return "Unrecognized value for VhostLDAPAliasDereference directive";
378 static const char *mod_vhost_ldap_set_fallback(cmd_parms *cmd, void *dummy, const char *fallback)
380 mod_vhost_ldap_config_t *conf =
381 (mod_vhost_ldap_config_t *)ap_get_module_config(cmd->server->module_config,
384 conf->fallback = apr_pstrdup(cmd->pool, fallback);
388 command_rec mod_vhost_ldap_cmds[] = {
389 AP_INIT_TAKE1("VhostLDAPURL", mod_vhost_ldap_parse_url, NULL, RSRC_CONF,
390 "URL to define LDAP connection. This should be an RFC 2255 compliant\n"
391 "URL of the form ldap://host[:port]/basedn[?attrib[?scope[?filter]]].\n"
393 "<li>Host is the name of the LDAP server. Use a space separated list of hosts \n"
394 "to specify redundant servers.\n"
395 "<li>Port is optional, and specifies the port to connect to.\n"
396 "<li>basedn specifies the base DN to start searches from\n"
399 AP_INIT_TAKE1 ("VhostLDAPBindDN", mod_vhost_ldap_set_binddn, NULL, RSRC_CONF,
400 "DN to use to bind to LDAP server. If not provided, will do an anonymous bind."),
402 AP_INIT_TAKE1("VhostLDAPBindPassword", mod_vhost_ldap_set_bindpw, NULL, RSRC_CONF,
403 "Password to use to bind to LDAP server. If not provided, will do an anonymous bind."),
405 AP_INIT_FLAG("VhostLDAPEnabled", mod_vhost_ldap_set_enabled, NULL, RSRC_CONF,
406 "Set to off to disable vhost_ldap, even if it's been enabled in a higher tree"),
408 AP_INIT_TAKE1("VhostLDAPDereferenceAliases", mod_vhost_ldap_set_deref, NULL, RSRC_CONF,
409 "Determines how aliases are handled during a search. Can be one of the"
410 "values \"never\", \"searching\", \"finding\", or \"always\". "
411 "Defaults to always."),
413 AP_INIT_TAKE1("VhostLDAPFallback", mod_vhost_ldap_set_fallback, NULL, RSRC_CONF,
414 "Set default virtual host which will be used when requested hostname"
415 "is not found in LDAP database. This option can be used to display"
416 "\"virtual host not found\" type of page."),
421 #define FILTER_LENGTH MAX_STRING_LEN
422 static int mod_vhost_ldap_translate_name(request_rec *r)
424 request_rec *top = (r->main)?r->main:r;
425 mod_vhost_ldap_request_t *reqc;
428 const char **vals = NULL;
429 char filtbuf[FILTER_LENGTH];
430 mod_vhost_ldap_config_t *conf =
431 (mod_vhost_ldap_config_t *)ap_get_module_config(r->server->module_config, &vhost_ldap_module);
432 core_server_config * core =
433 (core_server_config *) ap_get_module_config(r->server->module_config, &core_module);
434 util_ldap_connection_t *ldc = NULL;
436 const char *dn = NULL;
438 const char *hostname = NULL;
442 (mod_vhost_ldap_request_t *)apr_pcalloc(r->pool, sizeof(mod_vhost_ldap_request_t));
443 memset(reqc, 0, sizeof(mod_vhost_ldap_request_t));
445 ap_set_module_config(r->request_config, &vhost_ldap_module, reqc);
447 // mod_vhost_ldap is disabled or we don't have LDAP Url
448 if ((conf->enabled != MVL_ENABLED)||(!conf->have_ldap_url)) {
455 ldc = util_ldap_connection_find(r, conf->host, conf->port,
456 conf->binddn, conf->bindpw, conf->deref,
460 ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
461 "[mod_vhost_ldap.c] translate: no conf->host - weird...?");
465 hostname = r->hostname;
469 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
470 "[mod_vhost_ldap.c]: translating %s", r->uri);
472 apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(|(apacheServerName=%s)(apacheServerAlias=%s)))", conf->filter, hostname, hostname);
474 result = util_ldap_cache_getuserdn(r, ldc, conf->url, conf->basedn, conf->scope,
475 attributes, filtbuf, &dn, &vals);
477 util_ldap_connection_close(ldc);
479 /* sanity check - if server is down, retry it up to 5 times */
480 if (result == LDAP_SERVER_DOWN) {
481 if (failures++ <= 5) {
486 if ((result == LDAP_NO_SUCH_OBJECT)) {
487 if (conf->fallback && (is_fallback++ <= 0)) {
488 ap_log_rerror(APLOG_MARK, APLOG_NOTICE|APLOG_NOERRNO, 0, r,
489 "[mod_vhost_ldap.c] translate: "
490 "virtual host %s not found, trying fallback %s",
491 hostname, conf->fallback);
492 hostname = conf->fallback;
496 ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
497 "[mod_vhost_ldap.c] translate: "
498 "virtual host %s not found",
504 /* handle bind failure */
505 if (result != LDAP_SUCCESS) {
506 ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
507 "[mod_vhost_ldap.c] translate: "
508 "translate failed; virtual host %s; URI %s [%s]",
509 hostname, r->uri, ldap_err2string(result));
513 /* mark the user and DN */
514 reqc->dn = apr_pstrdup(r->pool, dn);
519 while (attributes[i]) {
521 if (strcasecmp (attributes[i], "apacheServerName") == 0) {
522 reqc->name = apr_pstrdup (r->pool, vals[i]);
524 else if (strcasecmp (attributes[i], "apacheServerAdmin") == 0) {
525 reqc->admin = apr_pstrdup (r->pool, vals[i]);
527 else if (strcasecmp (attributes[i], "apacheDocumentRoot") == 0) {
528 reqc->docroot = apr_pstrdup (r->pool, vals[i]);
530 else if (strcasecmp (attributes[i], "apacheScriptAlias") == 0) {
531 reqc->cgiroot = apr_pstrdup (r->pool, vals[i]);
533 else if (strcasecmp (attributes[i], "apacheSuexecUid") == 0) {
534 reqc->uid = apr_pstrdup(r->pool, vals[i]);
536 else if (strcasecmp (attributes[i], "apacheSuexecGid") == 0) {
537 reqc->gid = apr_pstrdup(r->pool, vals[i]);
543 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
544 "[mod_vhost_ldap.c]: loaded from ldap: "
545 "apacheServerName: %s, "
546 "apacheServerAdmin: %s, "
547 "apacheDocumentRoot: %s, "
548 "apacheScriptAlias: %s, "
549 "apacheSuexecUid: %s, "
550 "apacheSuexecGid: %s",
551 reqc->name, reqc->admin, reqc->docroot, reqc->cgiroot, reqc->uid, reqc->gid);
553 if ((reqc->name == NULL)||(reqc->docroot == NULL)) {
554 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r,
555 "[mod_vhost_ldap.c] translate: "
556 "translate failed; ServerName or DocumentRoot not defined");
563 cgi = strstr(r->uri, "cgi-bin/");
564 if (cgi && (cgi != r->uri + strspn(r->uri, "/"))) {
569 r->filename = apr_pstrcat (r->pool, reqc->cgiroot, cgi + strlen("cgi-bin"), NULL);
570 r->handler = "cgi-script";
571 apr_table_setn(r->notes, "alias-forced-type", r->handler);
572 } else if (r->uri[0] == '/') {
573 r->filename = apr_pstrcat (r->pool, reqc->docroot, r->uri, NULL);
578 top->server->server_hostname = apr_pstrdup (top->pool, reqc->name);
581 top->server->server_admin = apr_pstrdup (top->pool, reqc->admin);
584 // set environment variables
585 e = top->subprocess_env;
586 apr_table_addn (e, "SERVER_ROOT", reqc->docroot);
588 core->ap_document_root = apr_pstrdup(top->pool, reqc->docroot);
590 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
591 "[mod_vhost_ldap.c]: translated to %s", r->filename);
596 #ifdef HAVE_UNIX_SUEXEC
597 static ap_unix_identity_t *mod_vhost_ldap_get_suexec_id_doer(const request_rec * r)
599 ap_unix_identity_t *ugid = NULL;
600 mod_vhost_ldap_config_t *conf =
601 (mod_vhost_ldap_config_t *)ap_get_module_config(r->server->module_config,
603 mod_vhost_ldap_request_t *req =
604 (mod_vhost_ldap_request_t *)ap_get_module_config(r->request_config,
610 // mod_vhost_ldap is disabled or we don't have LDAP Url
611 if ((conf->enabled != MVL_ENABLED)||(!conf->have_ldap_url)) {
615 if ((req == NULL)||(req->uid == NULL)||(req->gid == NULL)) {
619 if ((ugid = apr_palloc(r->pool, sizeof(ap_unix_identity_t))) == NULL) {
623 uid = (uid_t)atoll(req->uid);
624 gid = (gid_t)atoll(req->gid);
626 if ((uid < MIN_UID)||(gid < MIN_GID)) {
639 mod_vhost_ldap_register_hooks (apr_pool_t * p)
641 ap_hook_post_config(mod_vhost_ldap_post_config, NULL, NULL, APR_HOOK_MIDDLE);
642 ap_hook_translate_name(mod_vhost_ldap_translate_name, NULL, NULL, APR_HOOK_MIDDLE);
643 #ifdef HAVE_UNIX_SUEXEC
644 ap_hook_get_suexec_identity(mod_vhost_ldap_get_suexec_id_doer, NULL, NULL, APR_HOOK_MIDDLE);
646 #if (APR_MAJOR_VERSION >= 1)
647 ap_hook_optional_fn_retrieve(ImportULDAPOptFn,NULL,NULL,APR_HOOK_MIDDLE);
651 module AP_MODULE_DECLARE_DATA vhost_ldap_module = {
652 STANDARD20_MODULE_STUFF,
655 mod_vhost_ldap_create_server_config,
656 mod_vhost_ldap_merge_server_config,
658 mod_vhost_ldap_register_hooks,