You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by mi...@apache.org on 2005/01/19 20:52:12 UTC
svn commit: r125645 - /httpd/httpd/trunk/CHANGES /httpd/httpd/trunk/docs/manual/mod/mod_ldap.xml /httpd/httpd/trunk/include/util_ldap.h /httpd/httpd/trunk/modules/ldap/util_ldap.c
Author: minfrin
Date: Wed Jan 19 11:52:08 2005
New Revision: 125645
URL: http://svn.apache.org/viewcvs?view=rev&rev=125645
Log:
mod_ldap: Updated to use the new apr-util v1.1 apr_ldap_*_option()
API for the setting of server and client SSL certificates. Replaced
LDAPTrustedCA directive with LDAPTrustedGlobalCert and
LDAPTrustedClientCert directives to correctly support global certs
(CA certs / Netware client certs) and per connection client certs
as supported by Netware, OpenLDAP and Netscape/Mozilla.
Modified:
httpd/httpd/trunk/CHANGES
httpd/httpd/trunk/docs/manual/mod/mod_ldap.xml
httpd/httpd/trunk/include/util_ldap.h
httpd/httpd/trunk/modules/ldap/util_ldap.c
Modified: httpd/httpd/trunk/CHANGES
Url: http://svn.apache.org/viewcvs/httpd/httpd/trunk/CHANGES?view=diff&rev=125645&p1=httpd/httpd/trunk/CHANGES&r1=125644&p2=httpd/httpd/trunk/CHANGES&r2=125645
==============================================================================
--- httpd/httpd/trunk/CHANGES (original)
+++ httpd/httpd/trunk/CHANGES Wed Jan 19 11:52:08 2005
@@ -2,6 +2,14 @@
[Remove entries to the current 2.0 section below, when backported]
+ *) mod_ldap: Updated to use the new apr-util v1.1 apr_ldap_*_option()
+ API for the setting of server and client SSL certificates. Replaced
+ LDAPTrustedCA directive with LDAPTrustedGlobalCert and
+ LDAPTrustedClientCert directives to correctly support global certs
+ (CA certs / Netware client certs) and per connection client certs
+ as supported by Netware, OpenLDAP and Netscape/Mozilla.
+ [Graham Leggett]
+
*) mod_proxy: Handle client-aborted connections correctly. PR 32443.
[Janne Hietam�ki, Joe Orton]
Modified: httpd/httpd/trunk/docs/manual/mod/mod_ldap.xml
Url: http://svn.apache.org/viewcvs/httpd/httpd/trunk/docs/manual/mod/mod_ldap.xml?view=diff&rev=125645&p1=httpd/httpd/trunk/docs/manual/mod/mod_ldap.xml&r1=125644&p2=httpd/httpd/trunk/docs/manual/mod/mod_ldap.xml&r2=125645
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_ldap.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_ldap.xml Wed Jan 19 11:52:08 2005
@@ -45,7 +45,7 @@
<p>SSL support requires that <module>mod_ldap</module> be linked
with one of the following LDAP SDKs: <a href="http://www.openldap.org/">
OpenLDAP SDK</a> (both 1.x and 2.x), <a href="http://developer.novell.com/ndk/cldap.htm">
- Novell LDAP SDK</a> or the <a href="http://www.iplanet.com/downloads/developer/">
+ Novell LDAP SDK</a>, native Solaris LDAP SDK, native Microsoft LDAP SDK, or the <a href="http://www.iplanet.com/downloads/developer/">
iPlanet(Netscape)</a> SDK.</p>
</summary>
@@ -182,23 +182,22 @@
</section>
</section>
-<section id="usingssltls"><title>Using SSL</title>
+<section id="usingssltls"><title>Using SSL/TLS</title>
- <p>The ability to create an SSL connections to an LDAP server
+ <p>The ability to create an SSL and TLS connections to an LDAP server
is defined by the directives <directive module="mod_ldap">
- LDAPTrustedCA</directive> and <directive module="mod_ldap">
- LDAPTrustedCAType</directive>. These directives specify the certificate
- file or database and the certificate type. Whenever the LDAP url
- includes <em>ldaps://</em>, <module>mod_ldap</module> will establish
- a secure connection to the LDAP server.</p>
+ LDAPTrustedGlobalCert</directive>, <directive module="mod_ldap">
+ LDAPTrustedClientCert</directive> and <directive module="mod_ldap">
+ LDAPTrustedMode</directive>. These directives specify the CA and
+ optional client certificates to be used, as well as the type of
+ encryption to be used on the connection (none, SSL or TLS/STARTTLS).</p>
<example>
- # Establish an SSL LDAP connection. Requires that <br />
+ # Establish an SSL LDAP connection on port 636. Requires that <br />
# mod_ldap and mod_authnz_ldap be loaded. Change the <br />
# "yourdomain.example.com" to match your domain.<br />
<br />
- LDAPTrustedCA /certs/certfile.der<br />
- LDAPTrustedCAType DER_FILE<br />
+ LDAPTrustedGlobalCert CA_DER /certs/certfile.der<br />
<br />
<Location /ldap-status><br />
<indent>
@@ -214,16 +213,163 @@
</Location>
</example>
- <p>If <module>mod_ldap</module> is linked against the
- Netscape/iPlanet LDAP SDK, it will not talk to any SSL server
- unless that server has a certificate signed by a known Certificate
- Authority. As part of the configuration
- <module>mod_ldap</module> needs to be told where it can find
- a database containing the known CAs. This database is in the same
- format as Netscape Communicator's <code>cert7.db</code>
- database. The easiest way to get this file is to start up a fresh
- copy of Netscape, and grab the resulting
- <code>$HOME/.netscape/cert7.db</code> file.</p>
+ <example>
+ # Establish a TLS LDAP connection on port 389. Requires that <br />
+ # mod_ldap and mod_authnz_ldap be loaded. Change the <br />
+ # "yourdomain.example.com" to match your domain.<br />
+ <br />
+ LDAPTrustedGlobalCert CA_DER /certs/certfile.der<br />
+ <br />
+ <Location /ldap-status><br />
+ <indent>
+ SetHandler ldap-status<br />
+ Order deny,allow<br />
+ Deny from all<br />
+ Allow from yourdomain.example.com<br />
+ AuthLDAPEnabled on<br />
+ LDAPTrustedMode TLS
+ AuthLDAPURL ldap://127.0.0.1/dc=example,dc=com?uid?one<br />
+ AuthLDAPAuthoritative on<br />
+ require valid-user<br />
+ </indent>
+ </Location>
+ </example>
+
+</section>
+
+<section id="settingcerts"><title>SSL/TLS Certificates</title>
+
+ <p>The different LDAP SDKs have widely different methods of setting
+ and handling both CA and client side certificates. Some of the
+ differences are described below:</p>
+
+ <section id="settingcerts-netscape"><title>Netscape/Mozilla/iPlanet SDK</title>
+ <p>CA certificates are specified within a file called cert7.db.
+ The SDK will not talk to any LDAP server whose certificate was
+ not signed by a CA specified in this file. If
+ client certificates are required, an optional key3.db file may
+ be specified with an optional password. The secmod file can be
+ specified if required. These files are in the same format as
+ used by Netscape Communicator / Mozilla web browser. The easiest
+ way to obtain these files is to grab them from a browser
+ installation.</p>
+
+ <p>Client certificates are specified per connection by referring
+ to the certificate "nickname", and an optional password may be
+ specified.</p>
+
+ <p>The SDK supports SSL only. An attempt to use STARTTLS will cause
+ an error when an attempt is made to contact the LDAP server at
+ runtime.</p>
+
+ <example>
+ # Specify a Netscape CA certificate file<br />
+ LDAPTrustedGlobalCert CA_CERT7_DB /certs/cert7.db<br />
+ # Specify an optional key3.db file for client certificate support<br />
+ LDAPTrustedGlobalCert CERT_KEY3_DB /certs/key3.db<br />
+ # Specify the secmod file if required<br />
+ LDAPTrustedGlobalCert CA_SECMOD /certs/secmod<br />
+ <Location /ldap-status><br />
+ <indent>
+ SetHandler ldap-status<br />
+ Order deny,allow<br />
+ Deny from all<br />
+ Allow from yourdomain.example.com<br />
+ AuthLDAPEnabled on<br />
+ LDAPTrustedClientCert CERT_NICKNAME <nickname> [password]<br />
+ AuthLDAPURL ldaps://127.0.0.1/dc=example,dc=com?uid?one<br />
+ AuthLDAPAuthoritative on<br />
+ require valid-user<br />
+ </indent>
+ </Location>
+ </example>
+
+ </section>
+
+ <section id="settingcerts-novell"><title>Novell SDK</title>
+
+ <p>One or more CA certificates must be specified for the Novell
+ SDK to work correctly. These certificates can be specified as
+ binary DER or Base64 (PEM) encoded files.</p>
+
+ <p>Client certificates are specified globally rather than per
+ connection, and so must be specified with the global certificate
+ option as below. Trying to set client certificates via the
+ LDAPTrustedClientCert option will cause an error to be thrown
+ when httpd starts up.</p>
+
+ <p>The SDK supports both SSL and STARTTLS, set using the
+ LDAPTrustedMode parameter. If an ldaps:// URL is specified,
+ SSL mode is forced.</p>
+
+ <example>
+ # Specify two CA certificate files<br />
+ LDAPTrustedGlobalCert CA_DER /certs/cacert1.der<br />
+ LDAPTrustedGlobalCert CA_BASE64 /certs/cacert2.pem<br />
+ # Specify a client certificate file and key<br />
+ LDAPTrustedGlobalCert CERT_BASE64 /certs/cert1.pem<br />
+ LDAPTrustedGlobalCert KEY_BASE64 /certs/key1.pem [password]<br />
+ </example>
+
+ </section>
+
+ <section id="settingcerts-openldap"><title>OpenLDAP SDK</title>
+
+ <p>One or more CA certificates must be specified for the OpenLDAP
+ SDK to work correctly. These certificates can be specified as
+ binary DER or Base64 (PEM) encoded files.</p>
+
+ <p>Client certificates are specified per connection using the
+ LDAPTrustedClientCert directive.</p>
+
+ <p>The documentation for the SDK claims to support both SSL and
+ STARTTLS, however STARTTLS does not seem to work on all versions
+ of the SDK. The SSL/TLS mode can be set using the
+ LDAPTrustedMode parameter. If an ldaps:// URL is specified,
+ SSL mode is forced. The OpenLDAP documentation notes that SSL
+ (ldaps://) support has been deprecated to be replaced with TLS,
+ although the SSL functionality still works.</p>
+
+ <example>
+ # Specify two CA certificate files<br />
+ LDAPTrustedGlobalCert CA_DER /certs/cacert1.der<br />
+ LDAPTrustedGlobalCert CA_BASE64 /certs/cacert2.pem<br />
+ <Location /ldap-status><br />
+ <indent>
+ SetHandler ldap-status<br />
+ Order deny,allow<br />
+ Deny from all<br />
+ Allow from yourdomain.example.com<br />
+ AuthLDAPEnabled on<br />
+ LDAPTrustedClientCert CERT_BASE64 /certs/cert1.pem<br />
+ LDAPTrustedClientCert KEY_BASE64 /certs/key1.pem<br />
+ AuthLDAPURL ldaps://127.0.0.1/dc=example,dc=com?uid?one<br />
+ AuthLDAPAuthoritative on<br />
+ require valid-user<br />
+ </indent>
+ </Location>
+ </example>
+
+ </section>
+
+ <section id="settingcerts-solaris"><title>Solaris SDK</title>
+
+ <p>SSL/TLS for the native Solaris LDAP libraries is not yet
+ supported. If required, install and use the OpenLDAP libraries
+ instead.</p>
+
+ </section>
+
+ <section id="settingcerts-microsoft"><title>Microsoft SDK</title>
+
+ <p>SSL/TLS certificate configuration for the native Microsoft
+ LDAP libraries is done inside the system registry, and no
+ configuration directives are required.</p>
+
+ <p>Both SSL and TLS are supported by using the ldaps:// URL
+ format, or by using the LDAPTrustedMode directive accordingly.</p>
+
+ </section>
</section>
@@ -313,32 +459,83 @@
</directivesynopsis>
<directivesynopsis>
-<name>LDAPTrustedCA</name>
-<description>Sets the file containing the trusted Certificate Authority certificate or database</description>
-<syntax>LDAPTrustedCA <var>directory-path/filename</var></syntax>
+<name>LDAPTrustedGlobalCert</name>
+<description>Sets the file or database containing global trusted
+Certificate Authority or global client certificates</description>
+<syntax>LDAPTrustedGlobalCert <var>type</var> <var>directory-path/filename</var> <var>[password]</var></syntax>
<contextlist><context>server config</context></contextlist>
<usage>
<p>It specifies the directory path and file name of the trusted CA
- <module>mod_ldap</module> should use when establishing an SSL
- connection to an LDAP server. If using the Netscape/iPlanet Directory
- SDK, the file name should be <code>cert7.db</code>.</p>
+ certificates and/or client certificates <module>mod_ldap</module>
+ should use when establishing an SSL or TLS connection to an LDAP
+ server. The type specifies the kind of certificate parameter being
+ set, depending on the LDAP toolkit being used. Supported types are:
+ <ul>
+ <li>CA_DER - binary DER encoded CA certificate</li>
+ <li>CA_BASE64 - PEM encoded CA certificate</li>
+ <li>CA_CERT7_DB - Netscape cert7.db CA certificate database file</li>
+ <li>CA_SECMOD - Netscape secmod database file</li>
+ <li>CERT_DER - binary DER encoded client certificate</li>
+ <li>CERT_BASE64 - PEM encoded client certificate</li>
+ <li>CERT_KEY3_DB - Netscape key3.db client certificate database file</li>
+ <li>CERT_NICKNAME - Client certificate "nickname" (Netscape SDK)</li>
+ <li>KEY_DER - binary DER encoded private key</li>
+ <li>KEY_BASE64 - PEM encoded private key</li>
+ </ul>
+ </p>
</usage>
</directivesynopsis>
<directivesynopsis>
-<name>LDAPTrustedCAType</name>
-<description>Specifies the type of the Certificate Authority file</description>
-<syntax>LDAPTrustedCAType <var>type</var></syntax>
-<contextlist><context>server config</context></contextlist>
+<name>LDAPTrustedClientCert</name>
+<description>Sets the file containing or nickname referring to a per
+connection client certificate. Not all LDAP toolkits support per
+connection client certificates.</description>
+<syntax>LDAPTrustedClientCert <var>type</var> <var>directory-path/filename/nickname</var> <var>[password]</var></syntax>
+<contextlist><context>All</context></contextlist>
<usage>
- <p>The following types are supported:</p>
+ <p>It specifies the directory path, file name or nickname of a
+ per connection client certificate used when establishing an SSL
+ or TLS connection to an LDAP server. Not all LDAP toolkits support
+ per connection client certificates (See the toolkit guide for details).
+ The type specifies the kind of certificate parameter being
+ set, depending on the LDAP toolkit being used. Supported types are:
<ul>
- <li>DER_FILE - file in binary DER format</li>
- <li>BASE64_FILE - file in Base64 format</li>
- <li>CERT7_DB_PATH - Netscape certificate database file</li>
+ <li>CERT_DER - binary DER encoded client certificate</li>
+ <li>CERT_BASE64 - PEM encoded client certificate</li>
+ <li>CERT_NICKNAME - Client certificate "nickname" (Netscape SDK)</li>
+ <li>KEY_DER - binary DER encoded private key</li>
+ <li>KEY_BASE64 - PEM encoded private key</li>
</ul>
+ </p>
+</usage>
+</directivesynopsis>
+
+<directivesynopsis>
+<name>LDAPTrustedMode</name>
+<description>Specifies the SSL/TLS mode to be used when connecting to an LDAP server.</description>
+<syntax>LDAPTrustedMode <var>type</var></syntax>
+<contextlist><context>All</context></contextlist>
+
+<usage>
+ <p>The following modes are supported:</p>
+ <ul>
+ <li>NONE - no encryption</li>
+ <li>SSL - ldaps:// encryption on default port 636</li>
+ <li>TLS - STARTTLS encryption on default port 389</li>
+ </ul>
+ </p>
+
+ <p>Not all LDAP toolkits support all the above modes. An error message
+ will be logged at runtime if a mode is not supported, and the
+ connection to the LDAP server will fail.
+ </p>
+
+ <p>If an ldaps:// URL is specified, the mode becomes SSL and the setting
+ of LDAPTrustedMode is ignored.</p>
+
</usage>
</directivesynopsis>
Modified: httpd/httpd/trunk/include/util_ldap.h
Url: http://svn.apache.org/viewcvs/httpd/httpd/trunk/include/util_ldap.h?view=diff&rev=125645&p1=httpd/httpd/trunk/include/util_ldap.h&r1=125644&p2=httpd/httpd/trunk/include/util_ldap.h&r2=125645
==============================================================================
--- httpd/httpd/trunk/include/util_ldap.h (original)
+++ httpd/httpd/trunk/include/util_ldap.h Wed Jan 19 11:52:08 2005
@@ -90,7 +90,8 @@
const char *binddn; /* DN to bind to server (can be NULL) */
const char *bindpw; /* Password to bind to server (can be NULL) */
- int secure; /* True if use SSL connection */
+ int secure; /* SSL/TLS mode of the connection */
+ apr_array_header_t *client_certs; /* Client certificates on this connection */
const char *reason; /* Reason for an error failure */
@@ -113,9 +114,11 @@
long compare_cache_size; /* Size (in entries) of compare cache */
struct util_ldap_connection_t *connections;
- char *cert_auth_file;
- int cert_file_type;
- int ssl_support;
+ int ssl_supported;
+ apr_array_header_t *global_certs; /* Global CA certificates */
+ apr_array_header_t *client_certs; /* Client certificates */
+ int secure;
+ int secure_set;
#if APR_HAS_SHARED_MEMORY
apr_shm_t *cache_shm;
Modified: httpd/httpd/trunk/modules/ldap/util_ldap.c
Url: http://svn.apache.org/viewcvs/httpd/httpd/trunk/modules/ldap/util_ldap.c?view=diff&rev=125645&p1=httpd/httpd/trunk/modules/ldap/util_ldap.c&r1=125644&p2=httpd/httpd/trunk/modules/ldap/util_ldap.c&r2=125645
==============================================================================
--- httpd/httpd/trunk/modules/ldap/util_ldap.c (original)
+++ httpd/httpd/trunk/modules/ldap/util_ldap.c Wed Jan 19 11:52:08 2005
@@ -239,9 +239,15 @@
LDAP_DECLARE(int) util_ldap_connection_open(request_rec *r,
util_ldap_connection_t *ldc)
{
- int result = 0;
+ int rc = 0;
int failures = 0;
int version = LDAP_VERSION3;
+ apr_ldap_err_t *result = NULL;
+
+ /* sanity check for NULL */
+ if (!ldc) {
+ return -1;
+ }
/* If the connection is already bound, return
*/
@@ -255,16 +261,24 @@
*/
if (NULL == ldc->ldap)
{
- apr_ldap_err_t *result = NULL;
+ /* To work around a bug in the Netware SDK, if no client certs are
+ * present (Netware client certs are global), we apply the SSL
+ * settings immediately. If client certs are present, we defer the
+ * setting of SSL on the connection until later.
+ */
+
+ /* Since the host will include a port if the default port is not used,
+ * always specify the default ports for the port parameter. This will allow
+ * a host string that contains multiple hosts the ability to mix some
+ * hosts with ports and some without. All hosts which do not specify
+ * a port will use the default port.
+ */
+ apr_ldap_init(ldc->pool, &(ldc->ldap),
+ ldc->host,
+ APR_LDAP_SSL == ldc->secure ? LDAPS_PORT : LDAP_PORT,
+ apr_is_empty_array(ldc->client_certs) ? ldc->secure : APR_LDAP_NONE,
+ &(result));
- /* Since the host will include a port if the default port is not used,
- always specify the default ports for the port parameter. This will allow
- a host string that contains multiple hosts the ability to mix some
- hosts with ports and some without. All hosts which do not specify
- a port will use the default port.*/
- apr_ldap_init(r->pool, &(ldc->ldap),
- ldc->host, ldc->secure?LDAPS_PORT:LDAP_PORT,
- ldc->secure, &(result));
if (result != NULL) {
ldc->reason = result->reason;
@@ -273,9 +287,37 @@
if (NULL == ldc->ldap)
{
ldc->bound = 0;
- if (NULL == ldc->reason)
+ if (NULL == ldc->reason) {
ldc->reason = "LDAP: ldap initialization failed";
- return(-1);
+ }
+ else {
+ ldc->reason = result->reason;
+ }
+ return(result->rc);
+ }
+
+ /* set client certificates */
+ if (!apr_is_empty_array(ldc->client_certs)) {
+ apr_ldap_set_option(ldc->pool, ldc->ldap, APR_LDAP_OPT_TLS_CERT,
+ ldc->client_certs, &(result));
+ if (LDAP_SUCCESS != result->rc) {
+ ldap_unbind_s(ldc->ldap);
+ ldc->ldap = NULL;
+ ldc->bound = 0;
+ ldc->reason = result->reason;
+ return(result->rc);
+ }
+ }
+
+ /* switch on SSL/TLS */
+ apr_ldap_set_option(ldc->pool, ldc->ldap,
+ APR_LDAP_OPT_TLS, &ldc->secure, &(result));
+ if (LDAP_SUCCESS != result->rc) {
+ ldap_unbind_s(ldc->ldap);
+ ldc->ldap = NULL;
+ ldc->bound = 0;
+ ldc->reason = result->reason;
+ return(result->rc);
}
/* Set the alias dereferencing option */
@@ -297,16 +339,17 @@
*/
for (failures=0; failures<10; failures++)
{
- result = ldap_simple_bind_s(ldc->ldap,
- (char *)ldc->binddn,
- (char *)ldc->bindpw);
- if (LDAP_SERVER_DOWN != result)
+ rc = ldap_simple_bind_s(ldc->ldap,
+ (char *)ldc->binddn,
+ (char *)ldc->bindpw);
+ if (LDAP_SERVER_DOWN != rc) {
break;
+ }
}
/* free the handle if there was an error
*/
- if (LDAP_SUCCESS != result)
+ if (LDAP_SUCCESS != rc)
{
ldap_unbind_s(ldc->ldap);
ldc->ldap = NULL;
@@ -318,7 +361,44 @@
ldc->reason = "LDAP: connection open successful";
}
- return(result);
+ return(rc);
+}
+
+
+/*
+ * Compare client certificate arrays.
+ *
+ * Returns 1 on compare failure, 0 otherwise.
+ */
+int compare_client_certs(apr_array_header_t *srcs, apr_array_header_t *dests) {
+
+ int i = 0;
+ struct apr_ldap_opt_tls_cert_t *src, *dest;
+
+ /* arrays both NULL? if so, then equal */
+ if (srcs == NULL && dests == NULL) {
+ return 0;
+ }
+
+ /* arrays different length or either NULL? If so, then not equal */
+ if (srcs == NULL || dests == NULL || srcs->nelts != dests->nelts) {
+ return 1;
+ }
+
+ /* run an actual comparison */
+ src = (struct apr_ldap_opt_tls_cert_t *)srcs->elts;
+ dest = (struct apr_ldap_opt_tls_cert_t *)dests->elts;
+ for (i = 0; i < srcs->nelts; i++) {
+ if (apr_strnatcmp(src[i].path, dest[i].path) ||
+ apr_strnatcmp(src[i].password, dest[i].password) ||
+ src[i].type != dest[i].type) {
+ return 1;
+ }
+ }
+
+ /* if we got here, the cert arrays were identical */
+ return 0;
+
}
@@ -330,11 +410,12 @@
* and returned to the caller. If found in the cache, a pointer to the existing
* ldc structure will be returned.
*/
-LDAP_DECLARE(util_ldap_connection_t *)util_ldap_connection_find(request_rec *r, const char *host, int port,
- const char *binddn, const char *bindpw, deref_options deref,
- int secure )
-{
- struct util_ldap_connection_t *l, *p; /* To traverse the linked list */
+LDAP_DECLARE(util_ldap_connection_t *)
+ util_ldap_connection_find(request_rec *r,
+ const char *host, int port,
+ const char *binddn, const char *bindpw,
+ deref_options deref, int secure) {
+ struct util_ldap_connection_t *l, *p; /* To traverse the linked list */
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(r->server->module_config,
@@ -359,7 +440,8 @@
if ((l->port == port) && (strcmp(l->host, host) == 0) &&
((!l->binddn && !binddn) || (l->binddn && binddn && !strcmp(l->binddn, binddn))) &&
((!l->bindpw && !bindpw) || (l->bindpw && bindpw && !strcmp(l->bindpw, bindpw))) &&
- (l->deref == deref) && (l->secure == secure)) {
+ (l->deref == deref) && (l->secure == secure) &&
+ !compare_client_certs(st->client_certs, l->client_certs)) {
break;
}
@@ -383,7 +465,8 @@
#endif
if ((l->port == port) && (strcmp(l->host, host) == 0) &&
- (l->deref == deref) && (l->secure == secure)) {
+ (l->deref == deref) && (l->secure == secure) &&
+ !compare_client_certs(st->client_certs, l->client_certs)) {
/* the bind credentials have changed */
l->bound = 0;
@@ -428,7 +511,18 @@
l->deref = deref;
util_ldap_strdup((char**)&(l->binddn), binddn);
util_ldap_strdup((char**)&(l->bindpw), bindpw);
- l->secure = secure;
+
+ /* The security mode after parsing the URL will always be either
+ * APR_LDAP_NONE (ldap://) or APR_LDAP_SSL (ldaps://).
+ * If the security setting is NONE, override it to the security
+ * setting optionally supplied by the admin using LDAPTrustedMode
+ */
+ l->secure = (APR_LDAP_NONE == secure) ?
+ st->secure :
+ secure;
+
+ /* save away a copy of the client cert list that is presently valid */
+ l->client_certs = apr_array_copy_hdr(l->pool, st->client_certs);
/* add the cleanup to the pool */
apr_pool_cleanup_register(l->pool, l,
@@ -1131,7 +1225,7 @@
util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(
r->server->module_config, &ldap_module);
- return(st->ssl_support);
+ return(st->ssl_supported);
}
@@ -1242,64 +1336,252 @@
return NULL;
}
-static const char *util_ldap_set_cert_auth(cmd_parms *cmd, void *dummy, const char *file)
+
+/**
+ * Parse the certificate type.
+ *
+ * The type can be one of the following:
+ * CA_DER, CA_BASE64, CA_CERT7_DB, CA_SECMOD, CERT_DER, CERT_BASE64,
+ * CERT_KEY3_DB, CERT_NICKNAME, KEY_DER, KEY_BASE64
+ *
+ * If no matches are found, APR_LDAP_CA_TYPE_UNKNOWN is returned.
+ */
+static const int util_ldap_parse_cert_type(const char *type) {
+
+ /* Authority file in binary DER format */
+ if (0 == strcasecmp("CA_DER", type)) {
+ return APR_LDAP_CA_TYPE_DER;
+ }
+
+ /* Authority file in Base64 format */
+ else if (0 == strcasecmp("CA_BASE64", type)) {
+ return APR_LDAP_CA_TYPE_BASE64;
+ }
+
+ /* Netscape certificate database file/directory */
+ else if (0 == strcasecmp("CA_CERT7_DB", type)) {
+ return APR_LDAP_CA_TYPE_CERT7_DB;
+ }
+
+ /* Netscape secmod file/directory */
+ else if (0 == strcasecmp("CA_SECMOD", type)) {
+ return APR_LDAP_CA_TYPE_SECMOD;
+ }
+
+ /* Client cert file in DER format */
+ else if (0 == strcasecmp("CERT_DER", type)) {
+ return APR_LDAP_CERT_TYPE_DER;
+ }
+
+ /* Client cert file in Base64 format */
+ else if (0 == strcasecmp("CERT_BASE64", type)) {
+ return APR_LDAP_CERT_TYPE_BASE64;
+ }
+
+ /* Netscape client cert database file/directory */
+ else if (0 == strcasecmp("CERT_KEY3_DB", type)) {
+ return APR_LDAP_CERT_TYPE_KEY3_DB;
+ }
+
+ /* Netscape client cert nickname */
+ else if (0 == strcasecmp("CERT_NICKNAME", type)) {
+ return APR_LDAP_CERT_TYPE_NICKNAME;
+ }
+
+ /* Client cert key file in DER format */
+ else if (0 == strcasecmp("KEY_DER", type)) {
+ return APR_LDAP_KEY_TYPE_DER;
+ }
+
+ /* Client cert key file in Base64 format */
+ else if (0 == strcasecmp("KEY_BASE64", type)) {
+ return APR_LDAP_KEY_TYPE_BASE64;
+ }
+
+ else {
+ return APR_LDAP_CA_TYPE_UNKNOWN;
+ }
+
+}
+
+
+/**
+ * Set LDAPTrustedGlobalCert.
+ *
+ * This directive takes either two or three arguments:
+ * - certificate type
+ * - certificate file / directory / nickname
+ * - certificate password (optional)
+ *
+ * This directive may only be used globally.
+ */
+static const char *util_ldap_set_trusted_global_cert(cmd_parms *cmd, void *dummy, const char *type, const char *file, const char *password)
{
- util_ldap_state_t *st =
- (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
- &ldap_module);
+ util_ldap_state_t *st =
+ (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
+ &ldap_module);
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
apr_finfo_t finfo;
apr_status_t rv;
+ int cert_type = 0;
if (err != NULL) {
return err;
}
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
- "LDAP: SSL trusted certificate authority file - %s",
- file);
+ /* handle the certificate type */
+ if (type) {
+ cert_type = util_ldap_parse_cert_type(type);
+ if (APR_LDAP_CA_TYPE_UNKNOWN == cert_type) {
+ return apr_psprintf(cmd->pool, "The certificate type %s is "
+ "not recognised. It should be one "
+ "of CA_DER, CA_BASE64, CA_CERT7_DB, "
+ "CA_SECMOD, CERT_DER, CERT_BASE64, "
+ "CERT_KEY3_DB, CERT_NICKNAME, "
+ "KEY_DER, KEY_BASE64", type);
+ }
+ }
+ else {
+ return "Certificate type was not specified.";
+ }
- st->cert_auth_file = ap_server_root_relative(cmd->pool, file);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
+ "LDAP: SSL trusted global cert - %s (type %s)",
+ file, type);
+
+ /* add the certificate to the global array */
+ apr_ldap_opt_tls_cert_t *cert = (apr_ldap_opt_tls_cert_t *)apr_array_push(st->global_certs);
+ cert->type = cert_type;
+ cert->path = file;
+ cert->password = password;
+
+ /* if file is a file or path, fix the path */
+ if (cert_type != APR_LDAP_CA_TYPE_UNKNOWN &&
+ cert_type != APR_LDAP_CERT_TYPE_NICKNAME) {
+
+ cert->path = ap_server_root_relative(cmd->pool, file);
+ if (cert->path &&
+ ((rv = apr_stat (&finfo, cert->path, APR_FINFO_MIN, cmd->pool)) != APR_SUCCESS)) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, cmd->server,
+ "LDAP: Could not open SSL trusted certificate "
+ "authority file - %s",
+ cert->path == NULL ? file : cert->path);
+ return "Invalid global certificate file path";
+ }
- if (st->cert_auth_file &&
- ((rv = apr_stat (&finfo, st->cert_auth_file, APR_FINFO_MIN, cmd->pool)) != APR_SUCCESS))
- {
- ap_log_error(APLOG_MARK, APLOG_ERR, rv, cmd->server,
- "LDAP: Could not open SSL trusted certificate authority file - %s",
- st->cert_auth_file == NULL ? file : st->cert_auth_file);
- return "Invalid file path";
}
return(NULL);
}
-static const char *util_ldap_set_cert_type(cmd_parms *cmd, void *dummy, const char *Type)
+/**
+ * Set LDAPTrustedClientCert.
+ *
+ * This directive takes either two or three arguments:
+ * - certificate type
+ * - certificate file / directory / nickname
+ * - certificate password (optional)
+ */
+static const char *util_ldap_set_trusted_client_cert(cmd_parms *cmd, void *config, const char *type, const char *file, const char *password)
{
- util_ldap_state_t *st =
- (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
- &ldap_module);
- const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
- if (err != NULL) {
- return err;
+ util_ldap_state_t *st =
+ (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
+ &ldap_module);
+ apr_finfo_t finfo;
+ apr_status_t rv;
+ int cert_type = 0;
+
+ /* handle the certificate type */
+ if (type) {
+ cert_type = util_ldap_parse_cert_type(type);
+ if (APR_LDAP_CA_TYPE_UNKNOWN == cert_type) {
+ return apr_psprintf(cmd->pool, "The certificate type \"%s\" is "
+ "not recognised. It should be one "
+ "of CERT_DER, CERT_BASE64, "
+ "CERT_NICKNAME, "
+ "KEY_DER, KEY_BASE64", type);
+ }
+ else if (APR_LDAP_CA_TYPE_DER == cert_type ||
+ APR_LDAP_CA_TYPE_BASE64 == cert_type ||
+ APR_LDAP_CA_TYPE_CERT7_DB == cert_type ||
+ APR_LDAP_CA_TYPE_SECMOD == cert_type ||
+ APR_LDAP_CERT_TYPE_KEY3_DB == cert_type) {
+ return apr_psprintf(cmd->pool, "The certificate type \"%s\" is "
+ "only valid within a "
+ "LDAPTrustedGlobalCert directive. "
+ "Only CERT_DER, CERT_BASE64, "
+ "CERT_NICKNAME, KEY_DER, and "
+ "KEY_BASE64 may be used.", type);
+ }
+ }
+ else {
+ return "Certificate type was not specified.";
}
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
- "LDAP: SSL trusted certificate authority file type - %s",
- Type);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
+ "LDAP: SSL trusted client cert - %s (type %s)",
+ file, type);
+
+ /* add the certificate to the global array */
+ apr_ldap_opt_tls_cert_t *cert = (apr_ldap_opt_tls_cert_t *)apr_array_push(st->global_certs);
+ cert->type = cert_type;
+ cert->path = file;
+ cert->password = password;
+
+ /* if file is a file or path, fix the path */
+ if (cert_type != APR_LDAP_CA_TYPE_UNKNOWN &&
+ cert_type != APR_LDAP_CERT_TYPE_NICKNAME) {
+
+ cert->path = ap_server_root_relative(cmd->pool, file);
+ if (cert->path &&
+ ((rv = apr_stat (&finfo, cert->path, APR_FINFO_MIN, cmd->pool)) != APR_SUCCESS)) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, cmd->server,
+ "LDAP: Could not open SSL client certificate "
+ "file - %s",
+ cert->path == NULL ? file : cert->path);
+ return "Invalid client certificate file path";
+ }
+
+ }
- if (0 == strcmp("DER_FILE", Type))
- st->cert_file_type = LDAP_CA_TYPE_DER;
+ return(NULL);
+}
- else if (0 == strcmp("BASE64_FILE", Type))
- st->cert_file_type = LDAP_CA_TYPE_BASE64;
- else if (0 == strcmp("CERT7_DB_PATH", Type))
- st->cert_file_type = LDAP_CA_TYPE_CERT7_DB;
+/**
+ * Set LDAPTrustedMode.
+ *
+ * This directive sets what encryption mode to use on a connection:
+ * - None (No encryption)
+ * - SSL (SSL encryption)
+ * - STARTTLS (TLS encryption)
+ */
+static const char *util_ldap_set_trusted_mode(cmd_parms *cmd, void *dummy, const char *mode)
+{
+ util_ldap_state_t *st =
+ (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
+ &ldap_module);
- else
- st->cert_file_type = LDAP_CA_TYPE_UNKNOWN;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
+ "LDAP: SSL trusted mode - %s",
+ mode);
+ if (0 == strcasecmp("NONE", mode)) {
+ st->secure = APR_LDAP_NONE;
+ }
+ else if (0 == strcasecmp("SSL", mode)) {
+ st->secure = APR_LDAP_SSL;
+ }
+ else if (0 == strcasecmp("TLS", mode) || 0 == strcasecmp("STARTTLS", mode)) {
+ st->secure = APR_LDAP_STARTTLS;
+ }
+ else {
+ return "Invalid LDAPTrustedMode setting: must be one of NONE, "
+ "SSL, or TLS/STARTTLS";
+ }
+
+ st->secure_set = 1;
return(NULL);
}
@@ -1317,9 +1599,33 @@
st->compare_cache_ttl = 600000000;
st->compare_cache_size = 1024;
st->connections = NULL;
- st->cert_auth_file = NULL;
- st->cert_file_type = LDAP_CA_TYPE_UNKNOWN;
- st->ssl_support = 0;
+ st->ssl_supported = 0;
+ st->global_certs = apr_array_make(p, 10, sizeof(apr_ldap_opt_tls_cert_t));
+ st->client_certs = apr_array_make(p, 10, sizeof(apr_ldap_opt_tls_cert_t));
+ st->secure = APR_LDAP_NONE;
+ st->secure_set = 0;
+
+ return st;
+}
+
+static void *util_ldap_merge_config(apr_pool_t *p, void *basev, void *overridesv)
+{
+ util_ldap_state_t *st = apr_pcalloc(p, sizeof(util_ldap_state_t));
+ util_ldap_state_t *base = (util_ldap_state_t *) basev;
+ util_ldap_state_t *overrides = (util_ldap_state_t *) overridesv;
+
+ st->pool = p;
+
+ st->cache_bytes = base->cache_bytes;
+ st->search_cache_ttl = base->search_cache_ttl;
+ st->search_cache_size = base->search_cache_size;
+ st->compare_cache_ttl = base->compare_cache_ttl;
+ st->compare_cache_size = base->compare_cache_size;
+ st->connections = base->connections;
+ st->ssl_supported = base->ssl_supported;
+ st->global_certs = apr_array_append(p, base->global_certs, overrides->global_certs);
+ st->client_certs = apr_array_append(p, base->client_certs, overrides->client_certs);
+ st->secure = (overrides->secure_set == 0) ? base->secure : overrides->secure;
return st;
}
@@ -1331,7 +1637,7 @@
util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(
s->module_config, &ldap_module);
- if (st->ssl_support) {
+ if (st->ssl_supported) {
apr_ldap_ssl_deinit();
}
@@ -1443,36 +1749,33 @@
apr_pool_cleanup_register(p, s, util_ldap_cleanup_module,
util_ldap_cleanup_module);
- /* initialize SSL support if requested
- */
- if (st->cert_auth_file) {
-
- apr_ldap_err_t *result = NULL;
- int rc = apr_ldap_ssl_init(p,
- st->cert_auth_file,
- st->cert_file_type,
- &(result));
-
- if (LDAP_SUCCESS == rc) {
- st->ssl_support = 1;
- }
- else if (NULL != result) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "%s", result->reason);
- st->ssl_support = 0;
- }
-
- }
-
- /* 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
+ /*
+ * Initialize SSL support, and log the result for the benefit of the admin.
+ *
+ * If SSL is not supported it is not necessarily an error, as the
+ * application may not want to use it.
*/
- if (st->ssl_support) {
- ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
+ apr_ldap_err_t *result_err = NULL;
+ int rc = apr_ldap_ssl_init(p,
+ NULL,
+ NULL,
+ &(result_err));
+ if (APR_SUCCESS == rc) {
+ rc = apr_ldap_set_option(p, NULL, APR_LDAP_OPT_TLS_CERT,
+ (void *)st->global_certs, &(result_err));
+ }
+
+ if (APR_SUCCESS == rc) {
+ st->ssl_supported = 1;
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
"LDAP: SSL support available" );
}
else {
- ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
+ st->ssl_supported = 0;
+ if (NULL != result_err) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "%s", result_err->reason);
+ }
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
"LDAP: SSL support unavailable" );
}
@@ -1531,16 +1834,45 @@
"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)."),
- AP_INIT_TAKE1("LDAPTrustedCA", util_ldap_set_cert_auth, NULL, RSRC_CONF,
- "Sets the file containing the trusted Certificate Authority certificate. "
- "Used to validate the LDAP server certificate for SSL connections."),
-
- AP_INIT_TAKE1("LDAPTrustedCAType", util_ldap_set_cert_type, NULL, RSRC_CONF,
- "Specifies the type of the Certificate Authority file. "
+ AP_INIT_TAKE23("LDAPTrustedGlobalCert", util_ldap_set_trusted_global_cert, NULL, RSRC_CONF,
+ "Sets the file and/or directory containing the trusted "
+ "certificate authority certificates, and global client "
+ "certificates (Netware). Used to validate the LDAP server "
+ "certificate for SSL/TLS connections. "
+ "The following types are supported: "
+ " CA_DER - Authority file in binary DER format "
+ " CA_BASE64 - Authority file in Base64 format "
+ " CA_CERT7_DB - Netscape certificate database file/directory "
+ " CA_SECMOD - Netscape secmod file/directory "
+ " CERT_DER - Client cert file in DER format "
+ " CERT_BASE64 - Client cert file in Base64 format "
+ " CERT_KEY3_DB - Netscape client cert database file/directory "
+ " CERT_NICKNAME - Netscape client cert nickname "
+ " KEY_DER - Client cert key file in DER format "
+ " KEY_BASE64 - Client cert key file in Base64 format "),
+
+ AP_INIT_TAKE23("LDAPTrustedClientCert", util_ldap_set_trusted_client_cert, NULL, OR_ALL,
+ "Specifies a file containing a client certificate or private "
+ "key, or the ID of the certificate to usethe 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 "),
+ " CA_DER - Authority file in binary DER format "
+ " CA_BASE64 - Authority file in Base64 format "
+ " CA_CERT7_DB - Netscape certificate database file/directory "
+ " CA_SECMOD - Netscape secmod file/directory "
+ " CERT_DER - Client cert file in DER format "
+ " CERT_BASE64 - Client cert file in Base64 format "
+ " CERT_KEY3_DB - Netscape client cert database file/directory "
+ " CERT_NICKNAME - Netscape client cert nickname "
+ " KEY_DER - Client cert key file in DER format "
+ " KEY_BASE64 - Client cert key file in Base64 format "),
+
+ AP_INIT_TAKE1("LDAPTrustedMode", util_ldap_set_trusted_mode, NULL, OR_ALL,
+ "Specifies the type of security that should be applied to "
+ "an LDAP connection. The types supported are: "
+ " NONE - no encryption enabled "
+ " SSL - SSL encryption enabled (forced by ldaps://) "
+ " STARTTLS - STARTTLS MUST be enabled "),
+
{NULL}
};
@@ -1556,7 +1888,7 @@
NULL, /* dir config creater */
NULL, /* dir merger --- default is to override */
util_ldap_create_config, /* server config */
- NULL, /* merge server config */
+ util_ldap_merge_config, /* merge server config */
util_ldap_cmds, /* command table */
util_ldap_register_hooks, /* set up request processing hooks */
};