michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: enum { michael@0: dbInvalidCert = 0, michael@0: dbNoSMimeProfile, michael@0: dbOlderCert, michael@0: dbBadCertificate, michael@0: dbCertNotWrittenToDB michael@0: }; michael@0: michael@0: typedef struct dbRestoreInfoStr michael@0: { michael@0: NSSLOWCERTCertDBHandle *handle; michael@0: PRBool verbose; michael@0: PRFileDesc *out; michael@0: int nCerts; michael@0: int nOldCerts; michael@0: int dbErrors[5]; michael@0: PRBool removeType[3]; michael@0: PRBool promptUser[3]; michael@0: } dbRestoreInfo; michael@0: michael@0: char * michael@0: IsEmailCert(CERTCertificate *cert) michael@0: { michael@0: char *email, *tmp1, *tmp2; michael@0: PRBool isCA; michael@0: int len; michael@0: michael@0: if (!cert->subjectName) { michael@0: return NULL; michael@0: } michael@0: michael@0: tmp1 = PORT_Strstr(cert->subjectName, "E="); michael@0: tmp2 = PORT_Strstr(cert->subjectName, "MAIL="); michael@0: /* XXX Nelson has cert for KTrilli which does not have either michael@0: * of above but is email cert (has cert->emailAddr). michael@0: */ michael@0: if (!tmp1 && !tmp2 && !(cert->emailAddr && cert->emailAddr[0])) { michael@0: return NULL; michael@0: } michael@0: michael@0: /* Server or CA cert, not personal email. */ michael@0: isCA = CERT_IsCACert(cert, NULL); michael@0: if (isCA) michael@0: return NULL; michael@0: michael@0: /* XXX CERT_IsCACert advertises checking the key usage ext., michael@0: but doesn't appear to. */ michael@0: /* Check the key usage extension. */ michael@0: if (cert->keyUsagePresent) { michael@0: /* Must at least be able to sign or encrypt (not neccesarily michael@0: * both if it is one of a dual cert). michael@0: */ michael@0: if (!((cert->rawKeyUsage & KU_DIGITAL_SIGNATURE) || michael@0: (cert->rawKeyUsage & KU_KEY_ENCIPHERMENT))) michael@0: return NULL; michael@0: michael@0: /* CA cert, not personal email. */ michael@0: if (cert->rawKeyUsage & (KU_KEY_CERT_SIGN | KU_CRL_SIGN)) michael@0: return NULL; michael@0: } michael@0: michael@0: if (cert->emailAddr && cert->emailAddr[0]) { michael@0: email = PORT_Strdup(cert->emailAddr); michael@0: } else { michael@0: if (tmp1) michael@0: tmp1 += 2; /* "E=" */ michael@0: else michael@0: tmp1 = tmp2 + 5; /* "MAIL=" */ michael@0: len = strcspn(tmp1, ", "); michael@0: email = (char*)PORT_Alloc(len+1); michael@0: PORT_Strncpy(email, tmp1, len); michael@0: email[len] = '\0'; michael@0: } michael@0: michael@0: return email; michael@0: } michael@0: michael@0: SECStatus michael@0: deleteit(CERTCertificate *cert, void *arg) michael@0: { michael@0: return SEC_DeletePermCertificate(cert); michael@0: } michael@0: michael@0: /* Different than DeleteCertificate - has the added bonus of removing michael@0: * all certs with the same DN. michael@0: */ michael@0: SECStatus michael@0: deleteAllEntriesForCert(NSSLOWCERTCertDBHandle *handle, CERTCertificate *cert, michael@0: PRFileDesc *outfile) michael@0: { michael@0: #if 0 michael@0: certDBEntrySubject *subjectEntry; michael@0: certDBEntryNickname *nicknameEntry; michael@0: certDBEntrySMime *smimeEntry; michael@0: int i; michael@0: #endif michael@0: michael@0: if (outfile) { michael@0: PR_fprintf(outfile, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n\n"); michael@0: PR_fprintf(outfile, "Deleting redundant certificate:\n"); michael@0: dumpCertificate(cert, -1, outfile); michael@0: } michael@0: michael@0: CERT_TraverseCertsForSubject(handle, cert->subjectList, deleteit, NULL); michael@0: #if 0 michael@0: CERT_LockDB(handle); michael@0: subjectEntry = ReadDBSubjectEntry(handle, &cert->derSubject); michael@0: /* It had better be there, or created a bad db. */ michael@0: PORT_Assert(subjectEntry); michael@0: for (i=0; incerts; i++) { michael@0: DeleteDBCertEntry(handle, &subjectEntry->certKeys[i]); michael@0: } michael@0: DeleteDBSubjectEntry(handle, &cert->derSubject); michael@0: if (subjectEntry->emailAddr && subjectEntry->emailAddr[0]) { michael@0: smimeEntry = ReadDBSMimeEntry(handle, subjectEntry->emailAddr); michael@0: if (smimeEntry) { michael@0: if (SECITEM_ItemsAreEqual(&subjectEntry->derSubject, michael@0: &smimeEntry->subjectName)) michael@0: /* Only delete it if it's for this subject! */ michael@0: DeleteDBSMimeEntry(handle, subjectEntry->emailAddr); michael@0: SEC_DestroyDBEntry((certDBEntry*)smimeEntry); michael@0: } michael@0: } michael@0: if (subjectEntry->nickname) { michael@0: nicknameEntry = ReadDBNicknameEntry(handle, subjectEntry->nickname); michael@0: if (nicknameEntry) { michael@0: if (SECITEM_ItemsAreEqual(&subjectEntry->derSubject, michael@0: &nicknameEntry->subjectName)) michael@0: /* Only delete it if it's for this subject! */ michael@0: DeleteDBNicknameEntry(handle, subjectEntry->nickname); michael@0: SEC_DestroyDBEntry((certDBEntry*)nicknameEntry); michael@0: } michael@0: } michael@0: SEC_DestroyDBEntry((certDBEntry*)subjectEntry); michael@0: CERT_UnlockDB(handle); michael@0: #endif michael@0: return SECSuccess; michael@0: } michael@0: michael@0: void michael@0: getCertsToDelete(char *numlist, int len, int *certNums, int nCerts) michael@0: { michael@0: int j, num; michael@0: char *numstr, *numend, *end; michael@0: michael@0: numstr = numlist; michael@0: end = numstr + len - 1; michael@0: while (numstr != end) { michael@0: numend = strpbrk(numstr, ", \n"); michael@0: *numend = '\0'; michael@0: if (PORT_Strlen(numstr) == 0) michael@0: return; michael@0: num = PORT_Atoi(numstr); michael@0: if (numstr == numlist) michael@0: certNums[0] = num; michael@0: for (j=1; jpromptUser[errtype] == PR_FALSE) michael@0: return (info->removeType[errtype]); michael@0: switch (errtype) { michael@0: case dbInvalidCert: michael@0: PR_fprintf(PR_STDOUT, "******** Expired ********\n"); michael@0: PR_fprintf(PR_STDOUT, "Cert has expired.\n\n"); michael@0: dumpCertificate(certs[0], -1, PR_STDOUT); michael@0: PR_fprintf(PR_STDOUT, michael@0: "Keep it? (y/n - this one, Y/N - all expired certs) [n] "); michael@0: break; michael@0: case dbNoSMimeProfile: michael@0: PR_fprintf(PR_STDOUT, "******** No Profile ********\n"); michael@0: PR_fprintf(PR_STDOUT, "S/MIME cert has no profile.\n\n"); michael@0: dumpCertificate(certs[0], -1, PR_STDOUT); michael@0: PR_fprintf(PR_STDOUT, michael@0: "Keep it? (y/n - this one, Y/N - all S/MIME w/o profile) [n] "); michael@0: break; michael@0: case dbOlderCert: michael@0: PR_fprintf(PR_STDOUT, "******* Redundant nickname/email *******\n\n"); michael@0: PR_fprintf(PR_STDOUT, "These certs have the same nickname/email:\n"); michael@0: for (i=0; ipromptUser[errtype] = PR_FALSE; michael@0: info->removeType[errtype] = PR_TRUE; michael@0: return PR_TRUE; michael@0: } michael@0: getCertsToDelete(response, nb, certNums, nCerts); michael@0: return PR_TRUE; michael@0: } michael@0: /* User doesn't want to be prompted for this type anymore. */ michael@0: if (response[0] == 'Y') { michael@0: info->promptUser[errtype] = PR_FALSE; michael@0: info->removeType[errtype] = PR_FALSE; michael@0: return PR_FALSE; michael@0: } else if (response[0] == 'N') { michael@0: info->promptUser[errtype] = PR_FALSE; michael@0: info->removeType[errtype] = PR_TRUE; michael@0: return PR_TRUE; michael@0: } michael@0: return (response[0] != 'y') ? PR_TRUE : PR_FALSE; michael@0: } michael@0: michael@0: SECStatus michael@0: addCertToDB(certDBEntryCert *certEntry, dbRestoreInfo *info, michael@0: NSSLOWCERTCertDBHandle *oldhandle) michael@0: { michael@0: SECStatus rv = SECSuccess; michael@0: PRBool allowOverride; michael@0: PRBool userCert; michael@0: SECCertTimeValidity validity; michael@0: CERTCertificate *oldCert = NULL; michael@0: CERTCertificate *dbCert = NULL; michael@0: CERTCertificate *newCert = NULL; michael@0: CERTCertTrust *trust; michael@0: certDBEntrySMime *smimeEntry = NULL; michael@0: char *email = NULL; michael@0: char *nickname = NULL; michael@0: int nCertsForSubject = 1; michael@0: michael@0: oldCert = CERT_DecodeDERCertificate(&certEntry->derCert, PR_FALSE, michael@0: certEntry->nickname); michael@0: if (!oldCert) { michael@0: info->dbErrors[dbBadCertificate]++; michael@0: SEC_DestroyDBEntry((certDBEntry*)certEntry); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: oldCert->dbEntry = certEntry; michael@0: oldCert->trust = &certEntry->trust; michael@0: oldCert->dbhandle = oldhandle; michael@0: michael@0: trust = oldCert->trust; michael@0: michael@0: info->nOldCerts++; michael@0: michael@0: if (info->verbose) michael@0: PR_fprintf(info->out, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n"); michael@0: michael@0: if (oldCert->nickname) michael@0: nickname = PORT_Strdup(oldCert->nickname); michael@0: michael@0: /* Always keep user certs. Skip ahead. */ michael@0: /* XXX if someone sends themselves a signed message, it is possible michael@0: for their cert to be imported as an "other" cert, not a user cert. michael@0: this mucks with smime entries... */ michael@0: userCert = (SEC_GET_TRUST_FLAGS(trust, trustSSL) & CERTDB_USER) || michael@0: (SEC_GET_TRUST_FLAGS(trust, trustEmail) & CERTDB_USER) || michael@0: (SEC_GET_TRUST_FLAGS(trust, trustObjectSigning) & CERTDB_USER); michael@0: if (userCert) michael@0: goto createcert; michael@0: michael@0: /* If user chooses so, ignore expired certificates. */ michael@0: allowOverride = (PRBool)((oldCert->keyUsage == certUsageSSLServer) || michael@0: (oldCert->keyUsage == certUsageSSLServerWithStepUp)); michael@0: validity = CERT_CheckCertValidTimes(oldCert, PR_Now(), allowOverride); michael@0: /* If cert expired and user wants to delete it, ignore it. */ michael@0: if ((validity != secCertTimeValid) && michael@0: userSaysDeleteCert(&oldCert, 1, dbInvalidCert, info, 0)) { michael@0: info->dbErrors[dbInvalidCert]++; michael@0: if (info->verbose) { michael@0: PR_fprintf(info->out, "Deleting expired certificate:\n"); michael@0: dumpCertificate(oldCert, -1, info->out); michael@0: } michael@0: goto cleanup; michael@0: } michael@0: michael@0: /* New database will already have default certs, don't attempt michael@0: to overwrite them. */ michael@0: dbCert = CERT_FindCertByDERCert(info->handle, &oldCert->derCert); michael@0: if (dbCert) { michael@0: info->nCerts++; michael@0: if (info->verbose) { michael@0: PR_fprintf(info->out, "Added certificate to database:\n"); michael@0: dumpCertificate(oldCert, -1, info->out); michael@0: } michael@0: goto cleanup; michael@0: } michael@0: michael@0: /* Determine if cert is S/MIME and get its email if so. */ michael@0: email = IsEmailCert(oldCert); michael@0: michael@0: /* michael@0: XXX Just create empty profiles? michael@0: if (email) { michael@0: SECItem *profile = CERT_FindSMimeProfile(oldCert); michael@0: if (!profile && michael@0: userSaysDeleteCert(&oldCert, 1, dbNoSMimeProfile, info, 0)) { michael@0: info->dbErrors[dbNoSMimeProfile]++; michael@0: if (info->verbose) { michael@0: PR_fprintf(info->out, michael@0: "Deleted cert missing S/MIME profile.\n"); michael@0: dumpCertificate(oldCert, -1, info->out); michael@0: } michael@0: goto cleanup; michael@0: } else { michael@0: SECITEM_FreeItem(profile); michael@0: } michael@0: } michael@0: */ michael@0: michael@0: createcert: michael@0: michael@0: /* Sometimes happens... */ michael@0: if (!nickname && userCert) michael@0: nickname = PORT_Strdup(oldCert->subjectName); michael@0: michael@0: /* Create a new certificate, copy of the old one. */ michael@0: newCert = CERT_NewTempCertificate(info->handle, &oldCert->derCert, michael@0: nickname, PR_FALSE, PR_TRUE); michael@0: if (!newCert) { michael@0: PR_fprintf(PR_STDERR, "Unable to create new certificate.\n"); michael@0: dumpCertificate(oldCert, -1, PR_STDERR); michael@0: info->dbErrors[dbBadCertificate]++; michael@0: goto cleanup; michael@0: } michael@0: michael@0: /* Add the cert to the new database. */ michael@0: rv = CERT_AddTempCertToPerm(newCert, nickname, oldCert->trust); michael@0: if (rv) { michael@0: PR_fprintf(PR_STDERR, "Failed to write temp cert to perm database.\n"); michael@0: dumpCertificate(oldCert, -1, PR_STDERR); michael@0: info->dbErrors[dbCertNotWrittenToDB]++; michael@0: goto cleanup; michael@0: } michael@0: michael@0: if (info->verbose) { michael@0: PR_fprintf(info->out, "Added certificate to database:\n"); michael@0: dumpCertificate(oldCert, -1, info->out); michael@0: } michael@0: michael@0: /* If the cert is an S/MIME cert, and the first with it's subject, michael@0: * modify the subject entry to include the email address, michael@0: * CERT_AddTempCertToPerm does not do email addresses and S/MIME entries. michael@0: */ michael@0: if (smimeEntry) { /*&& !userCert && nCertsForSubject == 1) { */ michael@0: #if 0 michael@0: UpdateSubjectWithEmailAddr(newCert, email); michael@0: #endif michael@0: SECItem emailProfile, profileTime; michael@0: rv = CERT_FindFullSMimeProfile(oldCert, &emailProfile, &profileTime); michael@0: /* calls UpdateSubjectWithEmailAddr */ michael@0: if (rv == SECSuccess) michael@0: rv = CERT_SaveSMimeProfile(newCert, &emailProfile, &profileTime); michael@0: } michael@0: michael@0: info->nCerts++; michael@0: michael@0: cleanup: michael@0: michael@0: if (nickname) michael@0: PORT_Free(nickname); michael@0: if (email) michael@0: PORT_Free(email); michael@0: if (oldCert) michael@0: CERT_DestroyCertificate(oldCert); michael@0: if (dbCert) michael@0: CERT_DestroyCertificate(dbCert); michael@0: if (newCert) michael@0: CERT_DestroyCertificate(newCert); michael@0: if (smimeEntry) michael@0: SEC_DestroyDBEntry((certDBEntry*)smimeEntry); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: #if 0 michael@0: SECStatus michael@0: copyDBEntry(SECItem *data, SECItem *key, certDBEntryType type, void *pdata) michael@0: { michael@0: SECStatus rv; michael@0: NSSLOWCERTCertDBHandle *newdb = (NSSLOWCERTCertDBHandle *)pdata; michael@0: certDBEntryCommon common; michael@0: SECItem dbkey; michael@0: michael@0: common.type = type; michael@0: common.version = CERT_DB_FILE_VERSION; michael@0: common.flags = data->data[2]; michael@0: common.arena = NULL; michael@0: michael@0: dbkey.len = key->len + SEC_DB_KEY_HEADER_LEN; michael@0: dbkey.data = (unsigned char *)PORT_Alloc(dbkey.len*sizeof(unsigned char)); michael@0: PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], key->data, key->len); michael@0: dbkey.data[0] = type; michael@0: michael@0: rv = WriteDBEntry(newdb, &common, &dbkey, data); michael@0: michael@0: PORT_Free(dbkey.data); michael@0: return rv; michael@0: } michael@0: #endif michael@0: michael@0: int michael@0: certIsOlder(CERTCertificate **cert1, CERTCertificate** cert2) michael@0: { michael@0: return !CERT_IsNewer(*cert1, *cert2); michael@0: } michael@0: michael@0: int michael@0: findNewestSubjectForEmail(NSSLOWCERTCertDBHandle *handle, int subjectNum, michael@0: certDBArray *dbArray, dbRestoreInfo *info, michael@0: int *subjectWithSMime, int *smimeForSubject) michael@0: { michael@0: int newestSubject; michael@0: int subjectsForEmail[50]; michael@0: int i, j, ns, sNum; michael@0: certDBEntryListNode *subjects = &dbArray->subjects; michael@0: certDBEntryListNode *smime = &dbArray->smime; michael@0: certDBEntrySubject *subjectEntry1, *subjectEntry2; michael@0: certDBEntrySMime *smimeEntry; michael@0: CERTCertificate **certs; michael@0: CERTCertificate *cert; michael@0: CERTCertTrust *trust; michael@0: PRBool userCert; michael@0: int *certNums; michael@0: michael@0: ns = 0; michael@0: subjectEntry1 = (certDBEntrySubject*)&subjects.entries[subjectNum]; michael@0: subjectsForEmail[ns++] = subjectNum; michael@0: michael@0: *subjectWithSMime = -1; michael@0: *smimeForSubject = -1; michael@0: newestSubject = subjectNum; michael@0: michael@0: cert = CERT_FindCertByKey(handle, &subjectEntry1->certKeys[0]); michael@0: if (cert) { michael@0: trust = cert->trust; michael@0: userCert = (SEC_GET_TRUST_FLAGS(trust, trustSSL) & CERTDB_USER) || michael@0: (SEC_GET_TRUST_FLAGS(trust, trustEmail) & CERTDB_USER) || michael@0: (SEC_GET_TRUST_FLAGS(trust, trustObjectSigning) & CERTDB_USER); michael@0: CERT_DestroyCertificate(cert); michael@0: } michael@0: michael@0: /* michael@0: * XXX Should we make sure that subjectEntry1->emailAddr is not michael@0: * a null pointer or an empty string before going into the next michael@0: * two for loops, which pass it to PORT_Strcmp? michael@0: */ michael@0: michael@0: /* Loop over the remaining subjects. */ michael@0: for (i=subjectNum+1; iemailAddr && subjectEntry2->emailAddr[0] && michael@0: PORT_Strcmp(subjectEntry1->emailAddr, michael@0: subjectEntry2->emailAddr) == 0) { michael@0: /* Found a subject using the same email address. */ michael@0: subjectsForEmail[ns++] = i; michael@0: } michael@0: } michael@0: michael@0: /* Find the S/MIME entry for this email address. */ michael@0: for (i=0; icommon.arena == NULL) michael@0: continue; michael@0: if (smimeEntry->emailAddr && smimeEntry->emailAddr[0] && michael@0: PORT_Strcmp(subjectEntry1->emailAddr, smimeEntry->emailAddr) == 0) { michael@0: /* Find which of the subjects uses this S/MIME entry. */ michael@0: for (j=0; jsubjectName, michael@0: &subjectEntry2->derSubject)) { michael@0: /* Found the subject corresponding to the S/MIME entry. */ michael@0: *subjectWithSMime = sNum; michael@0: *smimeForSubject = i; michael@0: } michael@0: } michael@0: SEC_DestroyDBEntry((certDBEntry*)smimeEntry); michael@0: PORT_Memset(smimeEntry, 0, sizeof(certDBEntry)); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (ns <= 1) michael@0: return subjectNum; michael@0: michael@0: if (userCert) michael@0: return *subjectWithSMime; michael@0: michael@0: /* Now find which of the subjects has the newest cert. */ michael@0: certs = (CERTCertificate**)PORT_Alloc(ns*sizeof(CERTCertificate*)); michael@0: certNums = (int*)PORT_Alloc((ns+1)*sizeof(int)); michael@0: certNums[0] = 0; michael@0: for (i=0; icertKeys[0]); michael@0: certNums[i+1] = i; michael@0: } michael@0: /* Sort the array by validity. */ michael@0: qsort(certs, ns, sizeof(CERTCertificate*), michael@0: (int (*)(const void *, const void *))certIsOlder); michael@0: newestSubject = -1; michael@0: for (i=0; iderSubject, michael@0: &certs[0]->derSubject)) michael@0: newestSubject = sNum; michael@0: else michael@0: SEC_DestroyDBEntry((certDBEntry*)subjectEntry1); michael@0: } michael@0: if (info && userSaysDeleteCert(certs, ns, dbOlderCert, info, certNums)) { michael@0: for (i=1; i= 0 && certNums[i] != certNums[0]) { michael@0: deleteAllEntriesForCert(handle, certs[certNums[i]], info->out); michael@0: info->dbErrors[dbOlderCert]++; michael@0: } michael@0: } michael@0: } michael@0: CERT_DestroyCertArray(certs, ns); michael@0: return newestSubject; michael@0: } michael@0: michael@0: NSSLOWCERTCertDBHandle * michael@0: DBCK_ReconstructDBFromCerts(NSSLOWCERTCertDBHandle *oldhandle, char *newdbname, michael@0: PRFileDesc *outfile, PRBool removeExpired, michael@0: PRBool requireProfile, PRBool singleEntry, michael@0: PRBool promptUser) michael@0: { michael@0: SECStatus rv; michael@0: dbRestoreInfo info; michael@0: certDBEntryContentVersion *oldContentVersion; michael@0: certDBArray dbArray; michael@0: int i; michael@0: michael@0: PORT_Memset(&dbArray, 0, sizeof(dbArray)); michael@0: PORT_Memset(&info, 0, sizeof(info)); michael@0: info.verbose = (outfile) ? PR_TRUE : PR_FALSE; michael@0: info.out = (outfile) ? outfile : PR_STDOUT; michael@0: info.removeType[dbInvalidCert] = removeExpired; michael@0: info.removeType[dbNoSMimeProfile] = requireProfile; michael@0: info.removeType[dbOlderCert] = singleEntry; michael@0: info.promptUser[dbInvalidCert] = promptUser; michael@0: info.promptUser[dbNoSMimeProfile] = promptUser; michael@0: info.promptUser[dbOlderCert] = promptUser; michael@0: michael@0: /* Allocate a handle to fill with CERT_OpenCertDB below. */ michael@0: info.handle = PORT_ZNew(NSSLOWCERTCertDBHandle); michael@0: if (!info.handle) { michael@0: fprintf(stderr, "unable to get database handle"); michael@0: return NULL; michael@0: } michael@0: michael@0: /* Create a certdb with the most recent set of roots. */ michael@0: rv = CERT_OpenCertDBFilename(info.handle, newdbname, PR_FALSE); michael@0: michael@0: if (rv) { michael@0: fprintf(stderr, "could not open certificate database"); michael@0: goto loser; michael@0: } michael@0: michael@0: /* Create certificate, subject, nickname, and email records. michael@0: * mcom_db seems to have a sequential access bug. Though reads and writes michael@0: * should be allowed during traversal, they seem to screw up the sequence. michael@0: * So, stuff all the cert entries into an array, and loop over the array michael@0: * doing read/writes in the db. michael@0: */ michael@0: fillDBEntryArray(oldhandle, certDBEntryTypeCert, &dbArray.certs); michael@0: for (elem = PR_LIST_HEAD(&dbArray->certs.link); michael@0: elem != &dbArray->certs.link; elem = PR_NEXT_LINK(elem)) { michael@0: node = LISTNODE_CAST(elem); michael@0: addCertToDB((certDBEntryCert*)&node->entry, &info, oldhandle); michael@0: /* entries get destroyed in addCertToDB */ michael@0: } michael@0: #if 0 michael@0: rv = nsslowcert_TraverseDBEntries(oldhandle, certDBEntryTypeSMimeProfile, michael@0: copyDBEntry, info.handle); michael@0: #endif michael@0: michael@0: /* Fix up the pointers between (nickname|S/MIME) --> (subject). michael@0: * Create S/MIME entries for S/MIME certs. michael@0: * Have the S/MIME entry point to the last-expiring cert using michael@0: * an email address. michael@0: */ michael@0: #if 0 michael@0: CERT_RedoHandlesForSubjects(info.handle, singleEntry, &info); michael@0: #endif michael@0: michael@0: freeDBEntryList(&dbArray.certs.link); michael@0: michael@0: /* Copy over the version record. */ michael@0: /* XXX Already exists - and _must_ be correct... */ michael@0: /* michael@0: versionEntry = ReadDBVersionEntry(oldhandle); michael@0: rv = WriteDBVersionEntry(info.handle, versionEntry); michael@0: */ michael@0: michael@0: /* Copy over the content version record. */ michael@0: /* XXX Can probably get useful info from old content version? michael@0: * Was this db created before/after this tool? etc. michael@0: */ michael@0: #if 0 michael@0: oldContentVersion = ReadDBContentVersionEntry(oldhandle); michael@0: CERT_SetDBContentVersion(oldContentVersion->contentVersion, info.handle); michael@0: #endif michael@0: michael@0: #if 0 michael@0: /* Copy over the CRL & KRL records. */ michael@0: rv = nsslowcert_TraverseDBEntries(oldhandle, certDBEntryTypeRevocation, michael@0: copyDBEntry, info.handle); michael@0: /* XXX Only one KRL, just do db->get? */ michael@0: rv = nsslowcert_TraverseDBEntries(oldhandle, certDBEntryTypeKeyRevocation, michael@0: copyDBEntry, info.handle); michael@0: #endif michael@0: michael@0: PR_fprintf(info.out, "Database had %d certificates.\n", info.nOldCerts); michael@0: michael@0: PR_fprintf(info.out, "Reconstructed %d certificates.\n", info.nCerts); michael@0: PR_fprintf(info.out, "(ax) Rejected %d expired certificates.\n", michael@0: info.dbErrors[dbInvalidCert]); michael@0: PR_fprintf(info.out, "(as) Rejected %d S/MIME certificates missing a profile.\n", michael@0: info.dbErrors[dbNoSMimeProfile]); michael@0: PR_fprintf(info.out, "(ar) Rejected %d certificates for which a newer certificate was found.\n", michael@0: info.dbErrors[dbOlderCert]); michael@0: PR_fprintf(info.out, " Rejected %d corrupt certificates.\n", michael@0: info.dbErrors[dbBadCertificate]); michael@0: PR_fprintf(info.out, " Rejected %d certificates which did not write to the DB.\n", michael@0: info.dbErrors[dbCertNotWrittenToDB]); michael@0: michael@0: if (rv) michael@0: goto loser; michael@0: michael@0: return info.handle; michael@0: michael@0: loser: michael@0: if (info.handle) michael@0: PORT_Free(info.handle); michael@0: return NULL; michael@0: } michael@0: