1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * util_ldap.c: LDAP things
20 * Original code from auth_ldap module for Apache v1.3:
21 * Copyright 1998, 1999 Enbridge Pipelines Inc.
22 * Copyright 1999-2001 Dave Carrigan
26 #include <apr_strings.h>
28 #include "ap_config.h"
30 #include "http_config.h"
31 #include "http_core.h"
33 #include "http_protocol.h"
34 #include "http_request.h"
35 #include "util_ldap.h"
36 #include "util_ldap_cache.h"
43 #error mod_ldap requires APR-util to have LDAP support built in
46 #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
48 #define UTIL_LDAP_SET_MUTEX_PERMS
51 /* defines for certificate file types
53 #define LDAP_CA_TYPE_UNKNOWN 0
54 #define LDAP_CA_TYPE_DER 1
55 #define LDAP_CA_TYPE_BASE64 2
56 #define LDAP_CA_TYPE_CERT7_DB 3
59 module AP_MODULE_DECLARE_DATA ldap_module;
61 int util_ldap_handler(request_rec *r);
62 void *util_ldap_create_config(apr_pool_t *p, server_rec *s);
66 * Some definitions to help between various versions of apache.
69 #ifndef DOCTYPE_HTML_2_0
70 #define DOCTYPE_HTML_2_0 "<!DOCTYPE HTML PUBLIC \"-//IETF//" \
71 "DTD HTML 2.0//EN\">\n"
74 #ifndef DOCTYPE_HTML_3_2
75 #define DOCTYPE_HTML_3_2 "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
76 "DTD HTML 3.2 Final//EN\">\n"
79 #ifndef DOCTYPE_HTML_4_0S
80 #define DOCTYPE_HTML_4_0S "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
81 "DTD HTML 4.0//EN\"\n" \
82 "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
85 #ifndef DOCTYPE_HTML_4_0T
86 #define DOCTYPE_HTML_4_0T "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
87 "DTD HTML 4.0 Transitional//EN\"\n" \
88 "\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n"
91 #ifndef DOCTYPE_HTML_4_0F
92 #define DOCTYPE_HTML_4_0F "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
93 "DTD HTML 4.0 Frameset//EN\"\n" \
94 "\"http://www.w3.org/TR/REC-html40/frameset.dtd\">\n"
97 #define LDAP_CACHE_LOCK() \
98 if (st->util_ldap_cache_lock) \
99 apr_global_mutex_lock(st->util_ldap_cache_lock)
100 #define LDAP_CACHE_UNLOCK() \
101 if (st->util_ldap_cache_lock) \
102 apr_global_mutex_unlock(st->util_ldap_cache_lock)
105 static void util_ldap_strdup (char **str, const char *newstr)
113 *str = calloc(1, strlen(newstr)+1);
114 strcpy (*str, newstr);
122 * This handler generates a status page about the current performance of
123 * the LDAP cache. It is enabled as follows:
125 * <Location /ldap-status>
126 * SetHandler ldap-status
130 int util_ldap_handler(request_rec *r)
132 util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(r->server->module_config, &ldap_module);
134 r->allowed |= (1 << M_GET);
135 if (r->method_number != M_GET)
138 if (strcmp(r->handler, "ldap-status")) {
142 r->content_type = "text/html; charset=ISO-8859-1";
146 ap_rputs(DOCTYPE_HTML_3_2
147 "<html><head><title>LDAP Cache Information</title></head>\n", r);
148 ap_rputs("<body bgcolor='#ffffff'><h1 align=center>LDAP Cache Information</h1>\n", r);
150 util_ald_cache_display(r, st);
155 /* ------------------------------------------------------------------ */
159 * Closes an LDAP connection by unlocking it. The next time
160 * util_ldap_connection_find() is called this connection will be
161 * available for reuse.
163 LDAP_DECLARE(void) util_ldap_connection_close(util_ldap_connection_t *ldc)
169 * Is it safe leaving bound connections floating around between the
170 * different modules? Keeping the user bound is a performance boost,
171 * but it is also a potential security problem - maybe.
173 * For now we unbind the user when we finish with a connection, but
174 * we don't have to...
177 /* mark our connection as available for reuse */
180 apr_thread_mutex_unlock(ldc->lock);
186 * Destroys an LDAP connection by unbinding and closing the connection to
187 * the LDAP server. It is used to bring the connection back to a known
188 * state after an error, and during pool cleanup.
190 LDAP_DECLARE_NONSTD(apr_status_t) util_ldap_connection_unbind(void *param)
192 util_ldap_connection_t *ldc = param;
196 ldap_unbind_s(ldc->ldap);
207 * Clean up an LDAP connection by unbinding and unlocking the connection.
208 * This function is registered with the pool cleanup function - causing
209 * the LDAP connections to be shut down cleanly on graceful restart.
211 LDAP_DECLARE_NONSTD(apr_status_t) util_ldap_connection_cleanup(void *param)
213 util_ldap_connection_t *ldc = param;
217 /* unbind and disconnect from the LDAP server */
218 util_ldap_connection_unbind(ldc);
220 /* free the username and password */
222 free((void*)ldc->bindpw);
225 free((void*)ldc->binddn);
228 /* unlock this entry */
229 util_ldap_connection_close(ldc);
238 * Connect to the LDAP server and binds. Does not connect if already
239 * connected (i.e. ldc->ldap is non-NULL.) Does not bind if already bound.
241 * Returns LDAP_SUCCESS on success; and an error code on failure
243 LDAP_DECLARE(int) util_ldap_connection_open(request_rec *r,
244 util_ldap_connection_t *ldc)
248 int version = LDAP_VERSION3;
249 int rc = LDAP_SUCCESS;
250 struct timeval timeOut = {10,0}; /* 10 second connection timeout */
252 util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(
253 r->server->module_config, &ldap_module);
255 /* If the connection is already bound, return
259 ldc->reason = "LDAP: connection open successful (already bound)";
263 /* create the ldap session handle
265 if (NULL == ldc->ldap)
267 /* clear connection requested */
270 ldc->ldap = ldap_init(const_cast(ldc->host), ldc->port);
272 else /* ssl connnection requested */
274 /* check configuration to make sure it supports SSL
280 #if APR_HAS_NOVELL_LDAPSDK
281 ldc->ldap = ldapssl_init(ldc->host, ldc->port, 1);
283 #elif APR_HAS_NETSCAPE_LDAPSDK
284 ldc->ldap = ldapssl_init(ldc->host, ldc->port, 1);
286 #elif APR_HAS_OPENLDAP_LDAPSDK
287 ldc->ldap = ldap_init(ldc->host, ldc->port);
288 if (NULL != ldc->ldap)
290 int SSLmode = LDAP_OPT_X_TLS_HARD;
291 result = ldap_set_option(ldc->ldap, LDAP_OPT_X_TLS, &SSLmode);
292 if (LDAP_SUCCESS != result)
294 ldap_unbind_s(ldc->ldap);
295 ldc->reason = "LDAP: ldap_set_option - LDAP_OPT_X_TLS_HARD failed";
300 #elif APR_HAS_MICROSOFT_LDAPSDK
301 ldc->ldap = ldap_sslinit(const_cast(ldc->host), ldc->port, 1);
304 ldc->reason = "LDAP: ssl connections not supported";
305 #endif /* APR_HAS_NOVELL_LDAPSDK */
307 #endif /* APR_HAS_LDAP_SSL */
310 ldc->reason = "LDAP: ssl connections not supported";
313 if (NULL == ldc->ldap)
316 if (NULL == ldc->reason)
317 ldc->reason = "LDAP: ldap initialization failed";
321 /* Set the alias dereferencing option */
322 ldap_set_option(ldc->ldap, LDAP_OPT_DEREF, &(ldc->deref));
324 /* always default to LDAP V3 */
325 ldap_set_option(ldc->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
327 #ifdef LDAP_OPT_NETWORK_TIMEOUT
328 if (st->connectionTimeout > 0) {
329 timeOut.tv_sec = st->connectionTimeout;
332 if (st->connectionTimeout >= 0) {
333 rc = ldap_set_option(ldc->ldap, LDAP_OPT_NETWORK_TIMEOUT, (void *)&timeOut);
334 if (APR_SUCCESS != rc) {
335 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
336 "LDAP: Could not set the connection timeout" );
343 /* loop trying to bind up to 10 times if LDAP_SERVER_DOWN error is
344 * returned. Break out of the loop on Success or any other error.
346 * NOTE: Looping is probably not a great idea. If the server isn't
347 * responding the chances it will respond after a few tries are poor.
348 * However, the original code looped and it only happens on
349 * the error condition.
351 for (failures=0; failures<10; failures++)
353 result = ldap_simple_bind_s(ldc->ldap, const_cast(ldc->binddn), const_cast(ldc->bindpw));
354 if (LDAP_SERVER_DOWN != result)
358 /* free the handle if there was an error
360 if (LDAP_SUCCESS != result)
362 ldap_unbind_s(ldc->ldap);
365 ldc->reason = "LDAP: ldap_simple_bind_s() failed";
369 ldc->reason = "LDAP: connection open successful";
377 * Find an existing ldap connection struct that matches the
378 * provided ldap connection parameters.
380 * If not found in the cache, a new ldc structure will be allocated from st->pool
381 * and returned to the caller. If found in the cache, a pointer to the existing
382 * ldc structure will be returned.
384 LDAP_DECLARE(util_ldap_connection_t *)util_ldap_connection_find(request_rec *r, const char *host, int port,
385 const char *binddn, const char *bindpw, deref_options deref,
388 struct util_ldap_connection_t *l, *p; /* To traverse the linked list */
390 util_ldap_state_t *st =
391 (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
396 /* mutex lock this function */
397 apr_thread_mutex_lock(st->mutex);
400 /* Search for an exact connection match in the list that is not
403 for (l=st->connections,p=NULL; l; l=l->next) {
405 if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {
407 if ((l->port == port) && (strcmp(l->host, host) == 0) &&
408 ((!l->binddn && !binddn) || (l->binddn && binddn && !strcmp(l->binddn, binddn))) &&
409 ((!l->bindpw && !bindpw) || (l->bindpw && bindpw && !strcmp(l->bindpw, bindpw))) &&
410 (l->deref == deref) && (l->secure == secure)) {
415 /* If this connection didn't match the criteria, then we
416 * need to unlock the mutex so it is available to be reused.
418 apr_thread_mutex_unlock(l->lock);
424 /* If nothing found, search again, but we don't care about the
425 * binddn and bindpw this time.
428 for (l=st->connections,p=NULL; l; l=l->next) {
430 if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {
433 if ((l->port == port) && (strcmp(l->host, host) == 0) &&
434 (l->deref == deref) && (l->secure == secure)) {
436 /* the bind credentials have changed */
438 util_ldap_strdup((char**)&(l->binddn), binddn);
439 util_ldap_strdup((char**)&(l->bindpw), bindpw);
443 /* If this connection didn't match the criteria, then we
444 * need to unlock the mutex so it is available to be reused.
446 apr_thread_mutex_unlock(l->lock);
453 /* artificially disable cache */
456 /* If no connection what found after the second search, we
462 * Add the new connection entry to the linked list. Note that we
463 * don't actually establish an LDAP connection yet; that happens
464 * the first time authentication is requested.
466 /* create the details to the pool in st */
467 l = apr_pcalloc(st->pool, sizeof(util_ldap_connection_t));
469 apr_thread_mutex_create(&l->lock, APR_THREAD_MUTEX_DEFAULT, st->pool);
470 apr_thread_mutex_lock(l->lock);
474 l->host = apr_pstrdup(st->pool, host);
477 util_ldap_strdup((char**)&(l->binddn), binddn);
478 util_ldap_strdup((char**)&(l->bindpw), bindpw);
481 /* add the cleanup to the pool */
482 apr_pool_cleanup_register(l->pool, l,
483 util_ldap_connection_cleanup,
484 apr_pool_cleanup_null);
495 apr_thread_mutex_unlock(st->mutex);
500 /* ------------------------------------------------------------------ */
503 * Compares two DNs to see if they're equal. The only way to do this correctly is to
504 * search for the dn and then do ldap_get_dn() on the result. This should match the
505 * initial dn, since it would have been also retrieved with ldap_get_dn(). This is
506 * expensive, so if the configuration value compare_dn_on_server is
507 * false, just does an ordinary strcmp.
509 * The lock for the ldap cache should already be acquired.
511 LDAP_DECLARE(int) util_ldap_cache_comparedn(request_rec *r, util_ldap_connection_t *ldc,
512 const char *url, const char *dn, const char *reqdn,
513 int compare_dn_on_server)
516 util_url_node_t *curl;
517 util_url_node_t curnode;
518 util_dn_compare_node_t *node;
519 util_dn_compare_node_t newnode;
521 LDAPMessage *res, *entry;
524 util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(r->server->module_config, &ldap_module);
526 /* get cache entry (or create one) */
530 curl = util_ald_cache_fetch(st->util_ldap_cache, &curnode);
532 curl = util_ald_create_caches(st, url);
536 /* a simple compare? */
537 if (!compare_dn_on_server) {
538 /* unlock this read lock */
539 if (strcmp(dn, reqdn)) {
540 ldc->reason = "DN Comparison FALSE (direct strcmp())";
541 return LDAP_COMPARE_FALSE;
544 ldc->reason = "DN Comparison TRUE (direct strcmp())";
545 return LDAP_COMPARE_TRUE;
550 /* no - it's a server side compare */
553 /* is it in the compare cache? */
554 newnode.reqdn = (char *)reqdn;
555 node = util_ald_cache_fetch(curl->dn_compare_cache, &newnode);
557 /* If it's in the cache, it's good */
558 /* unlock this read lock */
560 ldc->reason = "DN Comparison TRUE (cached)";
561 return LDAP_COMPARE_TRUE;
564 /* unlock this read lock */
569 if (failures++ > 10) {
570 /* too many failures */
574 /* make a server connection */
575 if (LDAP_SUCCESS != (result = util_ldap_connection_open(r, ldc))) {
576 /* connect to server failed */
580 /* search for reqdn */
581 if ((result = ldap_search_ext_s(ldc->ldap, const_cast(reqdn), LDAP_SCOPE_BASE,
582 "(objectclass=*)", NULL, 1,
583 NULL, NULL, NULL, -1, &res)) == LDAP_SERVER_DOWN) {
584 ldc->reason = "DN Comparison ldap_search_ext_s() failed with server down";
585 util_ldap_connection_unbind(ldc);
588 if (result != LDAP_SUCCESS) {
589 /* search for reqdn failed - no match */
590 ldc->reason = "DN Comparison ldap_search_ext_s() failed";
594 entry = ldap_first_entry(ldc->ldap, res);
595 searchdn = ldap_get_dn(ldc->ldap, entry);
598 if (strcmp(dn, searchdn) != 0) {
599 /* compare unsuccessful */
600 ldc->reason = "DN Comparison FALSE (checked on server)";
601 result = LDAP_COMPARE_FALSE;
605 /* compare successful - add to the compare cache */
607 newnode.reqdn = (char *)reqdn;
608 newnode.dn = (char *)dn;
610 node = util_ald_cache_fetch(curl->dn_compare_cache, &newnode);
611 if ((node == NULL) ||
612 (strcmp(reqdn, node->reqdn) != 0) || (strcmp(dn, node->dn) != 0)) {
614 util_ald_cache_insert(curl->dn_compare_cache, &newnode);
618 ldc->reason = "DN Comparison TRUE (checked on server)";
619 result = LDAP_COMPARE_TRUE;
621 ldap_memfree(searchdn);
627 * Does an generic ldap_compare operation. It accepts a cache that it will use
628 * to lookup the compare in the cache. We cache two kinds of compares
629 * (require group compares) and (require user compares). Each compare has a different
630 * cache node: require group includes the DN; require user does not because the
631 * require user cache is owned by the
634 LDAP_DECLARE(int) util_ldap_cache_compare(request_rec *r, util_ldap_connection_t *ldc,
635 const char *url, const char *dn,
636 const char *attrib, const char *value)
639 util_url_node_t *curl;
640 util_url_node_t curnode;
641 util_compare_node_t *compare_nodep;
642 util_compare_node_t the_compare_node;
643 apr_time_t curtime = 0; /* silence gcc -Wall */
646 util_ldap_state_t *st =
647 (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
650 /* get cache entry (or create one) */
653 curl = util_ald_cache_fetch(st->util_ldap_cache, &curnode);
655 curl = util_ald_create_caches(st, url);
660 /* make a comparison to the cache */
662 curtime = apr_time_now();
664 the_compare_node.dn = (char *)dn;
665 the_compare_node.attrib = (char *)attrib;
666 the_compare_node.value = (char *)value;
667 the_compare_node.result = 0;
669 compare_nodep = util_ald_cache_fetch(curl->compare_cache, &the_compare_node);
671 if (compare_nodep != NULL) {
673 if (curtime - compare_nodep->lastcompare > st->compare_cache_ttl) {
674 /* ...but it is too old */
675 util_ald_cache_remove(curl->compare_cache, compare_nodep);
678 /* ...and it is good */
679 /* unlock this read lock */
681 if (LDAP_COMPARE_TRUE == compare_nodep->result) {
682 ldc->reason = "Comparison true (cached)";
683 return compare_nodep->result;
685 else if (LDAP_COMPARE_FALSE == compare_nodep->result) {
686 ldc->reason = "Comparison false (cached)";
687 return compare_nodep->result;
689 else if (LDAP_NO_SUCH_ATTRIBUTE == compare_nodep->result) {
690 ldc->reason = "Comparison no such attribute (cached)";
691 return compare_nodep->result;
694 ldc->reason = "Comparison undefined (cached)";
695 return compare_nodep->result;
699 /* unlock this read lock */
704 if (failures++ > 10) {
705 /* too many failures */
708 if (LDAP_SUCCESS != (result = util_ldap_connection_open(r, ldc))) {
713 if ((result = ldap_compare_s(ldc->ldap, const_cast(dn), const_cast(attrib), const_cast(value)))
714 == LDAP_SERVER_DOWN) {
715 /* connection failed - try again */
716 ldc->reason = "ldap_compare_s() failed with server down";
717 util_ldap_connection_unbind(ldc);
721 ldc->reason = "Comparison complete";
722 if ((LDAP_COMPARE_TRUE == result) ||
723 (LDAP_COMPARE_FALSE == result) ||
724 (LDAP_NO_SUCH_ATTRIBUTE == result)) {
726 /* compare completed; caching result */
728 the_compare_node.lastcompare = curtime;
729 the_compare_node.result = result;
731 /* If the node doesn't exist then insert it, otherwise just update it with
733 compare_nodep = util_ald_cache_fetch(curl->compare_cache, &the_compare_node);
734 if ((compare_nodep == NULL) ||
735 (strcmp(the_compare_node.dn, compare_nodep->dn) != 0) ||
736 (strcmp(the_compare_node.attrib, compare_nodep->attrib) != 0) ||
737 (strcmp(the_compare_node.value, compare_nodep->value) != 0)) {
739 util_ald_cache_insert(curl->compare_cache, &the_compare_node);
742 compare_nodep->lastcompare = curtime;
743 compare_nodep->result = result;
747 if (LDAP_COMPARE_TRUE == result) {
748 ldc->reason = "Comparison true (adding to cache)";
749 return LDAP_COMPARE_TRUE;
751 else if (LDAP_COMPARE_FALSE == result) {
752 ldc->reason = "Comparison false (adding to cache)";
753 return LDAP_COMPARE_FALSE;
756 ldc->reason = "Comparison no such attribute (adding to cache)";
757 return LDAP_NO_SUCH_ATTRIBUTE;
763 LDAP_DECLARE(int) util_ldap_cache_checkuserid(request_rec *r, util_ldap_connection_t *ldc,
764 const char *url, const char *basedn, int scope, char **attrs,
765 const char *filter, const char *bindpw, const char **binddn,
766 const char ***retvals)
768 const char **vals = NULL;
771 LDAPMessage *res, *entry;
775 util_url_node_t *curl; /* Cached URL node */
776 util_url_node_t curnode;
777 util_search_node_t *search_nodep; /* Cached search node */
778 util_search_node_t the_search_node;
781 util_ldap_state_t *st =
782 (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
785 /* Get the cache node for this url */
788 curl = (util_url_node_t *)util_ald_cache_fetch(st->util_ldap_cache, &curnode);
790 curl = util_ald_create_caches(st, url);
796 the_search_node.username = filter;
797 search_nodep = util_ald_cache_fetch(curl->search_cache, &the_search_node);
798 if (search_nodep != NULL) {
800 /* found entry in search cache... */
801 curtime = apr_time_now();
804 * Remove this item from the cache if its expired.
805 * If the sent password doesn't match the stored password,
806 * the entry will be removed and readded later if the
807 * credentials pass authentication.
809 if ((curtime - search_nodep->lastbind) > st->search_cache_ttl) {
810 /* ...but entry is too old */
811 util_ald_cache_remove(curl->search_cache, search_nodep);
813 else if ((search_nodep->bindpw) &&
814 (search_nodep->bindpw[0] != '\0') &&
815 (strcmp(search_nodep->bindpw, bindpw) == 0)) {
816 /* ...and entry is valid */
817 *binddn = search_nodep->dn;
818 *retvals = search_nodep->vals;
820 ldc->reason = "Authentication successful (cached)";
824 /* unlock this read lock */
829 * At this point, there is no valid cached search, so lets do the search.
833 * If any LDAP operation fails due to LDAP_SERVER_DOWN, control returns here.
836 if (failures++ > 10) {
839 if (LDAP_SUCCESS != (result = util_ldap_connection_open(r, ldc))) {
843 /* try do the search */
844 if ((result = ldap_search_ext_s(ldc->ldap,
845 const_cast(basedn), scope,
846 const_cast(filter), attrs, 0,
847 NULL, NULL, NULL, -1, &res)) == LDAP_SERVER_DOWN) {
848 ldc->reason = "ldap_search_ext_s() for user failed with server down";
849 util_ldap_connection_unbind(ldc);
853 /* if there is an error (including LDAP_NO_SUCH_OBJECT) return now */
854 if (result != LDAP_SUCCESS) {
855 ldc->reason = "ldap_search_ext_s() for user failed";
860 * We should have found exactly one entry; to find a different
861 * number is an error.
863 count = ldap_count_entries(ldc->ldap, res);
867 ldc->reason = "User not found";
869 ldc->reason = "User is not unique (search found two or more matches)";
871 return LDAP_NO_SUCH_OBJECT;
874 entry = ldap_first_entry(ldc->ldap, res);
876 /* Grab the dn, copy it into the pool, and free it again */
877 dn = ldap_get_dn(ldc->ldap, entry);
878 *binddn = apr_pstrdup(r->pool, dn);
882 * A bind to the server with an empty password always succeeds, so
883 * we check to ensure that the password is not empty. This implies
884 * that users who actually do have empty passwords will never be
885 * able to authenticate with this module. I don't see this as a big
888 if (!bindpw || strlen(bindpw) <= 0) {
890 ldc->reason = "Empty password not allowed";
891 return LDAP_INVALID_CREDENTIALS;
895 * Attempt to bind with the retrieved dn and the password. If the bind
896 * fails, it means that the password is wrong (the dn obviously
897 * exists, since we just retrieved it)
900 ldap_simple_bind_s(ldc->ldap, const_cast(*binddn), const_cast(bindpw))) ==
902 ldc->reason = "ldap_simple_bind_s() to check user credentials failed with server down";
904 util_ldap_connection_unbind(ldc);
908 /* failure? if so - return */
909 if (result != LDAP_SUCCESS) {
910 ldc->reason = "ldap_simple_bind_s() to check user credentials failed";
912 util_ldap_connection_unbind(ldc);
917 * We have just bound the connection to a different user and password
918 * combination, which might be reused unintentionally next time this
919 * connection is used from the connection pool. To ensure no confusion,
920 * we mark the connection as unbound.
926 * Get values for the provided attributes.
932 vals = apr_pcalloc(r->pool, sizeof(char *) * (k+1));
939 values = ldap_get_values(ldc->ldap, entry, attrs[i]);
940 while (values && values[j]) {
941 str = str ? apr_pstrcat(r->pool, str, "; ", values[j], NULL) : apr_pstrdup(r->pool, values[j]);
944 ldap_value_free(values);
952 * Add the new username to the search cache.
956 the_search_node.username = filter;
957 the_search_node.dn = *binddn;
958 the_search_node.bindpw = bindpw;
959 the_search_node.lastbind = apr_time_now();
960 the_search_node.vals = vals;
961 the_search_node.numvals = numvals;
963 /* Search again to make sure that another thread didn't ready insert this node
964 into the cache before we got here. If it does exist then update the lastbind */
965 search_nodep = util_ald_cache_fetch(curl->search_cache, &the_search_node);
966 if ((search_nodep == NULL) ||
967 (strcmp(*binddn, search_nodep->dn) != 0)) {
969 /* Nothing in cache, insert new entry */
970 util_ald_cache_insert(curl->search_cache, &the_search_node);
972 else if ((!search_nodep->bindpw) ||
973 (strcmp(bindpw, search_nodep->bindpw) != 0)) {
975 /* Entry in cache is invalid, remove it and insert new one */
976 util_ald_cache_remove(curl->search_cache, search_nodep);
977 util_ald_cache_insert(curl->search_cache, &the_search_node);
980 /* Cache entry is valid, update lastbind */
981 search_nodep->lastbind = the_search_node.lastbind;
987 ldc->reason = "Authentication successful";
992 * This function will return the DN of the entry matching userid.
993 * It is used to get the DN in case some other module than mod_auth_ldap
994 * has authenticated the user.
995 * The function is basically a copy of util_ldap_cache_checkuserid
996 * with password checking removed.
998 LDAP_DECLARE(int) util_ldap_cache_getuserdn(request_rec *r, util_ldap_connection_t *ldc,
999 const char *url, const char *basedn, int scope, char **attrs,
1000 const char *filter, const char **binddn,
1001 const char ***retvals)
1003 const char **vals = NULL;
1006 LDAPMessage *res, *entry;
1010 util_url_node_t *curl; /* Cached URL node */
1011 util_url_node_t curnode;
1012 util_search_node_t *search_nodep; /* Cached search node */
1013 util_search_node_t the_search_node;
1016 util_ldap_state_t *st =
1017 (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
1020 /* Get the cache node for this url */
1023 curl = (util_url_node_t *)util_ald_cache_fetch(st->util_ldap_cache, &curnode);
1025 curl = util_ald_create_caches(st, url);
1027 LDAP_CACHE_UNLOCK();
1031 the_search_node.username = filter;
1032 search_nodep = util_ald_cache_fetch(curl->search_cache, &the_search_node);
1033 if (search_nodep != NULL) {
1035 /* found entry in search cache... */
1036 curtime = apr_time_now();
1039 * Remove this item from the cache if its expired.
1041 if ((curtime - search_nodep->lastbind) > st->search_cache_ttl) {
1042 /* ...but entry is too old */
1043 util_ald_cache_remove(curl->search_cache, search_nodep);
1046 /* ...and entry is valid */
1047 *binddn = search_nodep->dn;
1048 *retvals = search_nodep->vals;
1049 LDAP_CACHE_UNLOCK();
1050 ldc->reason = "Search successful (cached)";
1051 return LDAP_SUCCESS;
1054 /* unlock this read lock */
1055 LDAP_CACHE_UNLOCK();
1059 * At this point, there is no valid cached search, so lets do the search.
1063 * If any LDAP operation fails due to LDAP_SERVER_DOWN, control returns here.
1066 if (failures++ > 10) {
1069 if (LDAP_SUCCESS != (result = util_ldap_connection_open(r, ldc))) {
1073 /* try do the search */
1074 if ((result = ldap_search_ext_s(ldc->ldap,
1075 const_cast(basedn), scope,
1076 const_cast(filter), attrs, 0,
1077 NULL, NULL, NULL, -1, &res)) == LDAP_SERVER_DOWN) {
1078 ldc->reason = "ldap_search_ext_s() for user failed with server down";
1079 util_ldap_connection_unbind(ldc);
1083 /* if there is an error (including LDAP_NO_SUCH_OBJECT) return now */
1084 if (result != LDAP_SUCCESS) {
1085 ldc->reason = "ldap_search_ext_s() for user failed";
1090 * We should have found exactly one entry; to find a different
1091 * number is an error.
1093 count = ldap_count_entries(ldc->ldap, res);
1097 ldc->reason = "User not found";
1099 ldc->reason = "User is not unique (search found two or more matches)";
1101 return LDAP_NO_SUCH_OBJECT;
1104 entry = ldap_first_entry(ldc->ldap, res);
1106 /* Grab the dn, copy it into the pool, and free it again */
1107 dn = ldap_get_dn(ldc->ldap, entry);
1108 *binddn = apr_pstrdup(r->pool, dn);
1112 * Get values for the provided attributes.
1118 vals = apr_pcalloc(r->pool, sizeof(char *) * (k+1));
1125 values = ldap_get_values(ldc->ldap, entry, attrs[i]);
1126 while (values && values[j]) {
1127 str = str ? apr_pstrcat(r->pool, str, "; ", values[j], NULL) : apr_pstrdup(r->pool, values[j]);
1130 ldap_value_free(values);
1138 * Add the new username to the search cache.
1142 the_search_node.username = filter;
1143 the_search_node.dn = *binddn;
1144 the_search_node.bindpw = NULL;
1145 the_search_node.lastbind = apr_time_now();
1146 the_search_node.vals = vals;
1147 the_search_node.numvals = numvals;
1149 /* Search again to make sure that another thread didn't ready insert this node
1150 into the cache before we got here. If it does exist then update the lastbind */
1151 search_nodep = util_ald_cache_fetch(curl->search_cache, &the_search_node);
1152 if ((search_nodep == NULL) ||
1153 (strcmp(*binddn, search_nodep->dn) != 0)) {
1155 /* Nothing in cache, insert new entry */
1156 util_ald_cache_insert(curl->search_cache, &the_search_node);
1159 * Don't update lastbind on entries with bindpw because
1160 * we haven't verified that password. It's OK to update
1161 * the entry if there is no password in it.
1163 else if (!search_nodep->bindpw) {
1164 /* Cache entry is valid, update lastbind */
1165 search_nodep->lastbind = the_search_node.lastbind;
1167 LDAP_CACHE_UNLOCK();
1171 ldc->reason = "Search successful";
1172 return LDAP_SUCCESS;
1176 * Reports if ssl support is enabled
1178 * 1 = enabled, 0 = not enabled
1180 LDAP_DECLARE(int) util_ldap_ssl_supported(request_rec *r)
1182 util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(
1183 r->server->module_config, &ldap_module);
1185 return(st->ssl_support);
1189 /* ---------------------------------------- */
1190 /* config directives */
1193 static const char *util_ldap_set_cache_bytes(cmd_parms *cmd, void *dummy, const char *bytes)
1195 util_ldap_state_t *st =
1196 (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
1199 st->cache_bytes = atol(bytes);
1201 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
1202 "[%" APR_PID_T_FMT "] ldap cache: Setting shared memory "
1203 " cache size to %" APR_SIZE_T_FMT " bytes.",
1204 getpid(), st->cache_bytes);
1209 static const char *util_ldap_set_cache_file(cmd_parms *cmd, void *dummy, const char *file)
1211 util_ldap_state_t *st =
1212 (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
1216 st->cache_file = ap_server_root_relative(st->pool, file);
1219 st->cache_file = NULL;
1222 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
1223 "LDAP cache: Setting shared memory cache file to %s bytes.",
1229 static const char *util_ldap_set_cache_ttl(cmd_parms *cmd, void *dummy, const char *ttl)
1231 util_ldap_state_t *st =
1232 (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
1235 st->search_cache_ttl = atol(ttl) * 1000000;
1237 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
1238 "[%d] ldap cache: Setting cache TTL to %ld microseconds.",
1239 getpid(), st->search_cache_ttl);
1244 static const char *util_ldap_set_cache_entries(cmd_parms *cmd, void *dummy, const char *size)
1246 util_ldap_state_t *st =
1247 (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
1251 st->search_cache_size = atol(size);
1252 if (st->search_cache_size < 0) {
1253 st->search_cache_size = 0;
1256 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
1257 "[%d] ldap cache: Setting search cache size to %ld entries.",
1258 getpid(), st->search_cache_size);
1263 static const char *util_ldap_set_opcache_ttl(cmd_parms *cmd, void *dummy, const char *ttl)
1265 util_ldap_state_t *st =
1266 (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
1269 st->compare_cache_ttl = atol(ttl) * 1000000;
1271 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
1272 "[%d] ldap cache: Setting operation cache TTL to %ld microseconds.",
1273 getpid(), st->compare_cache_ttl);
1278 static const char *util_ldap_set_opcache_entries(cmd_parms *cmd, void *dummy, const char *size)
1280 util_ldap_state_t *st =
1281 (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
1284 st->compare_cache_size = atol(size);
1285 if (st->compare_cache_size < 0) {
1286 st->compare_cache_size = 0;
1289 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
1290 "[%d] ldap cache: Setting operation cache size to %ld entries.",
1291 getpid(), st->compare_cache_size);
1296 static const char *util_ldap_set_cert_auth(cmd_parms *cmd, void *dummy, const char *file)
1298 util_ldap_state_t *st =
1299 (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
1301 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1309 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
1310 "LDAP: SSL trusted certificate authority file - %s",
1313 st->cert_auth_file = ap_server_root_relative(cmd->pool, file);
1315 if (st->cert_auth_file &&
1316 ((rv = apr_stat (&finfo, st->cert_auth_file, APR_FINFO_MIN, cmd->pool)) != APR_SUCCESS))
1318 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cmd->server,
1319 "LDAP: Could not open SSL trusted certificate authority file - %s",
1320 st->cert_auth_file == NULL ? file : st->cert_auth_file);
1321 return "Invalid file path";
1328 static const char *util_ldap_set_cert_type(cmd_parms *cmd, void *dummy, const char *Type)
1330 util_ldap_state_t *st =
1331 (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
1333 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1338 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
1339 "LDAP: SSL trusted certificate authority file type - %s",
1342 if (0 == strcmp("DER_FILE", Type))
1343 st->cert_file_type = LDAP_CA_TYPE_DER;
1345 else if (0 == strcmp("BASE64_FILE", Type))
1346 st->cert_file_type = LDAP_CA_TYPE_BASE64;
1348 else if (0 == strcmp("CERT7_DB_PATH", Type))
1349 st->cert_file_type = LDAP_CA_TYPE_CERT7_DB;
1352 st->cert_file_type = LDAP_CA_TYPE_UNKNOWN;
1357 static const char *util_ldap_set_connection_timeout(cmd_parms *cmd, void *dummy, const char *ttl)
1359 util_ldap_state_t *st =
1360 (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
1362 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1368 #ifdef LDAP_OPT_NETWORK_TIMEOUT
1369 st->connectionTimeout = atol(ttl);
1371 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
1372 "[%d] ldap connection: Setting connection timeout to %ld seconds.",
1373 getpid(), st->connectionTimeout);
1375 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, cmd->server,
1376 "LDAP: Connection timout option not supported by the LDAP SDK in use." );
1382 void *util_ldap_create_config(apr_pool_t *p, server_rec *s)
1384 util_ldap_state_t *st =
1385 (util_ldap_state_t *)apr_pcalloc(p, sizeof(util_ldap_state_t));
1387 /* Create a per vhost pool for mod_ldap to use, serialized with
1388 * st->mutex (also one per vhost)
1390 apr_pool_create(&st->pool, p);
1392 apr_thread_mutex_create(&st->mutex, APR_THREAD_MUTEX_DEFAULT, st->pool);
1395 st->cache_bytes = 100000;
1396 st->search_cache_ttl = 600000000;
1397 st->search_cache_size = 1024;
1398 st->compare_cache_ttl = 600000000;
1399 st->compare_cache_size = 1024;
1400 st->connections = NULL;
1401 st->cert_auth_file = NULL;
1402 st->cert_file_type = LDAP_CA_TYPE_UNKNOWN;
1403 st->ssl_support = 0;
1404 st->connectionTimeout = 10;
1409 static apr_status_t util_ldap_cleanup_module(void *data)
1411 #if APR_HAS_LDAP_SSL && APR_HAS_NOVELL_LDAPSDK
1412 server_rec *s = data;
1413 util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(
1414 s->module_config, &ldap_module);
1416 if (st->ssl_support)
1417 ldapssl_client_deinit();
1423 static int util_ldap_post_config(apr_pool_t *p, apr_pool_t *plog,
1424 apr_pool_t *ptemp, server_rec *s)
1426 int rc = LDAP_SUCCESS;
1427 apr_status_t result;
1428 char buf[MAX_STRING_LEN];
1429 server_rec *s_vhost;
1430 util_ldap_state_t *st_vhost;
1432 util_ldap_state_t *st =
1433 (util_ldap_state_t *)ap_get_module_config(s->module_config, &ldap_module);
1436 const char *userdata_key = "util_ldap_init";
1438 /* util_ldap_post_config() will be called twice. Don't bother
1439 * going through all of the initialization on the first call
1440 * because it will just be thrown away.*/
1441 apr_pool_userdata_get(&data, userdata_key, s->process->pool);
1443 apr_pool_userdata_set((const void *)1, userdata_key,
1444 apr_pool_cleanup_null, s->process->pool);
1446 #if APR_HAS_SHARED_MEMORY
1447 /* If the cache file already exists then delete it. Otherwise we are
1448 * going to run into problems creating the shared memory. */
1449 if (st->cache_file) {
1450 char *lck_file = apr_pstrcat (ptemp, st->cache_file, ".lck", NULL);
1451 apr_file_remove(st->cache_file, ptemp);
1452 apr_file_remove(lck_file, ptemp);
1458 #if APR_HAS_SHARED_MEMORY
1459 /* initializing cache if shared memory size is not zero and we already don't have shm address */
1460 if (!st->cache_shm && st->cache_bytes > 0) {
1462 result = util_ldap_cache_init(p, st);
1463 if (result != APR_SUCCESS) {
1464 apr_strerror(result, buf, sizeof(buf));
1465 ap_log_error(APLOG_MARK, APLOG_ERR, result, s,
1466 "LDAP cache: error while creating a shared memory segment: %s", buf);
1470 #if APR_HAS_SHARED_MEMORY
1471 if (st->cache_file) {
1472 st->lock_file = apr_pstrcat (st->pool, st->cache_file, ".lck", NULL);
1476 st->lock_file = ap_server_root_relative(st->pool, tmpnam(NULL));
1478 result = apr_global_mutex_create(&st->util_ldap_cache_lock, st->lock_file, APR_LOCK_DEFAULT, st->pool);
1479 if (result != APR_SUCCESS) {
1483 #ifdef UTIL_LDAP_SET_MUTEX_PERMS
1484 result = unixd_set_global_mutex_perms(st->util_ldap_cache_lock);
1485 if (result != APR_SUCCESS) {
1486 ap_log_error(APLOG_MARK, APLOG_CRIT, result, s,
1487 "LDAP cache: failed to set mutex permissions");
1492 /* merge config in all vhost */
1495 st_vhost = (util_ldap_state_t *)ap_get_module_config(s_vhost->module_config, &ldap_module);
1497 #if APR_HAS_SHARED_MEMORY
1498 st_vhost->cache_shm = st->cache_shm;
1499 st_vhost->cache_rmm = st->cache_rmm;
1500 st_vhost->cache_file = st->cache_file;
1501 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, result, s,
1502 "LDAP merging Shared Cache conf: shm=0x%pp rmm=0x%pp for VHOST: %s",
1503 st->cache_shm, st->cache_rmm, s_vhost->server_hostname);
1505 st_vhost->lock_file = st->lock_file;
1506 s_vhost = s_vhost->next;
1508 #if APR_HAS_SHARED_MEMORY
1511 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "LDAP cache: LDAPSharedCacheSize is zero, disabling shared memory cache");
1515 /* log the LDAP SDK used
1517 #if APR_HAS_NETSCAPE_LDAPSDK
1519 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
1520 "LDAP: Built with Netscape LDAP SDK" );
1522 #elif APR_HAS_NOVELL_LDAPSDK
1524 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
1525 "LDAP: Built with Novell LDAP SDK" );
1527 #elif APR_HAS_OPENLDAP_LDAPSDK
1529 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
1530 "LDAP: Built with OpenLDAP LDAP SDK" );
1532 #elif APR_HAS_MICROSOFT_LDAPSDK
1534 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
1535 "LDAP: Built with Microsoft LDAP SDK" );
1538 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
1539 "LDAP: Built with unknown LDAP SDK" );
1541 #endif /* APR_HAS_NETSCAPE_LDAPSDK */
1545 apr_pool_cleanup_register(p, s, util_ldap_cleanup_module,
1546 util_ldap_cleanup_module);
1548 /* initialize SSL support if requested
1550 if (st->cert_auth_file)
1552 #if APR_HAS_LDAP_SSL /* compiled with ssl support */
1554 #if APR_HAS_NETSCAPE_LDAPSDK
1556 /* Netscape sdk only supports a cert7.db file
1558 if (st->cert_file_type == LDAP_CA_TYPE_CERT7_DB)
1560 rc = ldapssl_client_init(st->cert_auth_file, NULL);
1564 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
1565 "LDAP: Invalid LDAPTrustedCAType directive - "
1566 "CERT7_DB_PATH type required");
1570 #elif APR_HAS_NOVELL_LDAPSDK
1572 /* Novell SDK supports DER or BASE64 files
1574 if (st->cert_file_type == LDAP_CA_TYPE_DER ||
1575 st->cert_file_type == LDAP_CA_TYPE_BASE64 )
1577 rc = ldapssl_client_init(NULL, NULL);
1578 if (LDAP_SUCCESS == rc)
1580 if (st->cert_file_type == LDAP_CA_TYPE_BASE64)
1581 rc = ldapssl_add_trusted_cert(st->cert_auth_file,
1582 LDAPSSL_CERT_FILETYPE_B64);
1584 rc = ldapssl_add_trusted_cert(st->cert_auth_file,
1585 LDAPSSL_CERT_FILETYPE_DER);
1587 if (LDAP_SUCCESS != rc)
1588 ldapssl_client_deinit();
1593 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
1594 "LDAP: Invalid LDAPTrustedCAType directive - "
1595 "DER_FILE or BASE64_FILE type required");
1599 #elif APR_HAS_OPENLDAP_LDAPSDK
1601 /* OpenLDAP SDK supports BASE64 files
1603 if (st->cert_file_type == LDAP_CA_TYPE_BASE64)
1605 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, st->cert_auth_file);
1609 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
1610 "LDAP: Invalid LDAPTrustedCAType directive - "
1611 "BASE64_FILE type required");
1616 #elif APR_HAS_MICROSOFT_LDAPSDK
1618 /* Microsoft SDK use the registry certificate store - always
1619 * assume support is always available
1625 #endif /* APR_HAS_NETSCAPE_LDAPSDK */
1627 #else /* not compiled with SSL Support */
1629 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
1630 "LDAP: Not built with SSL support." );
1633 #endif /* APR_HAS_LDAP_SSL */
1635 if (LDAP_SUCCESS == rc)
1637 st->ssl_support = 1;
1641 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
1642 "LDAP: SSL initialization failed");
1643 st->ssl_support = 0;
1647 /* The Microsoft SDK uses the registry certificate store -
1648 * always assume support is available
1650 #if APR_HAS_MICROSOFT_LDAPSDK
1651 st->ssl_support = 1;
1655 /* log SSL status - If SSL isn't available it isn't necessarily
1656 * an error because the modules asking for LDAP connections
1657 * may not ask for SSL support
1659 if (st->ssl_support)
1661 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
1662 "LDAP: SSL support available" );
1666 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
1667 "LDAP: SSL support unavailable" );
1673 static void util_ldap_child_init(apr_pool_t *p, server_rec *s)
1676 util_ldap_state_t *st = ap_get_module_config(s->module_config, &ldap_module);
1678 if (!st->util_ldap_cache_lock) return;
1680 sts = apr_global_mutex_child_init(&st->util_ldap_cache_lock, st->lock_file, p);
1681 if (sts != APR_SUCCESS) {
1682 ap_log_error(APLOG_MARK, APLOG_CRIT, sts, s,
1683 "Failed to initialise global mutex %s in child process %"
1686 st->lock_file, getpid());
1690 ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, s,
1691 "Initialisation of global mutex %s in child process %"
1694 st->lock_file, getpid());
1698 command_rec util_ldap_cmds[] = {
1699 AP_INIT_TAKE1("LDAPSharedCacheSize", util_ldap_set_cache_bytes, NULL, RSRC_CONF,
1700 "Sets the size of the shared memory cache in bytes. "
1701 "Zero means disable the shared memory cache. Defaults to 100KB."),
1703 AP_INIT_TAKE1("LDAPSharedCacheFile", util_ldap_set_cache_file, NULL, RSRC_CONF,
1704 "Sets the file of the shared memory cache."
1705 "Nothing means disable the shared memory cache."),
1707 AP_INIT_TAKE1("LDAPCacheEntries", util_ldap_set_cache_entries, NULL, RSRC_CONF,
1708 "Sets the maximum number of entries that are possible in the LDAP "
1710 "Zero means no limit; -1 disables the cache. Defaults to 1024 entries."),
1712 AP_INIT_TAKE1("LDAPCacheTTL", util_ldap_set_cache_ttl, NULL, RSRC_CONF,
1713 "Sets the maximum time (in seconds) that an item can be cached in the LDAP "
1714 "search cache. Zero means no limit. Defaults to 600 seconds (10 minutes)."),
1716 AP_INIT_TAKE1("LDAPOpCacheEntries", util_ldap_set_opcache_entries, NULL, RSRC_CONF,
1717 "Sets the maximum number of entries that are possible in the LDAP "
1719 "Zero means no limit; -1 disables the cache. Defaults to 1024 entries."),
1721 AP_INIT_TAKE1("LDAPOpCacheTTL", util_ldap_set_opcache_ttl, NULL, RSRC_CONF,
1722 "Sets the maximum time (in seconds) that an item is cached in the LDAP "
1723 "operation cache. Zero means no limit. Defaults to 600 seconds (10 minutes)."),
1725 AP_INIT_TAKE1("LDAPTrustedCA", util_ldap_set_cert_auth, NULL, RSRC_CONF,
1726 "Sets the file containing the trusted Certificate Authority certificate. "
1727 "Used to validate the LDAP server certificate for SSL connections."),
1729 AP_INIT_TAKE1("LDAPTrustedCAType", util_ldap_set_cert_type, NULL, RSRC_CONF,
1730 "Specifies the type of the Certificate Authority file. "
1731 "The following types are supported: "
1732 " DER_FILE - file in binary DER format "
1733 " BASE64_FILE - file in Base64 format "
1734 " CERT7_DB_PATH - Netscape certificate database file "),
1736 AP_INIT_TAKE1("LDAPConnectionTimeout", util_ldap_set_connection_timeout, NULL, RSRC_CONF,
1737 "Specifies the LDAP socket connection timeout in seconds. "
1738 "Default is 10 seconds. "),
1743 static void util_ldap_register_hooks(apr_pool_t *p)
1745 ap_hook_post_config(util_ldap_post_config,NULL,NULL,APR_HOOK_MIDDLE);
1746 ap_hook_handler(util_ldap_handler, NULL, NULL, APR_HOOK_MIDDLE);
1747 ap_hook_child_init(util_ldap_child_init, NULL, NULL, APR_HOOK_MIDDLE);
1750 module ldap_module = {
1751 STANDARD20_MODULE_STUFF,
1752 NULL, /* dir config creater */
1753 NULL, /* dir merger --- default is to override */
1754 util_ldap_create_config, /* server config */
1755 NULL, /* merge server config */
1756 util_ldap_cmds, /* command table */
1757 util_ldap_register_hooks, /* set up request processing hooks */