util_ldap.c revision d0ba3b97557d47323bd055fb4002ed7692f703b9
/* ==================================================================== * The Apache Software License, Version 1.1 * Copyright (c) 2000-2003 The Apache Software Foundation. All rights * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * ==================================================================== * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * Original code from auth_ldap module for Apache v1.3: * Copyright 1998, 1999 Enbridge Pipelines Inc. * Copyright 1999-2001 Dave Carrigan /* defines for certificate file types * Some definitions to help between various versions of apache. "DTD HTML 3.2 Final//EN\">\n" "DTD HTML 4.0 Transitional//EN\"\n" \
"DTD HTML 4.0 Frameset//EN\"\n" \
* This handler generates a status page about the current performance of * the LDAP cache. It is enabled as follows: * <Location /ldap-status> "<html><head><title>LDAP Cache Information</title></head>\n", r);
ap_rputs(
"<body bgcolor='#ffffff'><h1 align=center>LDAP Cache Information</h1>\n", r);
"<tr bgcolor='#000000'>\n" "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name</b></font></td>" "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Entries</b></font></td>" "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg. Chain Len.</b></font></td>" "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Hits</b></font></td>" "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Ins/Rem</b></font></td>" "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Purges</b></font></td>" "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg Purge Time</b></font></td>" /* ------------------------------------------------------------------ */ * Closes an LDAP connection by unlocking it. The next time * util_ldap_connection_find() is called this connection will be * Is it safe leaving bound connections floating around between the * different modules? Keeping the user bound is a performance boost, * but it is also a potential security problem - maybe. * For now we unbind the user when we finish with a connection, but /* mark our connection as available for reuse */ * Destroys an LDAP connection by unbinding. This function is registered * with the pool cleanup function - causing the LDAP connections to be * shut down cleanly on graceful restart. /* unbinding from the LDAP server */ /* release the lock we were using. The lock should have already been released in the close connection call. But just in case it wasn't, we first try to get the lock before unlocking it to avoid unlocking an unheld lock. Unlocking an unheld lock causes problems on NetWare. The other option would be to assume that close connection did * Connect to the LDAP server and binds. Does not connect if already * connected (i.e. ldc->ldap is non-NULL.) Does not bind if already bound. * Returns LDAP_SUCCESS on success; and an error code on failure /* If the connection is already bound, return ldc->
reason =
"LDAP: connection open successful (already bound)";
/* create the ldap session handle /* clear connection requested */ else /* ssl connnection requested */ /* check configuration to make sure it supports SSL ldc->
reason =
"LDAP: ldap_set_option - LDAP_OPT_X_TLS_HARD failed";
ldc->
reason =
"LDAP: ssl connections not supported";
#
endif /* APR_HAS_NOVELL_LDAPSDK */ #
endif /* APR_HAS_LDAP_SSL */ ldc->
reason =
"LDAP: ssl connections not supported";
ldc->
reason =
"LDAP: ldap initialization failed";
/* Set the alias dereferencing option */ /* always default to LDAP V3 */ /* add the cleanup to the pool */ /* loop trying to bind up to 10 times if LDAP_SERVER_DOWN error is * returned. Break out of the loop on Success or any other error. * NOTE: Looping is probably not a great idea. If the server isn't * responding the chances it will respond after a few tries are poor. * However, the original code looped and it only happens on ldc->
reason =
"LDAP: connection open successful";
/* free the handle if there was an error ldc->
reason =
"LDAP: ldap_simple_bind_s() failed";
* Find an existing ldap connection struct that matches the * provided ldap connection parameters. * If not found in the cache, a new ldc structure will be allocated from st->pool * and returned to the caller. If found in the cache, a pointer to the existing * ldc structure will be returned. /* mutex lock this function */ /* Search for an exact connection match in the list that is not /* If nothing found, search again, but we don't care about the * binddn and bindpw this time. /* the bind credentials have changed */ /* artificially disable cache */ /* If no connection what found after the second search, we * Add the new connection entry to the linked list. Note that we * don't actually establish an LDAP connection yet; that happens * the first time authentication is requested. /* create the details to the pool in st */ /* ------------------------------------------------------------------ */ * Compares two DNs to see if they're equal. The only way to do this correctly is to * search for the dn and then do ldap_get_dn() on the result. This should match the * initial dn, since it would have been also retrieved with ldap_get_dn(). This is * expensive, so if the configuration value compare_dn_on_server is * false, just does an ordinary strcmp. * The lock for the ldap cache should already be acquired. const char *
url,
const char *
dn,
const char *
reqdn,
/* read lock this function */ /* get cache entry (or create one) */ /* unlock this read lock */ ldc->
reason =
"DN Comparison FALSE (direct strcmp())";
ldc->
reason =
"DN Comparison TRUE (direct strcmp())";
/* no - it's a server side compare */ /* is it in the compare cache? */ /* If it's in the cache, it's good */ /* unlock this read lock */ /* unlock this read lock */ /* make a server connection */ /* connect to server failed */ "(objectclass=*)",
NULL,
1,
ldc->
reason =
"DN Comparison ldap_search_ext_s() failed with server down";
/* search for reqdn failed - no match */ ldc->
reason =
"DN Comparison ldap_search_ext_s() failed";
/* compare unsuccessful */ ldc->
reason =
"DN Comparison FALSE (checked on server)";
/* compare successful - add to the compare cache */ ldc->
reason =
"DN Comparison TRUE (checked on server)";
* Does an generic ldap_compare operation. It accepts a cache that it will use * to lookup the compare in the cache. We cache two kinds of compares * (require group compares) and (require user compares). Each compare has a different * cache node: require group includes the DN; require user does not because the * require user cache is owned by the const char *
url,
const char *
dn,
/* read lock this function */ /* get cache entry (or create one) */ /* make a comparison to the cache */ /* ...but it is too old */ /* unlock this read lock */ ldc->
reason =
"Comparison no such attribute (cached)";
ldc->
reason =
"Comparison undefined (cached)";
/* unlock this read lock */ /* connection failed - try again */ ldc->
reason =
"ldap_compare_s() failed with server down";
/* compare completed; caching result */ ldc->
reason =
"Comparison true (adding to cache)";
ldc->
reason =
"Comparison false (adding to cache)";
ldc->
reason =
"Comparison no such attribute (adding to cache)";
/* read lock this function */ /* Get the cache node for this url */ /* found entry in search cache... */ * Remove this item from the cache if its expired, or if the * sent password doesn't match the storepassword. /* ...but entry is too old */ /* ...but cached password doesn't match sent password */ /* ...and entry is valid */ ldc->
reason =
"Authentication successful (cached)";
/* unlock this read lock */ * At this point, there is no valid cached search, so lets do the search. * If any LDAP operation fails due to LDAP_SERVER_DOWN, control returns here. ldc->
reason =
"ldap_search_ext_s() for user failed with server down";
/* if there is an error (including LDAP_NO_SUCH_OBJECT) return now */ ldc->
reason =
"ldap_search_ext_s() for user failed";
* We should have found exactly one entry; to find a different ldc->
reason =
"User is not unique (search found two or more matches)";
/* Grab the dn, copy it into the pool, and free it again */ * A bind to the server with an empty password always succeeds, so * we check to ensure that the password is not empty. This implies * that users who actually do have empty passwords will never be * able to authenticate with this module. I don't see this as a big * Attempt to bind with the retrieved dn and the password. If the bind * fails, it means that the password is wrong (the dn obviously * exists, since we just retrieved it) ldc->
reason =
"ldap_simple_bind_s() to check user credentials failed with server down";
/* failure? if so - return */ ldc->
reason =
"ldap_simple_bind_s() to check user credentials failed";
* Get values for the provided attributes. * Add the new username to the search cache. * Reports if ssl support is enabled * 1 = enabled, 0 = not enabled /* ---------------------------------------- */ "[%d] ldap cache: Setting shared memory cache size to %d bytes.",
"LDAP cache: Setting shared memory cache file to %s bytes.",
"[%d] ldap cache: Setting cache TTL to %ld microseconds.",
"[%d] ldap cache: Setting search cache size to %ld entries.",
"[%d] ldap cache: Setting operation cache TTL to %ld microseconds.",
"[%d] ldap cache: Setting operation cache size to %ld entries.",
"LDAP: SSL trusted certificate authority file - %s",
"LDAP: SSL trusted certificate authority file type - %s",
/* initializing cache if file is here and we already don't have shm addr*/ "LDAP cache init: %s",
buf);
/* merge config in all vhost */ "LDAP merging Shared Cache conf: shm=0x%x rmm=0x%x for VHOST: %s",
"LDAP: Built with Netscape LDAP SDK" );
"LDAP: Built with Novell LDAP SDK" );
"LDAP: Built with OpenLDAP LDAP SDK" );
"LDAP: Built with Microsoft LDAP SDK" );
"LDAP: Built with unknown LDAP SDK" );
#
endif /* APR_HAS_NETSCAPE_LDAPSDK */ /* initialize SSL support if requested /* Netscape sdk only supports a cert7.db file "LDAP: Invalid LDAPTrustedCAType directive - " "CERT7_DB_PATH type required");
/* Novell SDK supports DER or BASE64 files "LDAP: Invalid LDAPTrustedCAType directive - " "DER_FILE or BASE64_FILE type required");
/* OpenLDAP SDK supports BASE64 files "LDAP: Invalid LDAPTrustedCAType directive - " "BASE64_FILE type required");
/* Microsoft SDK use the registry certificate store - always * assume support is always available #
endif /* APR_HAS_NETSCAPE_LDAPSDK */ #
else /* not compiled with SSL Support */ "LDAP: Not built with SSL support." );
#
endif /* APR_HAS_LDAP_SSL */ "LDAP: SSL initialization failed");
/* The Microsoft SDK uses the registry certificate store - * always assume support is available /* log SSL status - If SSL isn't available it isn't necessarily * an error because the modules asking for LDAP connections * may not ask for SSL support "LDAP: SSL support available" );
"LDAP: SSL support unavailable" );
"Sets the size of the shared memory cache in bytes. " "Zero means disable the shared memory cache. Defaults to 100KB."),
"Sets the file of the shared memory cache." "Nothing means disable the shared memory cache."),
"Sets the maximum number of entries that are possible in the LDAP " "Zero means no limit; -1 disables the cache. Defaults to 1024 entries."),
"Sets the maximum time (in seconds) that an item can be cached in the LDAP " "search cache. Zero means no limit. Defaults to 600 seconds (10 minutes)."),
"Sets the maximum number of entries that are possible in the LDAP " "Zero means no limit; -1 disables the cache. Defaults to 1024 entries."),
"Sets the maximum time (in seconds) that an item is cached in the LDAP " "operation cache. Zero means no limit. Defaults to 600 seconds (10 minutes)."),
"Sets the file containing the trusted Certificate Authority certificate. " "Used to validate the LDAP server certificate for SSL connections."),
"Specifies the type of the Certificate Authority file. " "The following types are supported: " " DER_FILE - file in binary DER format " " BASE64_FILE - file in Base64 format " " CERT7_DB_PATH - Netscape certificate database file "),
NULL,
/* dir config creater */ NULL,
/* dir merger --- default is to override */ NULL,
/* merge server config */