[openldap] various TLS bugfixes

jvcelak jvcelak at fedoraproject.org
Thu Nov 18 10:58:32 UTC 2010


commit ce2de9613d73a54d2359a91dcb02368075ef48a7
Author: Jan Vcelak <jvcelak at redhat.com>
Date:   Thu Nov 18 10:37:16 2010 +0100

    various TLS bugfixes
    
    - reject non-file keyfiles in TLS_CACERTDIR (#652315)
    - TLS_CACERTDIR precedence over TLS_CACERT (#652304)
    - accept only files in hash.0 format in TLS_CACERTDIR (#650288)
    - improve SSL/TLS trace messages (#652818)
    - add support for multiple prefixed Mozilla NSS database files in TLS_CACERTDIR
    
    Resolves: #652315 #652304 #650288 #652818

 openldap-cacertdir-hash-only.patch      |   60 +++++++
 openldap-improve-trace-messages.patch   |  176 +++++++++++++++++++
 openldap-nss-db-prefix.patch            |  286 +++++++++++++++++++++++++++++++
 openldap-reject-non-file-keyfiles.patch |   84 +++++++++
 openldap-use-cacert-dir-and-file.patch  |  136 +++++++++++++++
 openldap.spec                           |   19 ++-
 6 files changed, 760 insertions(+), 1 deletions(-)
---
diff --git a/openldap-cacertdir-hash-only.patch b/openldap-cacertdir-hash-only.patch
new file mode 100644
index 0000000..70060a9
--- /dev/null
+++ b/openldap-cacertdir-hash-only.patch
@@ -0,0 +1,60 @@
+Openldap should ignore files not in the openssl c_rehash format (hash.0) in TLS_CACERTDIR
+
+Resolves: #650288
+Upstream ITS: #6705
+Author: Rich Megginson (rmeggins at redhat.com)
+
+--- openldap.old/libraries/libldap/tls_m.c.2	2010-11-11 15:21:05.000000000 -0700
++++ openldap.new/libraries/libldap/tls_m.c	2010-11-11 15:29:08.000000000 -0700
+@@ -100,16 +100,19 @@
+ typedef PRFileDesc tlsm_session;
+ 
+ static PRDescIdentity	tlsm_layer_id;
+ 
+ static const PRIOMethods tlsm_PR_methods;
+ 
+ #define PEM_LIBRARY	"nsspem"
+ #define PEM_MODULE	"PEM"
++/* hash files for use with cacertdir have this file name suffix */
++#define PEM_CA_HASH_FILE_SUFFIX	".0"
++#define PEM_CA_HASH_FILE_SUFFIX_LEN 2
+ 
+ static SECMODModule *pem_module;
+ 
+ #define DEFAULT_TOKEN_NAME "default"
+ /* sprintf format used to create token name */
+ #define TLSM_PEM_TOKEN_FMT "PEM Token #%ld"
+ 
+ static int tlsm_slot_count;
+@@ -1230,18 +1233,29 @@
+ 				   "TLS: could not open the CA certificate directory %s - error %d:%s.\n",
+ 				   cacertdir, errcode,
+ 				   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+ 			goto done;
+ 		}
+ 
+ 		do {
+ 			entry = PR_ReadDir( dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN );
+-			if ( NULL != entry ) {
+-				char *fullpath = PR_smprintf( "%s/%s", cacertdir, entry->name );
++			if ( ( NULL != entry ) && ( NULL != entry->name ) ) {
++				char *fullpath = NULL;
++				char *ptr;
++
++				ptr = PL_strrstr( entry->name, PEM_CA_HASH_FILE_SUFFIX );
++				if ( ( ptr == NULL ) || ( *(ptr + PEM_CA_HASH_FILE_SUFFIX_LEN) != '\0' ) ) {
++					Debug( LDAP_DEBUG_TRACE,
++						   "TLS: file %s does not end in [%s] - does not appear to be a CA certificate "
++						   "directory file with a properly hashed file name - skipping.\n",
++						   entry->name, PEM_CA_HASH_FILE_SUFFIX, 0 );
++					continue;
++				}
++				fullpath = PR_smprintf( "%s/%s", cacertdir, entry->name );
+ 				if ( !tlsm_add_cert_from_file( ctx, fullpath, isca ) ) {
+ 					Debug( LDAP_DEBUG_TRACE,
+ 						   "TLS: loaded CA certificate file %s from CA certificate directory %s.\n",
+ 						   fullpath, cacertdir, 0 );
+ 					status = PR_SUCCESS; /* found at least 1 valid CA file in the dir */
+ 				} else {
+ 					errcode = PR_GetError();
+ 					Debug( LDAP_DEBUG_TRACE,
diff --git a/openldap-improve-trace-messages.patch b/openldap-improve-trace-messages.patch
new file mode 100644
index 0000000..314bb36
--- /dev/null
+++ b/openldap-improve-trace-messages.patch
@@ -0,0 +1,176 @@
+Improve misleading SSL/TLS trace messages.
+
+Resolves: #652818
+Upstream ITS: #6706
+Author: Rich Megginson (rmeggins at redhat.com)
+
+--- openldap.old/libraries/libldap/tls_m.c.3	2010-11-11 18:39:48.000000000 -0700
++++ openldap.new/libraries/libldap/tls_m.c	2010-11-11 20:17:35.000000000 -0700
+@@ -709,16 +709,22 @@
+ 	Debug( LDAP_DEBUG_TRACE,
+ 		   "cache hits: %ld, cache misses: %ld, cache not reusable: %ld\n",
+ 		   ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses,
+ 		   ssl3stats->hch_sid_cache_not_ok );
+ 
+ 	return "";
+ }
+ 
++static void
++tlsm_handshake_complete_cb( PRFileDesc *fd, void *client_data )
++{
++	tlsm_dump_security_status( fd );
++}
++
+ #ifdef READ_PASSWORD_FROM_FILE
+ static char *
+ tlsm_get_pin_from_file(const char *token_name, tlsm_ctx *ctx)
+ {
+ 	char *pwdstr = NULL;
+ 	char *contents = NULL;
+ 	char *lasts = NULL;
+ 	char *line = NULL;
+@@ -894,26 +900,32 @@
+ }
+ 
+ static SECStatus
+ tlsm_auth_cert_handler(void *arg, PRFileDesc *fd,
+                        PRBool checksig, PRBool isServer)
+ {
+ 	SECStatus ret = SSL_AuthCertificate(arg, fd, checksig, isServer);
+ 
+-	tlsm_dump_security_status( fd );
+-	Debug( LDAP_DEBUG_TRACE,
+-		   "TLS certificate verification: %s\n",
+-		   ret == SECSuccess ? "ok" : "bad", 0, 0 );
+-
+ 	if ( ret != SECSuccess ) {
+ 		PRErrorCode errcode = PORT_GetError();
+-		Debug( LDAP_DEBUG_ANY,
+-			   "TLS certificate verification: Error, %d: %s\n",
+-			   errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 ) ;
++		/* we bypass NSS's hostname checks and do our own - tlsm_session_chkhost will handle it */
++		if ( errcode == SSL_ERROR_BAD_CERT_DOMAIN ) {
++			Debug( LDAP_DEBUG_TRACE,
++				   "TLS certificate verification: defer\n",
++				   0, 0, 0 );
++		} else {
++			Debug( LDAP_DEBUG_ANY,
++				   "TLS certificate verification: Error, %d: %s\n",
++				   errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 ) ;
++		}
++	} else {
++		Debug( LDAP_DEBUG_TRACE,
++			   "TLS certificate verification: ok\n",
++			   0, 0, 0 );
+ 	}
+ 
+ 	return ret;
+ }
+ 
+ static int
+ tlsm_authenticate_to_slot( tlsm_ctx *ctx, PK11SlotInfo *slot )
+ {
+@@ -1181,16 +1193,21 @@
+ 
+ static int
+ tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir )
+ {
+ 	PRBool isca = PR_TRUE;
+ 	PRStatus status = PR_FAILURE;
+ 	PRErrorCode errcode = PR_SUCCESS;
+ 
++	if ( !cacertfile && !cacertdir ) {
++		/* no checking - not good, but allowed */
++		return 0;
++	}
++
+ 	if ( cacertfile ) {
+ 		int rc = tlsm_add_cert_from_file( ctx, cacertfile, isca );
+ 		if ( rc ) {
+ 			errcode = PR_GetError();
+ 			Debug( LDAP_DEBUG_ANY,
+ 				   "TLS: %s is not a valid CA certificate file - error %d:%s.\n",
+ 				   cacertfile, errcode,
+ 				   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+@@ -1394,19 +1411,21 @@
+ 			rc = (initctx == NULL) ? SECFailure : SECSuccess;
+ #endif
+ #else
+ 			rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY );
+ #endif
+ 
+ 			if ( rc != SECSuccess ) {
+ 				errcode = PORT_GetError();
+-				Debug( LDAP_DEBUG_TRACE,
+-					   "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
+-					   realcertdir, prefix, errcode );
++				if ( securitydirs[ii] != lt->lt_cacertdir) {
++					Debug( LDAP_DEBUG_TRACE,
++						   "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
++						   realcertdir, prefix, errcode );
++				}
+ 			} else {
+ 				/* success */
+ 				Debug( LDAP_DEBUG_TRACE, "TLS: using moznss security dir %s prefix %s.\n",
+ 					   realcertdir, prefix, 0 );
+ 				errcode = 0;
+ 				done = 1;
+ 			}
+ 			if ( realcertdir != securitydir ) {
+@@ -1453,16 +1472,31 @@
+ 				errcode = PORT_GetError();
+ 				Debug( LDAP_DEBUG_ANY,
+ 					   "TLS: could not initialize moznss PEM module - error %d:%s.\n",
+ 					   errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
+ 				return -1;
+ 			}
+ 
+ 			if ( tlsm_init_ca_certs( ctx, lt->lt_cacertfile, lt->lt_cacertdir ) ) {
++				/* if we tried to use lt->lt_cacertdir as an NSS key/cert db, errcode 
++				   will be a value other than 1 - print an error message so that the
++				   user will know that failed too */
++				if ( ( errcode != 1 ) && ( lt->lt_cacertdir ) ) {
++					char *realcertdir = NULL;
++					char *prefix = NULL;
++					tlsm_get_certdb_prefix( lt->lt_cacertdir, &realcertdir, &prefix );
++					Debug( LDAP_DEBUG_TRACE,
++						   "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
++						   realcertdir, prefix ? prefix : "", errcode );
++					if ( realcertdir != lt->lt_cacertdir ) {
++						PL_strfree( realcertdir );
++					}
++					PL_strfree( prefix );
++				}
+ 				return -1;
+ 			}
+ 
+ 			ctx->tc_using_pem = PR_TRUE;
+ 		}
+ 
+ #ifdef HAVE_NSS_INITCONTEXT
+ 		if ( !ctx->tc_initctx ) {
+@@ -2040,16 +2074,24 @@
+                                   ctx->tc_certdb ) != SECSuccess ) {
+ 		PRErrorCode err = PR_GetError();
+ 		Debug( LDAP_DEBUG_ANY, 
+ 		       "TLS: error: could not set auth cert handler for moznss - error %d:%s\n",
+ 		       err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
+ 		return -1;
+ 	}
+ 
++	if ( SSL_HandshakeCallback( ctx->tc_model, tlsm_handshake_complete_cb, ctx ) ) {
++		PRErrorCode err = PR_GetError();
++		Debug( LDAP_DEBUG_ANY, 
++		       "TLS: error: could not set handshake callback for moznss - error %d:%s\n",
++		       err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
++		return -1;
++	}
++
+ 	return 0;
+ }
+ 
+ struct tls_data {
+ 	tlsm_session		*session;
+ 	Sockbuf_IO_Desc		*sbiod;
+ 	/* there seems to be no portable way to determine if the
+ 	   sockbuf sd has been set to nonblocking mode - the
diff --git a/openldap-nss-db-prefix.patch b/openldap-nss-db-prefix.patch
new file mode 100644
index 0000000..cb0b846
--- /dev/null
+++ b/openldap-nss-db-prefix.patch
@@ -0,0 +1,286 @@
+Enhancement, support multiple cert/key databases in tha same directory with another prefix.
+
+Upstream ITS: #6689
+
+--- openldap.old/libraries/libldap/tls_m.c	21 Jul 2010 20:57:01 -0000	1.18
++++ openldap.new/libraries/libldap/tls_m.c	28 Oct 2010 19:55:51 -0000
+@@ -1202,16 +1202,55 @@
+ 			return -1;
+ 		}
+ 	}
+ 
+ 	return 0;
+ }
+ 
+ /*
++ * NSS supports having multiple cert/key databases in the same
++ * directory, each one having a unique string prefix e.g.
++ * slapd-01-cert8.db - the prefix here is "slapd-01-"
++ * this function examines the given certdir - if it looks like
++ * /path/to/directory/prefix it will return the
++ * /path/to/directory part in realcertdir, and the prefix in prefix
++ */
++static void
++tlsm_get_certdb_prefix( const char *certdir, char **realcertdir, char **prefix )
++{
++	char sep = PR_GetDirectorySeparator();
++	char *ptr = NULL;
++	struct PRFileInfo prfi;
++	PRStatus prc;
++
++	*realcertdir = (char *)certdir; /* default is the one passed in */
++
++	/* if certdir is not given, just return */
++	if ( !certdir ) {
++		return;
++	}
++
++	prc = PR_GetFileInfo( certdir, &prfi );
++	/* if certdir exists (file or directory) then it cannot specify a prefix */
++	if ( prc == PR_SUCCESS ) {
++		return;
++	}
++
++	/* if certdir was given, and there is a '/' in certdir, see if there
++	   is anything after the last '/' - if so, assume it is the prefix */
++	if ( ( ( ptr = strrchr( certdir, sep ) ) ) && *(ptr+1) ) {
++		*realcertdir = PL_strndup( certdir, ptr-certdir );
++		*prefix = PL_strdup( ptr+1 );
++	}
++
++	return;
++}
++
++/*
+  * This is the part of the init we defer until we get the
+  * actual security configuration information.  This is
+  * only called once, protected by a PRCallOnce
+  * NOTE: This must be done before the first call to SSL_ImportFD,
+  * especially the setting of the policy
+  * NOTE: This must be called after fork()
+  */
+ static int
+@@ -1223,16 +1262,17 @@
+ 	int ii;
+ 	int nn;
+ 	PRErrorCode errcode = 1;
+ #ifdef HAVE_NSS_INITCONTEXT
+ 	NSSInitParameters initParams;
+ 	NSSInitContext *initctx = NULL;
+ #endif
+ 	SECStatus rc;
++	int done = 0;
+ 
+ #ifdef HAVE_NSS_INITCONTEXT
+ 	memset( &initParams, 0, sizeof( initParams ) );
+ 	initParams.length = sizeof( initParams );
+ #endif /* HAVE_NSS_INITCONTEXT */
+ 
+ #ifndef HAVE_NSS_INITCONTEXT
+ 	if ( !NSS_IsInitialized() ) {
+@@ -1246,50 +1286,61 @@
+ 		  DEFAULT_MOZNSS_DIR will only be used if the code cannot
+ 		  find a security dir to use based on the current
+ 		  settings
+ 		*/
+ 		nn = 0;
+ 		securitydirs[nn++] = PR_GetEnv( "MOZNSS_DIR" );
+ 		securitydirs[nn++] = lt->lt_cacertdir;
+ 		securitydirs[nn++] = PR_GetEnv( "DEFAULT_MOZNSS_DIR" );
+-		for ( ii = 0; ii < nn; ++ii ) {
++		for ( ii = 0; !done && ( ii < nn ); ++ii ) {
++			char *realcertdir = NULL;
++			const char *defprefix = "";
++			char *prefix = (char *)defprefix;
+ 			const char *securitydir = securitydirs[ii];
+ 			if ( NULL == securitydir ) {
+ 				continue;
+ 			}
++
++			tlsm_get_certdb_prefix( securitydir, &realcertdir, &prefix );
+ #ifdef HAVE_NSS_INITCONTEXT
+ #ifdef INITCONTEXT_HACK
+ 			if ( !NSS_IsInitialized() && ctx->tc_is_server ) {
+-				rc = NSS_Initialize( securitydir, "", "", SECMOD_DB, NSS_INIT_READONLY );
++				rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY );
+ 			} else {
+-				initctx = NSS_InitContext( securitydir, "", "", SECMOD_DB,
++				initctx = NSS_InitContext( realcertdir, prefix, prefix, SECMOD_DB,
+ 										   &initParams, NSS_INIT_READONLY );
+ 				rc = (initctx == NULL) ? SECFailure : SECSuccess;
+ 			}
+ #else
+-			initctx = NSS_InitContext( securitydir, "", "", SECMOD_DB,
++			initctx = NSS_InitContext( realcertdir, prefix, prefix, SECMOD_DB,
+ 									   &initParams, NSS_INIT_READONLY );
+ 			rc = (initctx == NULL) ? SECFailure : SECSuccess;
+ #endif
+ #else
+-			rc = NSS_Initialize( securitydir, "", "", SECMOD_DB, NSS_INIT_READONLY );
++			rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY );
+ #endif
+ 
+ 			if ( rc != SECSuccess ) {
+ 				errcode = PORT_GetError();
+ 				Debug( LDAP_DEBUG_TRACE,
+-					   "TLS: could not initialize moznss using security dir %s - error %d:%s.\n",
+-					   securitydir, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
++					   "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
++					   realcertdir, prefix, errcode );
+ 			} else {
+ 				/* success */
+-				Debug( LDAP_DEBUG_TRACE, "TLS: using moznss security dir %s.\n",
+-					   securitydir, 0, 0 );
++				Debug( LDAP_DEBUG_TRACE, "TLS: using moznss security dir %s prefix %s.\n",
++					   realcertdir, prefix, 0 );
+ 				errcode = 0;
+-				break;
++				done = 1;
++			}
++			if ( realcertdir != securitydir ) {
++				PL_strfree( realcertdir );
++			}
++			if ( prefix != defprefix ) {
++				PL_strfree( prefix );
+ 			}
+ 		}
+ 
+ 		if ( errcode ) { /* no moznss db found, or not using moznss db */
+ #ifdef HAVE_NSS_INITCONTEXT
+ 			int flags = NSS_INIT_READONLY|NSS_INIT_NOCERTDB|NSS_INIT_NOMODDB;
+ #ifdef INITCONTEXT_HACK
+ 			if ( !NSS_IsInitialized() && ctx->tc_is_server ) {
+@@ -2038,19 +2089,16 @@
+ 
+ 		errno = 0;
+ 		rc = SSL_ForceHandshake( s );
+ 		if (rc == SECSuccess) {
+ 			rc = 0;
+ 			break; /* done */
+ 		}
+ 		err = PR_GetError();
+-		Debug( LDAP_DEBUG_TRACE, 
+-			   "TLS: error: accept - force handshake failure %d - error %d waitcounter %d\n",
+-			   errno, err, waitcounter );
+ 		if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
+ 			waitcounter++;
+ 			in_flags = PR_POLL_READ | PR_POLL_EXCEPT;
+ 			out_flags = 0;
+ 			errno = 0;
+ 			filesReady = tlsm_is_io_ready( s, in_flags, &out_flags );
+ 			if ( filesReady < 0 ) {
+ 				err = PR_GetError();
+@@ -2155,49 +2203,49 @@
+ tlsm_session_my_dn( tls_session *session, struct berval *der_dn )
+ {
+ 	tlsm_session *s = (tlsm_session *)session;
+ 	CERTCertificate *cert;
+ 
+ 	cert = SSL_LocalCertificate( s );
+ 	if (!cert) return LDAP_INVALID_CREDENTIALS;
+ 
+-	der_dn->bv_val = cert->derSubject.data;
++	der_dn->bv_val = (char *)cert->derSubject.data;
+ 	der_dn->bv_len = cert->derSubject.len;
+ 	CERT_DestroyCertificate( cert );
+ 	return 0;
+ }
+ 
+ static int
+ tlsm_session_peer_dn( tls_session *session, struct berval *der_dn )
+ {
+ 	tlsm_session *s = (tlsm_session *)session;
+ 	CERTCertificate *cert;
+ 
+ 	cert = SSL_PeerCertificate( s );
+ 	if (!cert) return LDAP_INVALID_CREDENTIALS;
+ 	
+-	der_dn->bv_val = cert->derSubject.data;
++	der_dn->bv_val = (char *)cert->derSubject.data;
+ 	der_dn->bv_len = cert->derSubject.len;
+ 	CERT_DestroyCertificate( cert );
+ 	return 0;
+ }
+ 
+ /* what kind of hostname were we given? */
+ #define	IS_DNS	0
+ #define	IS_IP4	1
+ #define	IS_IP6	2
+ 
+ static int
+ tlsm_session_chkhost( LDAP *ld, tls_session *session, const char *name_in )
+ {
+ 	tlsm_session *s = (tlsm_session *)session;
+ 	CERTCertificate *cert;
+ 	const char *name, *domain = NULL, *ptr;
+-	int i, ret, ntype = IS_DNS, nlen, dlen;
++	int ret, ntype = IS_DNS, nlen, dlen;
+ #ifdef LDAP_PF_INET6
+ 	struct in6_addr addr;
+ #else
+ 	struct in_addr addr;
+ #endif
+ 	SECItem altname;
+ 	SECStatus rv;
+ 
+@@ -2259,17 +2307,17 @@
+ 
+ 		do {
+ 			char *host;
+ 			int hlen;
+ 
+ 			/* ignore empty */
+ 			if ( !cur->name.other.len ) continue;
+ 
+-			host = cur->name.other.data;
++			host = (char *)cur->name.other.data;
+ 			hlen = cur->name.other.len;
+ 
+ 			if ( cur->type == certDNSName ) {
+ 				if ( ntype != IS_DNS )	continue;
+ 
+ 				/* is this an exact match? */
+ 				if ( nlen == hlen && !strncasecmp( name, host, nlen )) {
+ 					ret = LDAP_SUCCESS;
+@@ -2317,21 +2365,21 @@
+ 			while ( avas && ( ava = *avas++ )) {
+ 				if ( CERT_GetAVATag( ava ) == SEC_OID_AVA_COMMON_NAME )
+ 					lastava = ava;
+ 			}
+ 		}
+ 		if ( lastava ) {
+ 			SECItem *av = CERT_DecodeAVAValue( &lastava->value );
+ 			if ( av ) {
+-				if ( av->len == nlen && !strncasecmp( name, av->data, nlen )) {
++				if ( av->len == nlen && !strncasecmp( name, (char *)av->data, nlen )) {
+ 					ret = LDAP_SUCCESS;
+ 				} else if ( av->data[0] == '*' && av->data[1] == '.' &&
+ 					domain && dlen == av->len - 1 && !strncasecmp( name,
+-						av->data+1, dlen )) {
++						(char *)(av->data+1), dlen )) {
+ 					ret = LDAP_SUCCESS;
+ 				} else {
+ 					int len = av->len;
+ 					if ( len >= sizeof(buf) )
+ 						len = sizeof(buf)-1;
+ 					memcpy( buf, av->data, len );
+ 					buf[len] = '\0';
+ 				}
+@@ -2479,17 +2527,16 @@
+ {
+ 	return tlsm_PR_Send( fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
+ }
+ 
+ static PRStatus PR_CALLBACK
+ tlsm_PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
+ {
+ 	struct tls_data		*p;
+-	int rc;
+ 	ber_socklen_t len;
+ 
+ 	p = (struct tls_data *)fd->secret;
+ 
+ 	if ( p == NULL || p->sbiod == NULL ) {
+ 		return PR_FAILURE;
+ 	}
+ 	len = sizeof(PRNetAddr);
diff --git a/openldap-reject-non-file-keyfiles.patch b/openldap-reject-non-file-keyfiles.patch
new file mode 100644
index 0000000..5d2ff92
--- /dev/null
+++ b/openldap-reject-non-file-keyfiles.patch
@@ -0,0 +1,84 @@
+This workarounds Mozilla NSS bug. libldap crashes when TLS_CACERTDIR contains a subdirectory.
+Skip all non-file entries in CA_CERTDIR.
+
+Resolves: #652315
+Upstream ITS: #6703
+Author: Rich Megginson (rmeggins at redhat.com)
+
+diff -u -8 -r1.19 tls_m.c
+--- openldap.old/libraries/libldap/tls_m.c	29 Oct 2010 08:30:30 -0000	1.19
++++ openldap.new/libraries/libldap/tls_m.c	11 Nov 2010 20:18:20 -0000
+@@ -1011,16 +1011,36 @@
+ 	CK_ATTRIBUTE theTemplate[20];
+ 	CK_BBOOL cktrue = CK_TRUE;
+ 	CK_BBOOL ckfalse = CK_FALSE;
+ 	CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
+ 	char tmpslotname[64];
+ 	char *slotname = NULL;
+ 	const char *ptr = NULL;
+ 	char sep = PR_GetDirectorySeparator();
++	PRFileInfo fi;
++	PRStatus status;
++
++	memset( &fi, 0, sizeof(fi) );
++	status = PR_GetFileInfo( filename, &fi );
++	if ( PR_SUCCESS != status) {
++		PRErrorCode errcode = PR_GetError();
++		Debug( LDAP_DEBUG_ANY,
++			   "TLS: could not read certificate file %s - error %d:%s.\n",
++			   filename, errcode,
++			   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
++		return -1;
++	}
++
++	if ( fi.type != PR_FILE_FILE ) {
++		Debug( LDAP_DEBUG_ANY,
++			   "TLS: error: the certificate file %s is not a file.\n",
++			   filename, 0 ,0 );
++		return -1;
++	}
+ 
+ 	attrs = theTemplate;
+ 
+ 	if ( isca ) {
+ 		slotID = 0; /* CA and trust objects use slot 0 */
+ 		PR_snprintf( tmpslotname, sizeof(tmpslotname), TLSM_PEM_TOKEN_FMT, slotID );
+ 		slotname = tmpslotname;
+ 	} else {
+@@ -1083,16 +1103,36 @@
+ 	CK_SLOT_ID slotID;
+ 	PK11SlotInfo * slot = NULL;
+ 	PK11GenericObject *rv;
+ 	CK_ATTRIBUTE *attrs;
+ 	CK_ATTRIBUTE theTemplate[20];
+ 	CK_BBOOL cktrue = CK_TRUE;
+ 	CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
+ 	int retcode = 0;
++	PRFileInfo fi;
++	PRStatus status;
++
++	memset( &fi, 0, sizeof(fi) );
++	status = PR_GetFileInfo( filename, &fi );
++	if ( PR_SUCCESS != status) {
++		PRErrorCode errcode = PR_GetError();
++		Debug( LDAP_DEBUG_ANY,
++			   "TLS: could not read key file %s - error %d:%s.\n",
++			   filename, errcode,
++			   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
++		return -1;
++	}
++
++	if ( fi.type != PR_FILE_FILE ) {
++		Debug( LDAP_DEBUG_ANY,
++			   "TLS: error: the key file %s is not a file.\n",
++			   filename, 0 ,0 );
++		return -1;
++	}
+ 
+ 	attrs = theTemplate;
+ 
+ 	if ( ctx->tc_slotname == NULL ) { /* need new slot */
+ 		slotID = ++tlsm_slot_count;
+ 		ctx->tc_slotname = PR_smprintf( TLSM_PEM_TOKEN_FMT, slotID );
+ 	}
+ 	slot = PK11_FindSlotByName( ctx->tc_slotname );
diff --git a/openldap-use-cacert-dir-and-file.patch b/openldap-use-cacert-dir-and-file.patch
new file mode 100644
index 0000000..0d1cf56
--- /dev/null
+++ b/openldap-use-cacert-dir-and-file.patch
@@ -0,0 +1,136 @@
+TLS_CACERTDIR takes precedence over TLS_CACERTFILE
+
+Resolves: #652304
+Upstream ITS: #6704
+Author: Rich Megginson (rmeggins at redhat.com)
+
+diff -uNPrp openldap-2.4.23.old/libraries/libldap/tls_m.c openldap-2.4.23.new/libraries/libldap/tls_m.c
+--- openldap-2.4.23.old/libraries/libldap/tls_m.c	2010-11-18 11:01:36.129392116 +0100
++++ openldap-2.4.23.new/libraries/libldap/tls_m.c	2010-11-18 11:02:19.466387205 +0100
+@@ -1031,6 +1031,7 @@ tlsm_add_cert_from_file( tlsm_ctx *ctx, 
+ 	}
+ 
+ 	if ( fi.type != PR_FILE_FILE ) {
++		PR_SetError(PR_IS_DIRECTORY_ERROR, 0);
+ 		Debug( LDAP_DEBUG_ANY,
+ 			   "TLS: error: the certificate file %s is not a file.\n",
+ 			   filename, 0 ,0 );
+@@ -1123,6 +1124,7 @@ tlsm_add_key_from_file( tlsm_ctx *ctx, c
+ 	}
+ 
+ 	if ( fi.type != PR_FILE_FILE ) {
++		PR_SetError(PR_IS_DIRECTORY_ERROR, 0);
+ 		Debug( LDAP_DEBUG_ANY,
+ 			   "TLS: error: the key file %s is not a file.\n",
+ 			   filename, 0 ,0 );
+@@ -1178,69 +1180,91 @@ static int
+ tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir )
+ {
+ 	PRBool isca = PR_TRUE;
++	PRStatus status = PR_FAILURE;
++	PRErrorCode errcode = PR_SUCCESS;
+ 
+ 	if ( cacertfile ) {
+ 		int rc = tlsm_add_cert_from_file( ctx, cacertfile, isca );
+ 		if ( rc ) {
+-			return rc;
++			errcode = PR_GetError();
++			Debug( LDAP_DEBUG_ANY,
++				   "TLS: %s is not a valid CA certificate file - error %d:%s.\n",
++				   cacertfile, errcode,
++				   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
++		} else {
++			Debug( LDAP_DEBUG_TRACE,
++				   "TLS: loaded CA certificate file %s.\n",
++				   cacertfile, 0, 0 );
++			status = PR_SUCCESS; /* have at least one good CA - we can proceed */
+ 		}
+ 	}
+ 
+ 	if ( cacertdir ) {
+ 		PRFileInfo fi;
+-		PRStatus status;
+ 		PRDir *dir;
+ 		PRDirEntry *entry;
++		PRStatus fistatus = PR_FAILURE;
+ 
+ 		memset( &fi, 0, sizeof(fi) );
+-		status = PR_GetFileInfo( cacertdir, &fi );
+-		if ( PR_SUCCESS != status) {
+-			PRErrorCode errcode = PR_GetError();
++		fistatus = PR_GetFileInfo( cacertdir, &fi );
++		if ( PR_SUCCESS != fistatus) {
++			errcode = PR_GetError();
+ 			Debug( LDAP_DEBUG_ANY,
+ 				   "TLS: could not get info about the CA certificate directory %s - error %d:%s.\n",
+ 				   cacertdir, errcode,
+ 				   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+-			return -1;
++			goto done;
+ 		}
+ 
+ 		if ( fi.type != PR_FILE_DIRECTORY ) {
+ 			Debug( LDAP_DEBUG_ANY,
+ 				   "TLS: error: the CA certificate directory %s is not a directory.\n",
+ 				   cacertdir, 0 ,0 );
+-			return -1;
++			goto done;
+ 		}
+ 
+ 		dir = PR_OpenDir( cacertdir );
+ 		if ( NULL == dir ) {
+-			PRErrorCode errcode = PR_GetError();
++			errcode = PR_GetError();
+ 			Debug( LDAP_DEBUG_ANY,
+ 				   "TLS: could not open the CA certificate directory %s - error %d:%s.\n",
+ 				   cacertdir, errcode,
+ 				   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+-			return -1;
++			goto done;
+ 		}
+ 
+-		status = -1;
+ 		do {
+ 			entry = PR_ReadDir( dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN );
+ 			if ( NULL != entry ) {
+ 				char *fullpath = PR_smprintf( "%s/%s", cacertdir, entry->name );
+ 				if ( !tlsm_add_cert_from_file( ctx, fullpath, isca ) ) {
+-					status = 0; /* found at least 1 valid CA file in the dir */
++					Debug( LDAP_DEBUG_TRACE,
++						   "TLS: loaded CA certificate file %s from CA certificate directory %s.\n",
++						   fullpath, cacertdir, 0 );
++					status = PR_SUCCESS; /* found at least 1 valid CA file in the dir */
++				} else {
++					errcode = PR_GetError();
++					Debug( LDAP_DEBUG_TRACE,
++						   "TLS: %s is not a valid CA certificate file - error %d:%s.\n",
++						   fullpath, errcode,
++						   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+ 				}
+ 				PR_smprintf_free( fullpath );
+ 			}
+ 		} while ( NULL != entry );
+ 		PR_CloseDir( dir );
+-
+-		if ( status ) {
+-			PRErrorCode errcode = PR_GetError();
+-			Debug( LDAP_DEBUG_ANY,
+-				   "TLS: did not find any valid CA certificate files in the CA certificate directory %s - error %d:%s.\n",
+-				   cacertdir, errcode,
+-				   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+-			return -1;
++	}
++done:
++	if ( status != PR_SUCCESS ) {
++		const char *fmtstr = NULL;
++		if ( cacertfile && cacertdir ) {
++			fmtstr = "TLS: did not find any valid CA certificates in %s or %s\n";
++		} else {
++			fmtstr = "TLS: did not find any valid CA certificates in %s%s\n";
+ 		}
++		Debug( LDAP_DEBUG_ANY, fmtstr, cacertdir ? cacertdir : "",
++			   cacertfile ? cacertfile : "", 0 );
++		return -1;
+ 	}
+ 
+ 	return 0;
diff --git a/openldap.spec b/openldap.spec
index 4f17f6f..c0ec47b 100644
--- a/openldap.spec
+++ b/openldap.spec
@@ -7,7 +7,7 @@
 
 Name: openldap
 Version: 2.4.23
-Release: 2%{?dist}
+Release: 3%{?dist}
 Summary: LDAP support libraries
 Group: System Environment/Daemons
 License: OpenLDAP
@@ -31,6 +31,11 @@ Patch8: openldap-userconfig-setgid.patch
 # already merged upstream
 Patch100: openldap-nss-ca-selfsigned.patch
 Patch101: openldap-nss-delay-token-auth.patch
+Patch102: openldap-nss-db-prefix.patch
+Patch103: openldap-reject-non-file-keyfiles.patch
+Patch104: openldap-use-cacert-dir-and-file.patch
+Patch105: openldap-cacertdir-hash-only.patch
+Patch106: openldap-improve-trace-messages.patch
 
 # patches for the evolution library (see README.evolution)
 Patch200: openldap-evolution-ntlm.patch
@@ -134,6 +139,11 @@ pushd openldap-%{version}
 
 %patch100 -p1 -b .nss-ca-selfsigned
 %patch101 -p1 -b .nss-delay-token-auth
+%patch102 -p1 -b .nss-db-prefix
+%patch103 -p1 -b .reject-non-file-keyfiles
+%patch104 -p1 -b .use-cacert-dir-and-file-dir
+%patch105 -p1 -b .cacertdir-hash-only
+%patch106 -p1 -b .improve-trace-messages
 
 cp %{_datadir}/libtool/config/config.{sub,guess} build/
 
@@ -641,6 +651,13 @@ exit 0
 %attr(0644,root,root)      %{evolution_connector_libdir}/*.a
 
 %changelog
+* Thu Nov 18 2010 Jan Vcelak <jvcelak at redhat.com> 2.4.23-3
+- add support for multiple prefixed Mozilla NSS database files in TLS_CACERTDIR
+- reject non-file keyfiles in TLS_CACERTDIR (#652315)
+- TLS_CACERTDIR precedence over TLS_CACERT (#652304)
+- accept only files in hash.0 format in TLS_CACERTDIR (#650288)
+- improve SSL/TLS trace messages (#652818)
+
 * Mon Nov 01 2010 Jan Vcelak <jvcelak at redhat.com> 2.4.23-2
 - fix possible infinite loop when checking permissions of TLS files (#641946)
 - removed outdated autofs.schema (#643045)


More information about the scm-commits mailing list