diff --git a/lib/pki/tdcache.c b/lib/pki/tdcache.c --- a/lib/pki/tdcache.c +++ b/lib/pki/tdcache.c @@ -379,23 +379,29 @@ nssTrustDomain_UnlockCertCache ( struct token_cert_dtor { NSSToken *token; nssTDCertificateCache *cache; NSSCertificate **certs; PRUint32 numCerts, arrSize; }; +static void cert_iter(const void *k, void *v, void *a) +{ + nssList *certList = (nssList *)a; + NSSCertificate *c = (NSSCertificate *)k; + nssList_Add(certList, nssCertificate_AddRef(c)); +} + static void -remove_token_certs(const void *k, void *v, void *a) +remove_token_certs(NSSCertificate *c, struct token_cert_dtor *dtor) { - NSSCertificate *c = (NSSCertificate *)k; nssPKIObject *object = &c->object; - struct token_cert_dtor *dtor = a; PRUint32 i; + nssPKIObject_AddRef(object); nssPKIObject_Lock(object); for (i=0; inumInstances; i++) { if (object->instances[i]->token == dtor->token) { nssCryptokiObject_Destroy(object->instances[i]); object->instances[i] = object->instances[object->numInstances-1]; object->instances[object->numInstances-1] = NULL; object->numInstances--; @@ -422,45 +428,83 @@ NSS_IMPLEMENT PRStatus nssTrustDomain_RemoveTokenCertsFromCache ( NSSTrustDomain *td, NSSToken *token ) { NSSCertificate **certs; PRUint32 i, arrSize = 10; struct token_cert_dtor dtor; + nssList *certList; + PRStatus nspr_rv = PR_FAILURE; + nssListIterator *iter; + NSSCertificate *c; + certs = nss_ZNEWARRAY(NULL, NSSCertificate *, arrSize); if (!certs) { return PR_FAILURE; } dtor.cache = td->cache; dtor.token = token; dtor.certs = certs; dtor.numCerts = 0; dtor.arrSize = arrSize; + + certList = nssList_Create(NULL, PR_FALSE); + if (!certList) { + goto loser; + } + /* fetch the list of certs in the cache */ PZ_Lock(td->cache->lock); - nssHash_Iterate(td->cache->issuerAndSN, remove_token_certs, &dtor); + nssHash_Iterate(td->cache->issuerAndSN, cert_iter, (void *)certList); + PZ_Unlock(td->cache->lock); + + /* find the certs that match this token without olding the td cache lock */ + iter=nssList_CreateIterator(certList); + if (!iter) { + goto loser; + } + for (c = (NSSCertificate *)nssListIterator_Start(iter); + c != (NSSCertificate *)NULL; + c = (NSSCertificate *)nssListIterator_Next(iter)) { + remove_token_certs( c, &dtor); + } + nssListIterator_Finish(iter); + nssListIterator_Destroy(iter); + nssList_Destroy(certList); + certList = NULL; + + /* now remove theose certs attached to this token */ + PZ_Lock(td->cache->lock); for (i=0; iobject.numInstances == 0) { nssTrustDomain_RemoveCertFromCacheLOCKED(td, dtor.certs[i]); dtor.certs[i] = NULL; /* skip this cert in the second for loop */ } else { /* make sure it doesn't disappear on us before we finish */ nssCertificate_AddRef(dtor.certs[i]); } } PZ_Unlock(td->cache->lock); + + /* clean up */ for (i=0; i