dbrecover.c (23369B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 enum { 6 dbInvalidCert = 0, 7 dbNoSMimeProfile, 8 dbOlderCert, 9 dbBadCertificate, 10 dbCertNotWrittenToDB 11 }; 12 13 typedef struct dbRestoreInfoStr { 14 NSSLOWCERTCertDBHandle *handle; 15 PRBool verbose; 16 PRFileDesc *out; 17 int nCerts; 18 int nOldCerts; 19 int dbErrors[5]; 20 PRBool removeType[3]; 21 PRBool promptUser[3]; 22 } dbRestoreInfo; 23 24 char * 25 IsEmailCert(CERTCertificate *cert) 26 { 27 char *email, *tmp1, *tmp2; 28 PRBool isCA; 29 int len; 30 31 if (!cert->subjectName) { 32 return NULL; 33 } 34 35 tmp1 = PORT_Strstr(cert->subjectName, "E="); 36 tmp2 = PORT_Strstr(cert->subjectName, "MAIL="); 37 /* XXX Nelson has cert for KTrilli which does not have either 38 * of above but is email cert (has cert->emailAddr). 39 */ 40 if (!tmp1 && !tmp2 && !(cert->emailAddr && cert->emailAddr[0])) { 41 return NULL; 42 } 43 44 /* Server or CA cert, not personal email. */ 45 isCA = CERT_IsCACert(cert, NULL); 46 if (isCA) 47 return NULL; 48 49 /* XXX CERT_IsCACert advertises checking the key usage ext., 50 but doesn't appear to. */ 51 /* Check the key usage extension. */ 52 if (cert->keyUsagePresent) { 53 /* Must at least be able to sign or encrypt (not neccesarily 54 * both if it is one of a dual cert). 55 */ 56 if (!((cert->rawKeyUsage & KU_DIGITAL_SIGNATURE) || 57 (cert->rawKeyUsage & KU_KEY_ENCIPHERMENT))) 58 return NULL; 59 60 /* CA cert, not personal email. */ 61 if (cert->rawKeyUsage & (KU_KEY_CERT_SIGN | KU_CRL_SIGN)) 62 return NULL; 63 } 64 65 if (cert->emailAddr && cert->emailAddr[0]) { 66 email = PORT_Strdup(cert->emailAddr); 67 } else { 68 if (tmp1) 69 tmp1 += 2; /* "E=" */ 70 else 71 tmp1 = tmp2 + 5; /* "MAIL=" */ 72 len = strcspn(tmp1, ", "); 73 email = (char *)PORT_Alloc(len + 1); 74 PORT_Strncpy(email, tmp1, len); 75 email[len] = '\0'; 76 } 77 78 return email; 79 } 80 81 SECStatus 82 deleteit(CERTCertificate *cert, void *arg) 83 { 84 return SEC_DeletePermCertificate(cert); 85 } 86 87 /* Different than DeleteCertificate - has the added bonus of removing 88 * all certs with the same DN. 89 */ 90 SECStatus 91 deleteAllEntriesForCert(NSSLOWCERTCertDBHandle *handle, CERTCertificate *cert, 92 PRFileDesc *outfile) 93 { 94 #if 0 95 certDBEntrySubject *subjectEntry; 96 certDBEntryNickname *nicknameEntry; 97 certDBEntrySMime *smimeEntry; 98 int i; 99 #endif 100 101 if (outfile) { 102 PR_fprintf(outfile, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n\n"); 103 PR_fprintf(outfile, "Deleting redundant certificate:\n"); 104 dumpCertificate(cert, -1, outfile); 105 } 106 107 CERT_TraverseCertsForSubject(handle, cert->subjectList, deleteit, NULL); 108 #if 0 109 CERT_LockDB(handle); 110 subjectEntry = ReadDBSubjectEntry(handle, &cert->derSubject); 111 /* It had better be there, or created a bad db. */ 112 PORT_Assert(subjectEntry); 113 for (i=0; i<subjectEntry->ncerts; i++) { 114 DeleteDBCertEntry(handle, &subjectEntry->certKeys[i]); 115 } 116 DeleteDBSubjectEntry(handle, &cert->derSubject); 117 if (subjectEntry->emailAddr && subjectEntry->emailAddr[0]) { 118 smimeEntry = ReadDBSMimeEntry(handle, subjectEntry->emailAddr); 119 if (smimeEntry) { 120 if (SECITEM_ItemsAreEqual(&subjectEntry->derSubject, 121 &smimeEntry->subjectName)) 122 /* Only delete it if it's for this subject! */ 123 DeleteDBSMimeEntry(handle, subjectEntry->emailAddr); 124 SEC_DestroyDBEntry((certDBEntry*)smimeEntry); 125 } 126 } 127 if (subjectEntry->nickname) { 128 nicknameEntry = ReadDBNicknameEntry(handle, subjectEntry->nickname); 129 if (nicknameEntry) { 130 if (SECITEM_ItemsAreEqual(&subjectEntry->derSubject, 131 &nicknameEntry->subjectName)) 132 /* Only delete it if it's for this subject! */ 133 DeleteDBNicknameEntry(handle, subjectEntry->nickname); 134 SEC_DestroyDBEntry((certDBEntry*)nicknameEntry); 135 } 136 } 137 SEC_DestroyDBEntry((certDBEntry*)subjectEntry); 138 CERT_UnlockDB(handle); 139 #endif 140 return SECSuccess; 141 } 142 143 void 144 getCertsToDelete(char *numlist, int len, int *certNums, int nCerts) 145 { 146 int j, num; 147 char *numstr, *numend, *end; 148 149 numstr = numlist; 150 end = numstr + len - 1; 151 while (numstr != end) { 152 numend = strpbrk(numstr, ", \n"); 153 *numend = '\0'; 154 if (PORT_Strlen(numstr) == 0) 155 return; 156 num = PORT_Atoi(numstr); 157 if (numstr == numlist) 158 certNums[0] = num; 159 for (j = 1; j < nCerts + 1; j++) { 160 if (num == certNums[j]) { 161 certNums[j] = -1; 162 break; 163 } 164 } 165 if (numend == end) 166 break; 167 numstr = strpbrk(numend + 1, "0123456789"); 168 } 169 } 170 171 PRBool 172 userSaysDeleteCert(CERTCertificate **certs, int nCerts, 173 int errtype, dbRestoreInfo *info, int *certNums) 174 { 175 char response[32]; 176 PRInt32 nb; 177 int i; 178 /* User wants to remove cert without prompting. */ 179 if (info->promptUser[errtype] == PR_FALSE) 180 return (info->removeType[errtype]); 181 switch (errtype) { 182 case dbInvalidCert: 183 PR_fprintf(PR_STDOUT, "******** Expired ********\n"); 184 PR_fprintf(PR_STDOUT, "Cert has expired.\n\n"); 185 dumpCertificate(certs[0], -1, PR_STDOUT); 186 PR_fprintf(PR_STDOUT, 187 "Keep it? (y/n - this one, Y/N - all expired certs) [n] "); 188 break; 189 case dbNoSMimeProfile: 190 PR_fprintf(PR_STDOUT, "******** No Profile ********\n"); 191 PR_fprintf(PR_STDOUT, "S/MIME cert has no profile.\n\n"); 192 dumpCertificate(certs[0], -1, PR_STDOUT); 193 PR_fprintf(PR_STDOUT, 194 "Keep it? (y/n - this one, Y/N - all S/MIME w/o profile) [n] "); 195 break; 196 case dbOlderCert: 197 PR_fprintf(PR_STDOUT, "******* Redundant nickname/email *******\n\n"); 198 PR_fprintf(PR_STDOUT, "These certs have the same nickname/email:\n"); 199 for (i = 0; i < nCerts; i++) 200 dumpCertificate(certs[i], i, PR_STDOUT); 201 PR_fprintf(PR_STDOUT, 202 "Enter the certs you would like to keep from those listed above.\n"); 203 PR_fprintf(PR_STDOUT, 204 "Use a comma-separated list of the cert numbers (ex. 0, 8, 12).\n"); 205 PR_fprintf(PR_STDOUT, 206 "The first cert in the list will be the primary cert\n"); 207 PR_fprintf(PR_STDOUT, 208 " accessed by the nickname/email handle.\n"); 209 PR_fprintf(PR_STDOUT, 210 "List cert numbers to keep here, or hit enter\n"); 211 PR_fprintf(PR_STDOUT, 212 " to always keep only the newest cert: "); 213 break; 214 default: 215 } 216 nb = PR_Read(PR_STDIN, response, sizeof(response)); 217 PR_fprintf(PR_STDOUT, "\n\n"); 218 if (errtype == dbOlderCert) { 219 if (!isdigit((unsigned char)response[0])) { 220 info->promptUser[errtype] = PR_FALSE; 221 info->removeType[errtype] = PR_TRUE; 222 return PR_TRUE; 223 } 224 getCertsToDelete(response, nb, certNums, nCerts); 225 return PR_TRUE; 226 } 227 /* User doesn't want to be prompted for this type anymore. */ 228 if (response[0] == 'Y') { 229 info->promptUser[errtype] = PR_FALSE; 230 info->removeType[errtype] = PR_FALSE; 231 return PR_FALSE; 232 } else if (response[0] == 'N') { 233 info->promptUser[errtype] = PR_FALSE; 234 info->removeType[errtype] = PR_TRUE; 235 return PR_TRUE; 236 } 237 return (response[0] != 'y') ? PR_TRUE : PR_FALSE; 238 } 239 240 SECStatus 241 addCertToDB(certDBEntryCert *certEntry, dbRestoreInfo *info, 242 NSSLOWCERTCertDBHandle *oldhandle) 243 { 244 SECStatus rv = SECSuccess; 245 PRBool allowOverride; 246 PRBool userCert; 247 SECCertTimeValidity validity; 248 CERTCertificate *oldCert = NULL; 249 CERTCertificate *dbCert = NULL; 250 CERTCertificate *newCert = NULL; 251 CERTCertTrust *trust; 252 certDBEntrySMime *smimeEntry = NULL; 253 char *email = NULL; 254 char *nickname = NULL; 255 int nCertsForSubject = 1; 256 257 oldCert = CERT_DecodeDERCertificate(&certEntry->derCert, PR_FALSE, 258 certEntry->nickname); 259 if (!oldCert) { 260 info->dbErrors[dbBadCertificate]++; 261 SEC_DestroyDBEntry((certDBEntry *)certEntry); 262 return SECSuccess; 263 } 264 265 oldCert->dbEntry = certEntry; 266 oldCert->trust = &certEntry->trust; 267 oldCert->dbhandle = oldhandle; 268 269 trust = oldCert->trust; 270 271 info->nOldCerts++; 272 273 if (info->verbose) 274 PR_fprintf(info->out, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n"); 275 276 if (oldCert->nickname) 277 nickname = PORT_Strdup(oldCert->nickname); 278 279 /* Always keep user certs. Skip ahead. */ 280 /* XXX if someone sends themselves a signed message, it is possible 281 for their cert to be imported as an "other" cert, not a user cert. 282 this mucks with smime entries... */ 283 userCert = (SEC_GET_TRUST_FLAGS(trust, trustSSL) & CERTDB_USER) || 284 (SEC_GET_TRUST_FLAGS(trust, trustEmail) & CERTDB_USER) || 285 (SEC_GET_TRUST_FLAGS(trust, trustObjectSigning) & CERTDB_USER); 286 if (userCert) 287 goto createcert; 288 289 /* If user chooses so, ignore expired certificates. */ 290 allowOverride = (PRBool)((oldCert->keyUsage == certUsageSSLServer) || 291 (oldCert->keyUsage == certUsageSSLServerWithStepUp) || 292 (oldCert->keyUsage == certUsageIPsec)); 293 validity = CERT_CheckCertValidTimes(oldCert, PR_Now(), allowOverride); 294 /* If cert expired and user wants to delete it, ignore it. */ 295 if ((validity != secCertTimeValid) && 296 userSaysDeleteCert(&oldCert, 1, dbInvalidCert, info, 0)) { 297 info->dbErrors[dbInvalidCert]++; 298 if (info->verbose) { 299 PR_fprintf(info->out, "Deleting expired certificate:\n"); 300 dumpCertificate(oldCert, -1, info->out); 301 } 302 goto cleanup; 303 } 304 305 /* New database will already have default certs, don't attempt 306 to overwrite them. */ 307 dbCert = CERT_FindCertByDERCert(info->handle, &oldCert->derCert); 308 if (dbCert) { 309 info->nCerts++; 310 if (info->verbose) { 311 PR_fprintf(info->out, "Added certificate to database:\n"); 312 dumpCertificate(oldCert, -1, info->out); 313 } 314 goto cleanup; 315 } 316 317 /* Determine if cert is S/MIME and get its email if so. */ 318 email = IsEmailCert(oldCert); 319 320 /* 321 XXX Just create empty profiles? 322 if (email) { 323 SECItem *profile = CERT_FindSMimeProfile(oldCert); 324 if (!profile && 325 userSaysDeleteCert(&oldCert, 1, dbNoSMimeProfile, info, 0)) { 326 info->dbErrors[dbNoSMimeProfile]++; 327 if (info->verbose) { 328 PR_fprintf(info->out, 329 "Deleted cert missing S/MIME profile.\n"); 330 dumpCertificate(oldCert, -1, info->out); 331 } 332 goto cleanup; 333 } else { 334 SECITEM_FreeItem(profile); 335 } 336 } 337 */ 338 339 createcert: 340 341 /* Sometimes happens... */ 342 if (!nickname && userCert) 343 nickname = PORT_Strdup(oldCert->subjectName); 344 345 /* Create a new certificate, copy of the old one. */ 346 newCert = CERT_NewTempCertificate(info->handle, &oldCert->derCert, 347 nickname, PR_FALSE, PR_TRUE); 348 if (!newCert) { 349 PR_fprintf(PR_STDERR, "Unable to create new certificate.\n"); 350 dumpCertificate(oldCert, -1, PR_STDERR); 351 info->dbErrors[dbBadCertificate]++; 352 goto cleanup; 353 } 354 355 /* Add the cert to the new database. */ 356 rv = CERT_AddTempCertToPerm(newCert, nickname, oldCert->trust); 357 if (rv) { 358 PR_fprintf(PR_STDERR, "Failed to write temp cert to perm database.\n"); 359 dumpCertificate(oldCert, -1, PR_STDERR); 360 info->dbErrors[dbCertNotWrittenToDB]++; 361 goto cleanup; 362 } 363 364 if (info->verbose) { 365 PR_fprintf(info->out, "Added certificate to database:\n"); 366 dumpCertificate(oldCert, -1, info->out); 367 } 368 369 /* If the cert is an S/MIME cert, and the first with it's subject, 370 * modify the subject entry to include the email address, 371 * CERT_AddTempCertToPerm does not do email addresses and S/MIME entries. 372 */ 373 if (smimeEntry) { /*&& !userCert && nCertsForSubject == 1) { */ 374 #if 0 375 UpdateSubjectWithEmailAddr(newCert, email); 376 #endif 377 SECItem emailProfile, profileTime; 378 rv = CERT_FindFullSMimeProfile(oldCert, &emailProfile, &profileTime); 379 /* calls UpdateSubjectWithEmailAddr */ 380 if (rv == SECSuccess) 381 rv = CERT_SaveSMimeProfile(newCert, &emailProfile, &profileTime); 382 } 383 384 info->nCerts++; 385 386 cleanup: 387 388 if (nickname) 389 PORT_Free(nickname); 390 if (email) 391 PORT_Free(email); 392 if (oldCert) 393 CERT_DestroyCertificate(oldCert); 394 if (dbCert) 395 CERT_DestroyCertificate(dbCert); 396 if (newCert) 397 CERT_DestroyCertificate(newCert); 398 if (smimeEntry) 399 SEC_DestroyDBEntry((certDBEntry *)smimeEntry); 400 return SECSuccess; 401 } 402 403 #if 0 404 SECStatus 405 copyDBEntry(SECItem *data, SECItem *key, certDBEntryType type, void *pdata) 406 { 407 SECStatus rv; 408 NSSLOWCERTCertDBHandle *newdb = (NSSLOWCERTCertDBHandle *)pdata; 409 certDBEntryCommon common; 410 SECItem dbkey; 411 412 common.type = type; 413 common.version = CERT_DB_FILE_VERSION; 414 common.flags = data->data[2]; 415 common.arena = NULL; 416 417 dbkey.len = key->len + SEC_DB_KEY_HEADER_LEN; 418 dbkey.data = (unsigned char *)PORT_Alloc(dbkey.len*sizeof(unsigned char)); 419 PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], key->data, key->len); 420 dbkey.data[0] = type; 421 422 rv = WriteDBEntry(newdb, &common, &dbkey, data); 423 424 PORT_Free(dbkey.data); 425 return rv; 426 } 427 #endif 428 429 int 430 certIsOlder(CERTCertificate **cert1, CERTCertificate **cert2) 431 { 432 return !CERT_IsNewer(*cert1, *cert2); 433 } 434 435 int 436 findNewestSubjectForEmail(NSSLOWCERTCertDBHandle *handle, int subjectNum, 437 certDBArray *dbArray, dbRestoreInfo *info, 438 int *subjectWithSMime, int *smimeForSubject) 439 { 440 int newestSubject; 441 int subjectsForEmail[50]; 442 int i, j, ns, sNum; 443 certDBEntryListNode *subjects = &dbArray->subjects; 444 certDBEntryListNode *smime = &dbArray->smime; 445 certDBEntrySubject *subjectEntry1, *subjectEntry2; 446 certDBEntrySMime *smimeEntry; 447 CERTCertificate **certs; 448 CERTCertificate *cert; 449 CERTCertTrust *trust; 450 PRBool userCert; 451 int *certNums; 452 453 ns = 0; 454 subjectEntry1 = (certDBEntrySubject *)&subjects.entries[subjectNum]; 455 subjectsForEmail[ns++] = subjectNum; 456 457 *subjectWithSMime = -1; 458 *smimeForSubject = -1; 459 newestSubject = subjectNum; 460 461 cert = CERT_FindCertByKey(handle, &subjectEntry1->certKeys[0]); 462 if (cert) { 463 trust = cert->trust; 464 userCert = (SEC_GET_TRUST_FLAGS(trust, trustSSL) & CERTDB_USER) || 465 (SEC_GET_TRUST_FLAGS(trust, trustEmail) & CERTDB_USER) || 466 (SEC_GET_TRUST_FLAGS(trust, trustObjectSigning) & CERTDB_USER); 467 CERT_DestroyCertificate(cert); 468 } 469 470 /* 471 * XXX Should we make sure that subjectEntry1->emailAddr is not 472 * a null pointer or an empty string before going into the next 473 * two for loops, which pass it to PORT_Strcmp? 474 */ 475 476 /* Loop over the remaining subjects. */ 477 for (i = subjectNum + 1; i < subjects.numEntries; i++) { 478 subjectEntry2 = (certDBEntrySubject *)&subjects.entries[i]; 479 if (!subjectEntry2) 480 continue; 481 if (subjectEntry2->emailAddr && subjectEntry2->emailAddr[0] && 482 PORT_Strcmp(subjectEntry1->emailAddr, 483 subjectEntry2->emailAddr) == 0) { 484 /* Found a subject using the same email address. */ 485 subjectsForEmail[ns++] = i; 486 } 487 } 488 489 /* Find the S/MIME entry for this email address. */ 490 for (i = 0; i < smime.numEntries; i++) { 491 smimeEntry = (certDBEntrySMime *)&smime.entries[i]; 492 if (smimeEntry->common.arena == NULL) 493 continue; 494 if (smimeEntry->emailAddr && smimeEntry->emailAddr[0] && 495 PORT_Strcmp(subjectEntry1->emailAddr, smimeEntry->emailAddr) == 0) { 496 /* Find which of the subjects uses this S/MIME entry. */ 497 for (j = 0; j < ns && *subjectWithSMime < 0; j++) { 498 sNum = subjectsForEmail[j]; 499 subjectEntry2 = (certDBEntrySubject *)&subjects.entries[sNum]; 500 if (SECITEM_ItemsAreEqual(&smimeEntry->subjectName, 501 &subjectEntry2->derSubject)) { 502 /* Found the subject corresponding to the S/MIME entry. */ 503 *subjectWithSMime = sNum; 504 *smimeForSubject = i; 505 } 506 } 507 SEC_DestroyDBEntry((certDBEntry *)smimeEntry); 508 PORT_Memset(smimeEntry, 0, sizeof(certDBEntry)); 509 break; 510 } 511 } 512 513 if (ns <= 1) 514 return subjectNum; 515 516 if (userCert) 517 return *subjectWithSMime; 518 519 /* Now find which of the subjects has the newest cert. */ 520 certs = (CERTCertificate **)PORT_Alloc(ns * sizeof(CERTCertificate *)); 521 certNums = (int *)PORT_Alloc((ns + 1) * sizeof(int)); 522 certNums[0] = 0; 523 for (i = 0; i < ns; i++) { 524 sNum = subjectsForEmail[i]; 525 subjectEntry1 = (certDBEntrySubject *)&subjects.entries[sNum]; 526 certs[i] = CERT_FindCertByKey(handle, &subjectEntry1->certKeys[0]); 527 certNums[i + 1] = i; 528 } 529 /* Sort the array by validity. */ 530 qsort(certs, ns, sizeof(CERTCertificate *), 531 (int (*)(const void *, const void *))certIsOlder); 532 newestSubject = -1; 533 for (i = 0; i < ns; i++) { 534 sNum = subjectsForEmail[i]; 535 subjectEntry1 = (certDBEntrySubject *)&subjects.entries[sNum]; 536 if (SECITEM_ItemsAreEqual(&subjectEntry1->derSubject, 537 &certs[0]->derSubject)) 538 newestSubject = sNum; 539 else 540 SEC_DestroyDBEntry((certDBEntry *)subjectEntry1); 541 } 542 if (info && userSaysDeleteCert(certs, ns, dbOlderCert, info, certNums)) { 543 for (i = 1; i < ns + 1; i++) { 544 if (certNums[i] >= 0 && certNums[i] != certNums[0]) { 545 deleteAllEntriesForCert(handle, certs[certNums[i]], info->out); 546 info->dbErrors[dbOlderCert]++; 547 } 548 } 549 } 550 CERT_DestroyCertArray(certs, ns); 551 return newestSubject; 552 } 553 554 NSSLOWCERTCertDBHandle * 555 DBCK_ReconstructDBFromCerts(NSSLOWCERTCertDBHandle *oldhandle, char *newdbname, 556 PRFileDesc *outfile, PRBool removeExpired, 557 PRBool requireProfile, PRBool singleEntry, 558 PRBool promptUser) 559 { 560 SECStatus rv; 561 dbRestoreInfo info; 562 certDBEntryContentVersion *oldContentVersion; 563 certDBArray dbArray; 564 int i; 565 566 PORT_Memset(&dbArray, 0, sizeof(dbArray)); 567 PORT_Memset(&info, 0, sizeof(info)); 568 info.verbose = (outfile) ? PR_TRUE : PR_FALSE; 569 info.out = (outfile) ? outfile : PR_STDOUT; 570 info.removeType[dbInvalidCert] = removeExpired; 571 info.removeType[dbNoSMimeProfile] = requireProfile; 572 info.removeType[dbOlderCert] = singleEntry; 573 info.promptUser[dbInvalidCert] = promptUser; 574 info.promptUser[dbNoSMimeProfile] = promptUser; 575 info.promptUser[dbOlderCert] = promptUser; 576 577 /* Allocate a handle to fill with CERT_OpenCertDB below. */ 578 info.handle = PORT_ZNew(NSSLOWCERTCertDBHandle); 579 if (!info.handle) { 580 fprintf(stderr, "unable to get database handle"); 581 return NULL; 582 } 583 584 /* Create a certdb with the most recent set of roots. */ 585 rv = CERT_OpenCertDBFilename(info.handle, newdbname, PR_FALSE); 586 587 if (rv) { 588 fprintf(stderr, "could not open certificate database"); 589 goto loser; 590 } 591 592 /* Create certificate, subject, nickname, and email records. 593 * mcom_db seems to have a sequential access bug. Though reads and writes 594 * should be allowed during traversal, they seem to screw up the sequence. 595 * So, stuff all the cert entries into an array, and loop over the array 596 * doing read/writes in the db. 597 */ 598 fillDBEntryArray(oldhandle, certDBEntryTypeCert, &dbArray.certs); 599 for (elem = PR_LIST_HEAD(&dbArray->certs.link); 600 elem != &dbArray->certs.link; elem = PR_NEXT_LINK(elem)) { 601 node = LISTNODE_CAST(elem); 602 addCertToDB((certDBEntryCert *)&node->entry, &info, oldhandle); 603 /* entries get destroyed in addCertToDB */ 604 } 605 #if 0 606 rv = nsslowcert_TraverseDBEntries(oldhandle, certDBEntryTypeSMimeProfile, 607 copyDBEntry, info.handle); 608 #endif 609 610 /* Fix up the pointers between (nickname|S/MIME) --> (subject). 611 * Create S/MIME entries for S/MIME certs. 612 * Have the S/MIME entry point to the last-expiring cert using 613 * an email address. 614 */ 615 #if 0 616 CERT_RedoHandlesForSubjects(info.handle, singleEntry, &info); 617 #endif 618 619 freeDBEntryList(&dbArray.certs.link); 620 621 /* Copy over the version record. */ 622 /* XXX Already exists - and _must_ be correct... */ 623 /* 624 versionEntry = ReadDBVersionEntry(oldhandle); 625 rv = WriteDBVersionEntry(info.handle, versionEntry); 626 */ 627 628 /* Copy over the content version record. */ 629 /* XXX Can probably get useful info from old content version? 630 * Was this db created before/after this tool? etc. 631 */ 632 #if 0 633 oldContentVersion = ReadDBContentVersionEntry(oldhandle); 634 CERT_SetDBContentVersion(oldContentVersion->contentVersion, info.handle); 635 #endif 636 637 #if 0 638 /* Copy over the CRL & KRL records. */ 639 rv = nsslowcert_TraverseDBEntries(oldhandle, certDBEntryTypeRevocation, 640 copyDBEntry, info.handle); 641 /* XXX Only one KRL, just do db->get? */ 642 rv = nsslowcert_TraverseDBEntries(oldhandle, certDBEntryTypeKeyRevocation, 643 copyDBEntry, info.handle); 644 #endif 645 646 PR_fprintf(info.out, "Database had %d certificates.\n", info.nOldCerts); 647 648 PR_fprintf(info.out, "Reconstructed %d certificates.\n", info.nCerts); 649 PR_fprintf(info.out, "(ax) Rejected %d expired certificates.\n", 650 info.dbErrors[dbInvalidCert]); 651 PR_fprintf(info.out, "(as) Rejected %d S/MIME certificates missing a profile.\n", 652 info.dbErrors[dbNoSMimeProfile]); 653 PR_fprintf(info.out, "(ar) Rejected %d certificates for which a newer certificate was found.\n", 654 info.dbErrors[dbOlderCert]); 655 PR_fprintf(info.out, " Rejected %d corrupt certificates.\n", 656 info.dbErrors[dbBadCertificate]); 657 PR_fprintf(info.out, " Rejected %d certificates which did not write to the DB.\n", 658 info.dbErrors[dbCertNotWrittenToDB]); 659 660 if (rv) 661 goto loser; 662 663 return info.handle; 664 665 loser: 666 if (info.handle) 667 PORT_Free(info.handle); 668 return NULL; 669 }