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