diff --git a/CHANGES b/CHANGES
index f8a3f4eb7216ad694d28e2dc5f6616cb918ec7d0..8b8cac4dc6a43de101d881c8ed4b60cf2ed10e4e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,7 @@ OpenLDAP 2.4.22 Engineering
 	Added slapo-ldap idassert-passthru (ITS#6456)
 	Added slapo-pbind
 	Fixed libldap GnuTLS serial length (ITS#6460)
+	Fixed libldap MozNSS context and PEM support (ITS#6432)
 	Fixed slapd acl non-entry internal searches (ITS#6481)
 	Fixed slapd certificateListValidate (ITS#6466)
 	Fixed slapd empty URI parsing (ITS#6465)
diff --git a/libraries/libldap/tls_m.c b/libraries/libldap/tls_m.c
index 8604b14075027587499c0a3ec13f22acccd42737..443b966346b2fe35b025aae713d2ec3c1907f764 100644
--- a/libraries/libldap/tls_m.c
+++ b/libraries/libldap/tls_m.c
@@ -64,6 +64,16 @@
 #include <nss/keyhi.h>
 #include <nss/secmod.h>
 
+/* NSS 3.12.5 and later have NSS_InitContext */
+#if NSS_VMAJOR <= 3 && NSS_VMINOR <= 12 && NSS_VPATCH < 5
+/* do nothing */
+#else
+#define HAVE_NSS_INITCONTEXT 1
+#endif
+
+/* InitContext does not currently work in server mode */
+/* #define INITCONTEXT_HACK 1 */
+
 typedef struct tlsm_ctx {
 	PRFileDesc *tc_model;
 	int tc_refcnt;
@@ -77,6 +87,11 @@ typedef struct tlsm_ctx {
 	PRCallOnceType tc_callonce;
 	PRBool tc_using_pem;
 	char *tc_slotname; /* if using pem */
+#ifdef HAVE_NSS_INITCONTEXT
+	NSSInitContext *tc_initctx; /* the NSS context */
+#endif
+	PK11GenericObject **tc_pem_objs; /* array of objects to free */
+	int tc_n_pem_objs; /* number of objects */
 #ifdef LDAP_R_COMPILE
 	ldap_pvt_thread_mutex_t tc_refmutex;
 #endif
@@ -88,10 +103,9 @@ static PRDescIdentity	tlsm_layer_id;
 
 static const PRIOMethods tlsm_PR_methods;
 
-static int tlsm_did_init;
-
 static const char* pem_library = "nsspem";
-static SECMODModule* pemMod = NULL;
+static const char *pem_mod_name = "PEM";
+static SECMODModule* pem_module;
 
 #define DEFAULT_TOKEN_NAME "default"
 /* sprintf format used to create token name */
@@ -925,12 +939,29 @@ tlsm_init_tokens( tlsm_ctx *ctx )
 	slotList = PK11_GetAllTokens( CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, NULL );
 
 	for ( listEntry = PK11_GetFirstSafe( slotList ); !rc && listEntry;
-		  listEntry = listEntry->next) {
+		  listEntry = PK11_GetNextSafe( slotList, listEntry, PR_FALSE ) ) {
 		PK11SlotInfo *slot = listEntry->slot;
 		rc = tlsm_authenticate_to_slot( ctx, slot );
-		PK11_FreeSlot(slot);
 	}
 
+	PK11_FreeSlotList( slotList );
+
+	return rc;
+}
+
+static SECStatus
+tlsm_nss_shutdown_cb( void *appData, void *nssData )
+{
+	SECStatus rc = SECSuccess;
+
+	SSL_ShutdownServerSessionIDCache();
+	SSL_ClearSessionCache();
+
+	if ( pem_module ) {
+		SECMOD_UnloadUserModule( pem_module );
+		SECMOD_DestroyModule( pem_module );
+		pem_module = NULL;
+	}
 	return rc;
 }
 
@@ -941,19 +972,24 @@ tlsm_init_pem_module( void )
 	char *fullname = NULL;
 	char *configstring = NULL;
 
+	if ( pem_module ) {
+		return rc;
+	}
+
+	/* not loaded - load it */
 	/* get the system dependent library name */
 	fullname = PR_GetLibraryName( NULL, pem_library );
 	/* Load our PKCS#11 module */
-	configstring = PR_smprintf( "library=%s name=PEM parameters=\"\"", fullname );
-	PR_smprintf_free( fullname );
+	configstring = PR_smprintf( "library=%s name=%s parameters=\"\"", fullname, pem_mod_name );
+	PL_strfree( fullname );
 
-	pemMod = SECMOD_LoadUserModule( configstring, NULL, PR_FALSE );
+	pem_module = SECMOD_LoadUserModule( configstring, NULL, PR_FALSE );
 	PR_smprintf_free( configstring );
 
-	if ( !pemMod || !pemMod->loaded ) {
-		if ( pemMod ) {
-			SECMOD_DestroyModule( pemMod );
-			pemMod = NULL;
+	if ( !pem_module || !pem_module->loaded ) {
+		if ( pem_module ) {
+			SECMOD_DestroyModule( pem_module );
+			pem_module = NULL;
 		}
 		rc = -1;
 	}
@@ -961,6 +997,29 @@ tlsm_init_pem_module( void )
 	return rc;
 }
 
+static void
+tlsm_add_pem_obj( tlsm_ctx *ctx, PK11GenericObject *obj )
+{
+	int idx = ctx->tc_n_pem_objs;
+	ctx->tc_n_pem_objs++;
+	ctx->tc_pem_objs = (PK11GenericObject **)
+		PORT_Realloc( ctx->tc_pem_objs, ctx->tc_n_pem_objs * sizeof( PK11GenericObject * ) );
+	ctx->tc_pem_objs[idx] = obj;														  
+}
+
+static void
+tlsm_free_pem_objs( tlsm_ctx *ctx )
+{
+	/* free in reverse order of allocation */
+	while ( ctx->tc_n_pem_objs-- ) {
+		PK11_DestroyGenericObject( ctx->tc_pem_objs[ctx->tc_n_pem_objs] );
+		ctx->tc_pem_objs[ctx->tc_n_pem_objs] = NULL;
+	}
+	PORT_Free(ctx->tc_pem_objs);
+	ctx->tc_pem_objs = NULL;
+	ctx->tc_n_pem_objs = 0;
+}
+
 static int
 tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca )
 {
@@ -1032,6 +1091,8 @@ tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca )
 		return -1;
 	}
 
+	tlsm_add_pem_obj( ctx, rv );
+
 	return 0;
 }
 
@@ -1079,13 +1140,16 @@ tlsm_add_key_from_file( tlsm_ctx *ctx, const char *filename )
 	} else {
 		/* When adding an encrypted key the PKCS#11 will be set as removed */
 		/* This will force the token to be seen as re-inserted */
-		SECMOD_WaitForAnyTokenEvent( pemMod, 0, 0 );
+		SECMOD_WaitForAnyTokenEvent( pem_module, 0, 0 );
 		PK11_IsPresent( slot );
 		retcode = 0;
 	}
 
 	PK11_FreeSlot( slot );
 
+	if ( !retcode ) {
+		tlsm_add_pem_obj( ctx, rv );
+	}
 	return retcode;
 }
 
@@ -1178,11 +1242,20 @@ tlsm_deferred_init( void *arg )
 	int ii;
 	int nn;
 	PRErrorCode errcode = 1;
+#ifdef HAVE_NSS_INITCONTEXT
+	NSSInitParameters initParams;
+	NSSInitContext *initctx = NULL;
+#endif
+	SECStatus rc;
 
-	/* NSS support for multi-init is coming */
-#ifndef NSS_MULTI_INIT
+#ifdef HAVE_NSS_INITCONTEXT
+	memset( &initParams, 0, sizeof( initParams ) );
+	initParams.length = sizeof( initParams );
+#endif /* HAVE_NSS_INITCONTEXT */
+
+#ifndef HAVE_NSS_INITCONTEXT
 	if ( !NSS_IsInitialized() ) {
-#endif /* NSS_MULTI_INIT */
+#endif /* HAVE_NSS_INITCONTEXT */
 		/*
 		  MOZNSS_DIR will override everything else - you can
 		  always set MOZNSS_DIR to force the use of this
@@ -1197,12 +1270,30 @@ tlsm_deferred_init( void *arg )
 		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; ii < nn; ++ii ) {
 			const char *securitydir = securitydirs[ii];
 			if ( NULL == securitydir ) {
 				continue;
 			}
-			if ( NSS_Initialize( securitydir, "", "", SECMOD_DB, NSS_INIT_READONLY ) ) {
+#ifdef HAVE_NSS_INITCONTEXT
+#ifdef INITCONTEXT_HACK
+			if ( !NSS_IsInitialized() && ctx->tc_is_server ) {
+				rc = NSS_Initialize( securitydir, "", "", SECMOD_DB, NSS_INIT_READONLY );
+			} else {
+				initctx = NSS_InitContext( securitydir, "", "", SECMOD_DB,
+										   &initParams, NSS_INIT_READONLY );
+				rc = (initctx == NULL) ? SECFailure : SECSuccess;
+			}
+#else
+			initctx = NSS_InitContext( securitydir, "", "", SECMOD_DB,
+									   &initParams, NSS_INIT_READONLY );
+			rc = (initctx == NULL) ? SECFailure : SECSuccess;
+#endif
+#else
+			rc = NSS_Initialize( securitydir, "", "", 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",
@@ -1217,7 +1308,25 @@ tlsm_deferred_init( void *arg )
 		}
 
 		if ( errcode ) { /* no moznss db found, or not using moznss db */
-			if ( NSS_NoDB_Init( NULL ) ) {
+#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 ) {
+				rc = NSS_NoDB_Init( NULL );
+			} else {
+				initctx = NSS_InitContext( "", "", "", SECMOD_DB,
+										   &initParams, flags );
+				rc = (initctx == NULL) ? SECFailure : SECSuccess;
+			}
+#else
+			initctx = NSS_InitContext( "", "", "", SECMOD_DB,
+									   &initParams, flags );
+			rc = (initctx == NULL) ? SECFailure : SECSuccess;
+#endif
+#else
+			rc = NSS_NoDB_Init( NULL );
+#endif
+			if ( rc != SECSuccess ) {
 				errcode = PORT_GetError();
 				Debug( LDAP_DEBUG_ANY,
 					   "TLS: could not initialize moznss - error %d:%s.\n",
@@ -1225,6 +1334,10 @@ tlsm_deferred_init( void *arg )
 				return -1;
 			}
 
+#ifdef HAVE_NSS_INITCONTEXT
+			ctx->tc_initctx = initctx;
+#endif
+
 			/* initialize the PEM module */
 			if ( tlsm_init_pem_module() ) {
 				errcode = PORT_GetError();
@@ -1241,6 +1354,12 @@ tlsm_deferred_init( void *arg )
 			ctx->tc_using_pem = PR_TRUE;
 		}
 
+#ifdef HAVE_NSS_INITCONTEXT
+		if ( !ctx->tc_initctx ) {
+			ctx->tc_initctx = initctx;
+		}
+#endif
+
 		NSS_SetDomesticPolicy();
 
 		PK11_SetPasswordFunc( tlsm_pin_prompt );
@@ -1249,10 +1368,14 @@ tlsm_deferred_init( void *arg )
 			return -1;
 		}
 
-		tlsm_did_init = 1; /* we did the init - we should also clean up */
-#ifndef NSS_MULTI_INIT
+		/* register cleanup function */
+		/* delete the old one, if any */
+		NSS_UnregisterShutdown( tlsm_nss_shutdown_cb, NULL );
+		NSS_RegisterShutdown( tlsm_nss_shutdown_cb, NULL );
+
+#ifndef HAVE_NSS_INITCONTEXT
 	}
-#endif /* NSS_MULTI_INIT */
+#endif /* HAVE_NSS_INITCONTEXT */
 
 	return 0;
 }
@@ -1420,22 +1543,19 @@ tlsm_get_client_auth_data( void *arg, PRFileDesc *fd,
  * the database
 */
 static int
-tlsm_clientauth_init( tlsm_ctx *ctx, const char *certname )
+tlsm_clientauth_init( tlsm_ctx *ctx )
 {
 	SECStatus status = SECFailure;
 	int rc;
 
-	PL_strfree( ctx->tc_certname );
-	rc = tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, certname, 0, NULL, NULL );
+	rc = tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, 0, NULL, NULL );
 	if ( rc ) {
 		Debug( LDAP_DEBUG_ANY,
 			   "TLS: error: unable to set up client certificate authentication for "
-			   "certificate named %s\n", certname, 0, 0 );
+			   "certificate named %s\n", ctx->tc_certname, 0, 0 );
 		return -1;
 	}
 
-	ctx->tc_certname = PL_strdup( certname );
-
 	status = SSL_GetClientAuthDataHook( ctx->tc_model,
 										tlsm_get_client_auth_data,
 										(void *)ctx );
@@ -1449,21 +1569,6 @@ tlsm_clientauth_init( tlsm_ctx *ctx, const char *certname )
 static void
 tlsm_destroy( void )
 {
-	if (pemMod) {
-		SECMOD_DestroyModule(pemMod);
-		pemMod = NULL;
-	}
-
-	/* Only if we did the actual initialization */
-	if ( tlsm_did_init ) {
-		tlsm_did_init = 0;
-
-		SSL_ShutdownServerSessionIDCache();
-		SSL_ClearSessionCache();
-		NSS_Shutdown();
-	}
-
-	PR_Cleanup();
 }
 
 static tls_ctx *
@@ -1487,6 +1592,11 @@ tlsm_ctx_new ( struct ldapoptions *lo )
 		ctx->tc_verify_cert = PR_FALSE;
 		ctx->tc_using_pem = PR_FALSE;
 		ctx->tc_slotname = NULL;
+#ifdef HAVE_NSS_INITCONTEXT
+		ctx->tc_initctx = NULL;
+#endif /* HAVE_NSS_INITCONTEXT */
+		ctx->tc_pem_objs = NULL;
+		ctx->tc_n_pem_objs = 0;
 	}
 	return (tls_ctx *)ctx;
 }
@@ -1528,7 +1638,13 @@ tlsm_ctx_free ( tls_ctx *ctx )
 	c->tc_certname = NULL;
 	PL_strfree( c->tc_pin_file );
 	c->tc_pin_file = NULL;
-	PL_strfree( c->tc_slotname );
+	PL_strfree( c->tc_slotname );		
+	tlsm_free_pem_objs( c );
+#ifdef HAVE_NSS_INITCONTEXT
+	if (c->tc_initctx)
+		NSS_ShutdownContext( c->tc_initctx );
+	c->tc_initctx = NULL;
+#endif /* HAVE_NSS_INITCONTEXT */
 #ifdef LDAP_R_COMPILE
 	ldap_pvt_thread_mutex_destroy( &c->tc_refmutex );
 #endif
@@ -1566,7 +1682,7 @@ tlsm_deferred_ctx_init( void *arg )
 	    return -1;
 	}
 
-	ctx->tc_certdb = CERT_GetDefaultCertDB(); /* replace with multi-init db call */
+	ctx->tc_certdb = CERT_GetDefaultCertDB(); /* If there is ever a per-context db, change this */
 
 	fd = PR_CreateIOLayerStub( tlsm_layer_id, &tlsm_PR_methods );
 	if ( fd ) {
@@ -1731,7 +1847,7 @@ tlsm_deferred_ctx_init( void *arg )
 				       ctx->tc_certname, 0, 0 );
 				return -1;
 			}
-			if ( tlsm_clientauth_init( ctx, ctx->tc_certname ) ) {
+			if ( tlsm_clientauth_init( ctx ) ) {
 				Debug( LDAP_DEBUG_ANY, 
 				       "TLS: error: unable to set up client certificate authentication using %s\n",
 				       ctx->tc_certname, 0, 0 );