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
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.
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 ***** */
40 ** utility for fixing corrupt cert databases
57 static char *progName
;
59 /* placeholders for pointer error types */
60 static void *WrongEntry
;
61 static void *NoNickname
;
65 /* 0*/ NoSubjectForCert
= 0,
66 /* 1*/ SubjectHasNoKeyForCert
,
67 /* 2*/ NoNicknameOrSMimeForSubject
,
68 /* 3*/ WrongNicknameForSubject
,
69 /* 4*/ NoNicknameEntry
,
70 /* 5*/ WrongSMimeForSubject
,
72 /* 7*/ NoSubjectForNickname
,
73 /* 8*/ NoSubjectForSMime
,
74 /* 9*/ NicknameAndSMimeEntries
,
78 static char *dbErrorString
[NUM_ERROR_TYPES
] = {
79 /* 0*/ "<CERT ENTRY>\nDid not find a subject entry for this certificate.",
80 /* 1*/ "<SUBJECT ENTRY>\nSubject has certKey which is not in db.",
81 /* 2*/ "<SUBJECT ENTRY>\nSubject does not have a nickname or email address.",
82 /* 3*/ "<SUBJECT ENTRY>\nUsing this subject's nickname, found a nickname entry for a different subject.",
83 /* 4*/ "<SUBJECT ENTRY>\nDid not find a nickname entry for this subject.",
84 /* 5*/ "<SUBJECT ENTRY>\nUsing this subject's email, found an S/MIME entry for a different subject.",
85 /* 6*/ "<SUBJECT ENTRY>\nDid not find an S/MIME entry for this subject.",
86 /* 7*/ "<NICKNAME ENTRY>\nDid not find a subject entry for this nickname.",
87 /* 8*/ "<S/MIME ENTRY>\nDid not find a subject entry for this S/MIME profile.",
90 static char *errResult
[NUM_ERROR_TYPES
] = {
91 "Certificate entries that had no subject entry.",
92 "Subject entries with no corresponding Certificate entries.",
93 "Subject entries that had no nickname or S/MIME entries.",
94 "Redundant nicknames (subjects with the same nickname).",
95 "Subject entries that had no nickname entry.",
96 "Redundant email addresses (subjects with the same email address).",
97 "Subject entries that had no S/MIME entry.",
98 "Nickname entries that had no subject entry.",
99 "S/MIME entries that had no subject entry.",
100 "Subject entries with BOTH nickname and S/MIME entries."
115 PRFileDesc
*graphfile
;
116 int dbErrors
[NUM_ERROR_TYPES
];
119 struct certDBEntryListNodeStr
{
124 typedef struct certDBEntryListNodeStr certDBEntryListNode
;
127 * A list node for a cert db entry. The index is a unique identifier
128 * to use for creating generic maps of a db. This struct handles
129 * the cert, nickname, and smime db entry types, as all three have a
130 * single handle to a subject entry.
131 * This structure is pointed to by certDBEntryListNode->appData.
137 certDBEntryListNode
*pSubject
;
141 * Subject entry is special case, it has bidirectional handles. One
142 * subject entry can point to several certs (using the same DN), and
143 * a nickname and/or smime entry.
144 * This structure is pointed to by certDBEntryListNode->appData.
151 certDBEntryListNode
**pCerts
;
152 certDBEntryListNode
*pNickname
;
153 certDBEntryListNode
*pSMime
;
154 } certDBSubjectEntryMap
;
166 certDBEntryListNode certs
; /* pointer to head of cert list */
167 certDBEntryListNode subjects
; /* pointer to head of subject list */
168 certDBEntryListNode nicknames
; /* pointer to head of nickname list */
169 certDBEntryListNode smime
; /* pointer to head of smime list */
170 certDBEntryListNode revocation
; /* pointer to head of revocation list */
173 /* Cast list to the base element, a certDBEntryListNode. */
174 #define LISTNODE_CAST(node) \
175 ((certDBEntryListNode *)(node))
178 Usage(char *progName
)
180 #define FPS fprintf(stderr,
181 FPS
"Type %s -H for more detailed descriptions\n", progName
);
182 FPS
"Usage: %s -D [-d certdir] [-m] [-v [-f dumpfile]]\n",
185 FPS
" %s -R -o newdbname [-d certdir] [-aprsx] [-v [-f dumpfile]]\n",
192 LongUsage(char *progName
)
194 FPS
"%-15s Display this help message.\n",
196 FPS
"%-15s Dump analysis. No changes will be made to the database.\n",
198 FPS
"%-15s Cert database directory (default is ~/.netscape)\n",
200 FPS
"%-15s Put database graph in ./mailfile (default is stdout).\n",
202 FPS
"%-15s Verbose mode. Dumps the entire contents of your cert8.db.\n",
204 FPS
"%-15s File to dump verbose output into. (default is stdout)\n",
207 FPS
"%-15s Repair the database. The program will look for broken\n",
209 FPS
"%-15s dependencies between subject entries and certificates,\n",
211 FPS
"%-15s between nickname entries and subjects, and between SMIME\n",
213 FPS
"%-15s profiles and subjects. Any duplicate entries will be\n",
215 FPS
"%-15s removed, any missing entries will be created.\n",
217 FPS
"%-15s File to store new database in (default is new_cert8.db)\n",
219 FPS
"%-15s Cert database directory (default is ~/.netscape)\n",
221 FPS
"%-15s Prompt before removing any certificates.\n",
223 FPS
"%-15s Keep all possible certificates. Only remove certificates\n",
225 FPS
"%-15s which prevent creation of a consistent database. Thus any\n",
227 FPS
"%-15s expired or redundant entries will be kept.\n",
229 FPS
"%-15s Keep redundant nickname/email entries. It is possible\n",
231 FPS
"%-15s only one such entry will be usable.\n",
233 FPS
"%-15s Don't require an S/MIME profile in order to keep an S/MIME\n",
235 FPS
"%-15s cert. An empty profile will be created.\n",
237 FPS
"%-15s Keep expired certificates.\n",
239 FPS
"%-15s Verbose mode - report all activity while recovering db.\n",
241 FPS
"%-15s File to dump verbose output into.\n",
249 /*******************************************************************
251 * Functions for dbck.
253 ******************************************************************/
256 printHexString(PRFileDesc
*out
, SECItem
*hexval
)
259 for (i
= 0; i
< hexval
->len
; i
++) {
260 if (i
!= hexval
->len
- 1) {
261 PR_fprintf(out
, "%02x:", hexval
->data
[i
]);
263 PR_fprintf(out
, "%02x", hexval
->data
[i
]);
266 PR_fprintf(out
, "\n");
271 dumpCertificate(CERTCertificate
*cert
, int num
, PRFileDesc
*outfile
)
274 CERTCertTrust
*trust
= cert
->trust
;
275 userCert
= (SEC_GET_TRUST_FLAGS(trust
, trustSSL
) & CERTDB_USER
) ||
276 (SEC_GET_TRUST_FLAGS(trust
, trustEmail
) & CERTDB_USER
) ||
277 (SEC_GET_TRUST_FLAGS(trust
, trustObjectSigning
) & CERTDB_USER
);
279 PR_fprintf(outfile
, "Certificate: %3d\n", num
);
281 PR_fprintf(outfile
, "Certificate:\n");
283 PR_fprintf(outfile
, "----------------\n");
285 PR_fprintf(outfile
, "(User Cert)\n");
286 PR_fprintf(outfile
, "## SUBJECT: %s\n", cert
->subjectName
);
287 PR_fprintf(outfile
, "## ISSUER: %s\n", cert
->issuerName
);
288 PR_fprintf(outfile
, "## SERIAL NUMBER: ");
289 printHexString(outfile
, &cert
->serialNumber
);
290 { /* XXX should be separate function. */
291 int64 timeBefore
, timeAfter
;
292 PRExplodedTime beforePrintable
, afterPrintable
;
293 char *beforestr
, *afterstr
;
294 DER_DecodeTimeChoice(&timeBefore
, &cert
->validity
.notBefore
);
295 DER_DecodeTimeChoice(&timeAfter
, &cert
->validity
.notAfter
);
296 PR_ExplodeTime(timeBefore
, PR_GMTParameters
, &beforePrintable
);
297 PR_ExplodeTime(timeAfter
, PR_GMTParameters
, &afterPrintable
);
298 beforestr
= PORT_Alloc(100);
299 afterstr
= PORT_Alloc(100);
300 PR_FormatTime(beforestr
, 100, "%a %b %d %H:%M:%S %Y", &beforePrintable
);
301 PR_FormatTime(afterstr
, 100, "%a %b %d %H:%M:%S %Y", &afterPrintable
);
302 PR_fprintf(outfile
, "## VALIDITY: %s to %s\n", beforestr
, afterstr
);
304 PR_fprintf(outfile
, "\n");
309 dumpCertEntry(certDBEntryCert
*entry
, int num
, PRFileDesc
*outfile
)
312 NSSLOWCERTCertificate
*cert
;
313 /* should we check for existing duplicates? */
314 cert
= nsslowcert_DecodeDERCertificate(&entry
->cert
.derCert
,
315 entry
->cert
.nickname
);
317 CERTCertificate
*cert
;
318 cert
= CERT_DecodeDERCertificate(&entry
->derCert
, PR_FALSE
, NULL
);
321 fprintf(stderr
, "Failed to decode certificate.\n");
324 cert
->trust
= (CERTCertTrust
*)&entry
->trust
;
325 dumpCertificate(cert
, num
, outfile
);
326 CERT_DestroyCertificate(cert
);
331 dumpSubjectEntry(certDBEntrySubject
*entry
, int num
, PRFileDesc
*outfile
)
333 char *subjectName
= CERT_DerNameToAscii(&entry
->derSubject
);
335 PR_fprintf(outfile
, "Subject: %3d\n", num
);
336 PR_fprintf(outfile
, "------------\n");
337 PR_fprintf(outfile
, "## %s\n", subjectName
);
339 PR_fprintf(outfile
, "## Subject nickname: %s\n", entry
->nickname
);
340 if (entry
->emailAddrs
) {
342 for (n
= 0; n
< entry
->nemailAddrs
&& entry
->emailAddrs
[n
]; ++n
) {
343 char * emailAddr
= entry
->emailAddrs
[n
];
345 PR_fprintf(outfile
, "## Subject email address: %s\n",
350 PR_fprintf(outfile
, "## This subject has %d cert(s).\n", entry
->ncerts
);
351 PR_fprintf(outfile
, "\n");
352 PORT_Free(subjectName
);
357 dumpNicknameEntry(certDBEntryNickname
*entry
, int num
, PRFileDesc
*outfile
)
359 PR_fprintf(outfile
, "Nickname: %3d\n", num
);
360 PR_fprintf(outfile
, "-------------\n");
361 PR_fprintf(outfile
, "## \"%s\"\n\n", entry
->nickname
);
366 dumpSMimeEntry(certDBEntrySMime
*entry
, int num
, PRFileDesc
*outfile
)
368 PR_fprintf(outfile
, "S/MIME Profile: %3d\n", num
);
369 PR_fprintf(outfile
, "-------------------\n");
370 PR_fprintf(outfile
, "## \"%s\"\n", entry
->emailAddr
);
372 PR_fprintf(outfile
, "## OPTIONS: ");
373 printHexString(outfile
, &entry
->smimeOptions
);
374 PR_fprintf(outfile
, "## TIMESTAMP: ");
375 printHexString(outfile
, &entry
->optionsDate
);
377 SECU_PrintAny(stdout
, &entry
->smimeOptions
, "## OPTIONS ", 0);
379 if (entry
->optionsDate
.len
&& entry
->optionsDate
.data
)
380 PR_fprintf(outfile
, "## TIMESTAMP: %.*s\n",
381 entry
->optionsDate
.len
, entry
->optionsDate
.data
);
383 PR_fprintf(outfile
, "\n");
388 mapCertEntries(certDBArray
*dbArray
)
390 certDBEntryCert
*certEntry
;
391 certDBEntrySubject
*subjectEntry
;
392 certDBEntryListNode
*certNode
, *subjNode
;
393 certDBSubjectEntryMap
*smap
;
395 PRArenaPool
*tmparena
;
398 PRCList
*cElem
, *sElem
;
400 /* Arena for decoded entries */
401 tmparena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
402 if (tmparena
== NULL
) {
403 PORT_SetError(SEC_ERROR_NO_MEMORY
);
407 /* Iterate over cert entries and map them to subject entries.
408 * NOTE: mapSubjectEntries must be called first to alloc memory
409 * for array of subject->cert map.
411 for (cElem
= PR_LIST_HEAD(&dbArray
->certs
.link
);
412 cElem
!= &dbArray
->certs
.link
; cElem
= PR_NEXT_LINK(cElem
)) {
413 certNode
= LISTNODE_CAST(cElem
);
414 certEntry
= (certDBEntryCert
*)&certNode
->entry
;
415 map
= (certDBEntryMap
*)certNode
->appData
;
416 CERT_NameFromDERCert(&certEntry
->derCert
, &derSubject
);
417 CERT_KeyFromDERCert(tmparena
, &certEntry
->derCert
, &certKey
);
418 /* Loop over found subjects for cert's DN. */
419 for (sElem
= PR_LIST_HEAD(&dbArray
->subjects
.link
);
420 sElem
!= &dbArray
->subjects
.link
; sElem
= PR_NEXT_LINK(sElem
)) {
421 subjNode
= LISTNODE_CAST(sElem
);
422 subjectEntry
= (certDBEntrySubject
*)&subjNode
->entry
;
423 if (SECITEM_ItemsAreEqual(&derSubject
, &subjectEntry
->derSubject
)) {
425 /* Found matching subject name, create link. */
426 map
->pSubject
= subjNode
;
427 /* Make sure subject entry has cert's key. */
428 for (i
=0; i
<subjectEntry
->ncerts
; i
++) {
429 if (SECITEM_ItemsAreEqual(&certKey
,
430 &subjectEntry
->certKeys
[i
])) {
431 /* Found matching cert key. */
432 smap
= (certDBSubjectEntryMap
*)subjNode
->appData
;
433 smap
->pCerts
[i
] = certNode
;
440 PORT_FreeArena(tmparena
, PR_FALSE
);
445 mapSubjectEntries(certDBArray
*dbArray
)
447 certDBEntrySubject
*subjectEntry
;
448 certDBEntryListNode
*subjNode
;
449 certDBSubjectEntryMap
*subjMap
;
452 for (sElem
= PR_LIST_HEAD(&dbArray
->subjects
.link
);
453 sElem
!= &dbArray
->subjects
.link
; sElem
= PR_NEXT_LINK(sElem
)) {
454 /* Iterate over subject entries and map subjects to nickname
455 * and smime entries. The cert<->subject map will be handled
456 * by a subsequent call to mapCertEntries.
458 subjNode
= LISTNODE_CAST(sElem
);
459 subjectEntry
= (certDBEntrySubject
*)&subjNode
->entry
;
460 subjMap
= (certDBSubjectEntryMap
*)subjNode
->appData
;
461 /* need to alloc memory here for array of matching certs. */
462 subjMap
->pCerts
= PORT_ArenaAlloc(subjMap
->arena
,
463 subjectEntry
->ncerts
*sizeof(int));
464 subjMap
->numCerts
= subjectEntry
->ncerts
;
465 subjMap
->pNickname
= NoNickname
;
466 subjMap
->pSMime
= NoSMime
;
468 if (subjectEntry
->nickname
) {
469 /* Subject should have a nickname entry, so create a link. */
471 for (nElem
= PR_LIST_HEAD(&dbArray
->nicknames
.link
);
472 nElem
!= &dbArray
->nicknames
.link
;
473 nElem
= PR_NEXT_LINK(nElem
)) {
474 certDBEntryListNode
*nickNode
;
475 certDBEntryNickname
*nicknameEntry
;
476 /* Look for subject's nickname in nickname entries. */
477 nickNode
= LISTNODE_CAST(nElem
);
478 nicknameEntry
= (certDBEntryNickname
*)&nickNode
->entry
;
479 if (PL_strcmp(subjectEntry
->nickname
,
480 nicknameEntry
->nickname
) == 0) {
481 /* Found a nickname entry for subject's nickname. */
482 if (SECITEM_ItemsAreEqual(&subjectEntry
->derSubject
,
483 &nicknameEntry
->subjectName
)) {
484 certDBEntryMap
*nickMap
;
485 nickMap
= (certDBEntryMap
*)nickNode
->appData
;
486 /* Nickname and subject match. */
487 subjMap
->pNickname
= nickNode
;
488 nickMap
->pSubject
= subjNode
;
489 } else if (subjMap
->pNickname
== NoNickname
) {
490 /* Nickname entry found is for diff. subject. */
491 subjMap
->pNickname
= WrongEntry
;
496 if (subjectEntry
->emailAddrs
) {
498 for (n
= 0; n
< subjectEntry
->nemailAddrs
&&
499 subjectEntry
->emailAddrs
[n
]; ++n
) {
500 char * emailAddr
= subjectEntry
->emailAddrs
[n
];
503 /* Subject should have an smime entry, so create a link. */
504 for (mElem
= PR_LIST_HEAD(&dbArray
->smime
.link
);
505 mElem
!= &dbArray
->smime
.link
;
506 mElem
= PR_NEXT_LINK(mElem
)) {
507 certDBEntryListNode
*smimeNode
;
508 certDBEntrySMime
*smimeEntry
;
509 /* Look for subject's email in S/MIME entries. */
510 smimeNode
= LISTNODE_CAST(mElem
);
511 smimeEntry
= (certDBEntrySMime
*)&smimeNode
->entry
;
512 if (PL_strcmp(emailAddr
,
513 smimeEntry
->emailAddr
) == 0) {
514 /* Found a S/MIME entry for subject's email. */
515 if (SECITEM_ItemsAreEqual(
516 &subjectEntry
->derSubject
,
517 &smimeEntry
->subjectName
)) {
518 certDBEntryMap
*smimeMap
;
519 /* S/MIME entry and subject match. */
520 subjMap
->pSMime
= smimeNode
;
521 smimeMap
= (certDBEntryMap
*)smimeNode
->appData
;
522 smimeMap
->pSubject
= subjNode
;
523 } else if (subjMap
->pSMime
== NoSMime
) {
524 /* S/MIME entry found is for diff. subject. */
525 subjMap
->pSMime
= WrongEntry
;
529 } /* endif (emailAddr[0]) */
531 } /* endif (subjectEntry->emailAddrs) */
537 printnode(dbDebugInfo
*info
, const char *str
, int num
)
542 PR_fprintf(info
->graphfile
, str
);
544 PR_fprintf(info
->graphfile
, str
, num
);
549 map_handle_is_ok(dbDebugInfo
*info
, void *mapPtr
, int indent
)
551 if (mapPtr
== NULL
) {
553 printnode(info
, " ", -1);
555 printnode(info
, "******************* ", -1);
557 } else if (mapPtr
== WrongEntry
) {
559 printnode(info
, " ", -1);
561 printnode(info
, "??????????????????? ", -1);
568 /* these call each other */
569 void print_smime_graph(dbDebugInfo
*info
, certDBEntryMap
*smimeMap
,
571 void print_nickname_graph(dbDebugInfo
*info
, certDBEntryMap
*nickMap
,
573 void print_subject_graph(dbDebugInfo
*info
, certDBSubjectEntryMap
*subjMap
,
574 int direction
, int optindex
, int opttype
);
575 void print_cert_graph(dbDebugInfo
*info
, certDBEntryMap
*certMap
,
578 /* Given an smime entry, print its unique identifier. If GOLEFT is
579 * specified, print the cert<-subject<-smime map, else just print
583 print_smime_graph(dbDebugInfo
*info
, certDBEntryMap
*smimeMap
, int direction
)
585 certDBSubjectEntryMap
*subjMap
;
586 certDBEntryListNode
*subjNode
;
587 if (direction
== GOLEFT
) {
588 /* Need to output subject and cert first, see print_subject_graph */
589 subjNode
= smimeMap
->pSubject
;
590 if (map_handle_is_ok(info
, (void *)subjNode
, 1)) {
591 subjMap
= (certDBSubjectEntryMap
*)subjNode
->appData
;
592 print_subject_graph(info
, subjMap
, GOLEFT
,
593 smimeMap
->index
, certDBEntryTypeSMimeProfile
);
595 printnode(info
, "<---- S/MIME %5d ", smimeMap
->index
);
596 info
->dbErrors
[NoSubjectForSMime
]++;
599 printnode(info
, "S/MIME %5d ", smimeMap
->index
);
603 /* Given a nickname entry, print its unique identifier. If GOLEFT is
604 * specified, print the cert<-subject<-nickname map, else just print
605 * the nickname entry.
608 print_nickname_graph(dbDebugInfo
*info
, certDBEntryMap
*nickMap
, int direction
)
610 certDBSubjectEntryMap
*subjMap
;
611 certDBEntryListNode
*subjNode
;
612 if (direction
== GOLEFT
) {
613 /* Need to output subject and cert first, see print_subject_graph */
614 subjNode
= nickMap
->pSubject
;
615 if (map_handle_is_ok(info
, (void *)subjNode
, 1)) {
616 subjMap
= (certDBSubjectEntryMap
*)subjNode
->appData
;
617 print_subject_graph(info
, subjMap
, GOLEFT
,
618 nickMap
->index
, certDBEntryTypeNickname
);
620 printnode(info
, "<---- Nickname %5d ", nickMap
->index
);
621 info
->dbErrors
[NoSubjectForNickname
]++;
624 printnode(info
, "Nickname %5d ", nickMap
->index
);
628 /* Given a subject entry, if going right print the graph of the nickname|smime
629 * that it maps to (by its unique identifier); and if going left
630 * print the list of certs that it points to.
633 print_subject_graph(dbDebugInfo
*info
, certDBSubjectEntryMap
*subjMap
,
634 int direction
, int optindex
, int opttype
)
637 certDBEntryListNode
*node
;
639 /* The first line of output always contains the cert id, subject id,
640 * and nickname|smime id. Subsequent lines may contain additional
641 * cert id's for the subject if going left or both directions.
642 * Ex. of printing the graph for a subject entry:
643 * Cert 3 <- Subject 5 -> Nickname 32
646 * means subject 5 has 3 certs, 3, 8, and 9, and corresponds
647 * to nickname entry 32.
648 * To accomplish the above, it is required to dump the entire first
649 * line left-to-right, regardless of the input direction, and then
650 * finish up any remaining cert entries. Hence the code is uglier
651 * than one may expect.
653 if (direction
== GOLEFT
|| direction
== GOBOTH
) {
654 /* In this case, nothing should be output until the first cert is
655 * located and output (cert 3 in the above example).
657 if (subjMap
->numCerts
== 0 || subjMap
->pCerts
== NULL
)
660 /* get the first cert and dump it. */
661 node
= subjMap
->pCerts
[0];
662 if (map_handle_is_ok(info
, (void *)node
, 0)) {
663 map
= (certDBEntryMap
*)node
->appData
;
664 /* going left here stops. */
665 print_cert_graph(info
, map
, GOLEFT
);
667 info
->dbErrors
[SubjectHasNoKeyForCert
]++;
669 /* Now it is safe to output the subject id. */
670 if (direction
== GOLEFT
)
671 printnode(info
, "Subject %5d <---- ", subjMap
->index
);
672 else /* direction == GOBOTH */
673 printnode(info
, "Subject %5d ----> ", subjMap
->index
);
675 if (direction
== GORIGHT
|| direction
== GOBOTH
) {
676 /* Okay, now output the nickname|smime for this subject. */
677 if (direction
!= GOBOTH
) /* handled above */
678 printnode(info
, "Subject %5d ----> ", subjMap
->index
);
679 if (subjMap
->pNickname
) {
680 node
= subjMap
->pNickname
;
681 if (map_handle_is_ok(info
, (void *)node
, 0)) {
682 map
= (certDBEntryMap
*)node
->appData
;
683 /* going right here stops. */
684 print_nickname_graph(info
, map
, GORIGHT
);
687 if (subjMap
->pSMime
) {
688 node
= subjMap
->pSMime
;
689 if (map_handle_is_ok(info
, (void *)node
, 0)) {
690 map
= (certDBEntryMap
*)node
->appData
;
691 /* going right here stops. */
692 print_smime_graph(info
, map
, GORIGHT
);
695 if (!subjMap
->pNickname
&& !subjMap
->pSMime
) {
696 printnode(info
, "******************* ", -1);
697 info
->dbErrors
[NoNicknameOrSMimeForSubject
]++;
699 if (subjMap
->pNickname
&& subjMap
->pSMime
) {
700 info
->dbErrors
[NicknameAndSMimeEntries
]++;
703 if (direction
!= GORIGHT
) { /* going right has only one cert */
704 if (opttype
== certDBEntryTypeNickname
)
705 printnode(info
, "Nickname %5d ", optindex
);
706 else if (opttype
== certDBEntryTypeSMimeProfile
)
707 printnode(info
, "S/MIME %5d ", optindex
);
708 for (i
=1 /* 1st one already done */; i
<subjMap
->numCerts
; i
++) {
709 printnode(info
, "\n", -1); /* start a new line */
710 node
= subjMap
->pCerts
[i
];
711 if (map_handle_is_ok(info
, (void *)node
, 0)) {
712 map
= (certDBEntryMap
*)node
->appData
;
713 /* going left here stops. */
714 print_cert_graph(info
, map
, GOLEFT
);
715 printnode(info
, "/", -1);
721 /* Given a cert entry, print its unique identifer. If GORIGHT is specified,
722 * print the cert->subject->nickname|smime map, else just print
726 print_cert_graph(dbDebugInfo
*info
, certDBEntryMap
*certMap
, int direction
)
728 certDBSubjectEntryMap
*subjMap
;
729 certDBEntryListNode
*subjNode
;
730 if (direction
== GOLEFT
) {
731 printnode(info
, "Cert %5d <---- ", certMap
->index
);
732 /* only want cert entry, terminate here. */
735 /* Keep going right then. */
736 printnode(info
, "Cert %5d ----> ", certMap
->index
);
737 subjNode
= certMap
->pSubject
;
738 if (map_handle_is_ok(info
, (void *)subjNode
, 0)) {
739 subjMap
= (certDBSubjectEntryMap
*)subjNode
->appData
;
740 print_subject_graph(info
, subjMap
, GORIGHT
, -1, -1);
742 info
->dbErrors
[NoSubjectForCert
]++;
747 computeDBGraph(certDBArray
*dbArray
, dbDebugInfo
*info
)
749 PRCList
*cElem
, *sElem
, *nElem
, *mElem
;
750 certDBEntryListNode
*node
;
752 certDBSubjectEntryMap
*subjMap
;
754 /* Graph is of this form:
757 * cert ---> subject ---> (nickname|smime)
760 * cert <--- subject ---> (nickname|smime)
762 * nicknames and smime:
763 * cert <--- subject <--- (nickname|smime)
766 /* Print cert graph. */
767 for (cElem
= PR_LIST_HEAD(&dbArray
->certs
.link
);
768 cElem
!= &dbArray
->certs
.link
; cElem
= PR_NEXT_LINK(cElem
)) {
769 /* Print graph of everything to right of cert entry. */
770 node
= LISTNODE_CAST(cElem
);
771 map
= (certDBEntryMap
*)node
->appData
;
772 print_cert_graph(info
, map
, GORIGHT
);
773 printnode(info
, "\n", -1);
775 printnode(info
, "\n", -1);
777 /* Print subject graph. */
778 for (sElem
= PR_LIST_HEAD(&dbArray
->subjects
.link
);
779 sElem
!= &dbArray
->subjects
.link
; sElem
= PR_NEXT_LINK(sElem
)) {
780 /* Print graph of everything to both sides of subject entry. */
781 node
= LISTNODE_CAST(sElem
);
782 subjMap
= (certDBSubjectEntryMap
*)node
->appData
;
783 print_subject_graph(info
, subjMap
, GOBOTH
, -1, -1);
784 printnode(info
, "\n", -1);
786 printnode(info
, "\n", -1);
788 /* Print nickname graph. */
789 for (nElem
= PR_LIST_HEAD(&dbArray
->nicknames
.link
);
790 nElem
!= &dbArray
->nicknames
.link
; nElem
= PR_NEXT_LINK(nElem
)) {
791 /* Print graph of everything to left of nickname entry. */
792 node
= LISTNODE_CAST(nElem
);
793 map
= (certDBEntryMap
*)node
->appData
;
794 print_nickname_graph(info
, map
, GOLEFT
);
795 printnode(info
, "\n", -1);
797 printnode(info
, "\n", -1);
799 /* Print smime graph. */
800 for (mElem
= PR_LIST_HEAD(&dbArray
->smime
.link
);
801 mElem
!= &dbArray
->smime
.link
; mElem
= PR_NEXT_LINK(mElem
)) {
802 /* Print graph of everything to left of smime entry. */
803 node
= LISTNODE_CAST(mElem
);
804 if (node
== NULL
) break;
805 map
= (certDBEntryMap
*)node
->appData
;
806 print_smime_graph(info
, map
, GOLEFT
);
807 printnode(info
, "\n", -1);
809 printnode(info
, "\n", -1);
815 * List the entries in the db, showing handles between entry types.
818 verboseOutput(certDBArray
*dbArray
, dbDebugInfo
*info
)
822 certDBEntryListNode
*node
;
824 certDBSubjectEntryMap
*smap
;
825 certDBEntrySubject
*subjectEntry
;
828 for (elem
= PR_LIST_HEAD(&dbArray
->certs
.link
);
829 elem
!= &dbArray
->certs
.link
; elem
= PR_NEXT_LINK(elem
)) {
830 node
= LISTNODE_CAST(elem
);
831 map
= (certDBEntryMap
*)node
->appData
;
832 dumpCertEntry((certDBEntryCert
*)&node
->entry
, map
->index
, info
->out
);
833 /* walk the cert handle to it's subject entry */
834 if (map_handle_is_ok(info
, map
->pSubject
, -1)) {
835 smap
= (certDBSubjectEntryMap
*)map
->pSubject
->appData
;
837 PR_fprintf(info
->out
, "-->(subject %d)\n\n\n", ref
);
839 PR_fprintf(info
->out
, "-->(MISSING SUBJECT ENTRY)\n\n\n");
843 for (elem
= PR_LIST_HEAD(&dbArray
->subjects
.link
);
844 elem
!= &dbArray
->subjects
.link
; elem
= PR_NEXT_LINK(elem
)) {
846 node
= LISTNODE_CAST(elem
);
847 subjectEntry
= (certDBEntrySubject
*)&node
->entry
;
848 smap
= (certDBSubjectEntryMap
*)node
->appData
;
849 dumpSubjectEntry(subjectEntry
, smap
->index
, info
->out
);
850 /* iterate over subject's certs */
851 for (i
=0; i
<smap
->numCerts
; i
++) {
852 /* walk each subject handle to it's cert entries */
853 if (map_handle_is_ok(info
, smap
->pCerts
[i
], -1)) {
854 ref
= ((certDBEntryMap
*)smap
->pCerts
[i
]->appData
)->index
;
855 PR_fprintf(info
->out
, "-->(%d. certificate %d)\n", i
, ref
);
857 PR_fprintf(info
->out
, "-->(%d. MISSING CERT ENTRY)\n", i
);
860 if (subjectEntry
->nickname
) {
862 /* walk each subject handle to it's nickname entry */
863 if (map_handle_is_ok(info
, smap
->pNickname
, -1)) {
864 ref
= ((certDBEntryMap
*)smap
->pNickname
->appData
)->index
;
865 PR_fprintf(info
->out
, "-->(nickname %d)\n", ref
);
867 PR_fprintf(info
->out
, "-->(MISSING NICKNAME ENTRY)\n");
870 if (subjectEntry
->nemailAddrs
&&
871 subjectEntry
->emailAddrs
&&
872 subjectEntry
->emailAddrs
[0] &&
873 subjectEntry
->emailAddrs
[0][0]) {
875 /* walk each subject handle to it's smime entry */
876 if (map_handle_is_ok(info
, smap
->pSMime
, -1)) {
877 ref
= ((certDBEntryMap
*)smap
->pSMime
->appData
)->index
;
878 PR_fprintf(info
->out
, "-->(s/mime %d)\n", ref
);
880 PR_fprintf(info
->out
, "-->(MISSING S/MIME ENTRY)\n");
884 PR_fprintf(info
->out
, "-->(NO NICKNAME+S/MIME ENTRY)\n");
886 PR_fprintf(info
->out
, "\n\n");
888 for (elem
= PR_LIST_HEAD(&dbArray
->nicknames
.link
);
889 elem
!= &dbArray
->nicknames
.link
; elem
= PR_NEXT_LINK(elem
)) {
890 node
= LISTNODE_CAST(elem
);
891 map
= (certDBEntryMap
*)node
->appData
;
892 dumpNicknameEntry((certDBEntryNickname
*)&node
->entry
, map
->index
,
894 if (map_handle_is_ok(info
, map
->pSubject
, -1)) {
895 ref
= ((certDBEntryMap
*)map
->pSubject
->appData
)->index
;
896 PR_fprintf(info
->out
, "-->(subject %d)\n\n\n", ref
);
898 PR_fprintf(info
->out
, "-->(MISSING SUBJECT ENTRY)\n\n\n");
901 for (elem
= PR_LIST_HEAD(&dbArray
->smime
.link
);
902 elem
!= &dbArray
->smime
.link
; elem
= PR_NEXT_LINK(elem
)) {
903 node
= LISTNODE_CAST(elem
);
904 map
= (certDBEntryMap
*)node
->appData
;
905 dumpSMimeEntry((certDBEntrySMime
*)&node
->entry
, map
->index
, info
->out
);
906 if (map_handle_is_ok(info
, map
->pSubject
, -1)) {
907 ref
= ((certDBEntryMap
*)map
->pSubject
->appData
)->index
;
908 PR_fprintf(info
->out
, "-->(subject %d)\n\n\n", ref
);
910 PR_fprintf(info
->out
, "-->(MISSING SUBJECT ENTRY)\n\n\n");
913 PR_fprintf(info
->out
, "\n\n");
917 /* A callback function, intended to be called from nsslowcert_TraverseDBEntries
918 * Builds a PRCList of DB entries of the specified type.
921 SEC_GetCertDBEntryList(SECItem
*dbdata
, SECItem
*dbkey
,
922 certDBEntryType entryType
, void *pdata
)
925 certDBEntryListNode
* node
;
926 PRCList
* list
= (PRCList
*)pdata
;
928 if (!dbdata
|| !dbkey
|| !pdata
|| !dbdata
->data
|| !dbkey
->data
) {
929 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
932 entry
= nsslowcert_DecodeAnyDBEntry(dbdata
, dbkey
, entryType
, NULL
);
934 return SECSuccess
; /* skip it */
936 node
= PORT_ArenaZNew(entry
->common
.arena
, certDBEntryListNode
);
938 /* DestroyDBEntry(entry); */
939 PLArenaPool
*arena
= entry
->common
.arena
;
940 PORT_Memset(&entry
->common
, 0, sizeof entry
->common
);
941 PORT_FreeArena(arena
, PR_FALSE
);
944 node
->entry
= *entry
; /* crude but effective. */
945 PR_INIT_CLIST(&node
->link
);
946 PR_INSERT_BEFORE(&node
->link
, list
);
952 fillDBEntryArray(NSSLOWCERTCertDBHandle
*handle
, certDBEntryType type
,
953 certDBEntryListNode
*list
)
956 certDBEntryListNode
*node
;
957 certDBEntryMap
*mnode
;
958 certDBSubjectEntryMap
*smnode
;
962 /* Initialize a dummy entry in the list. The list head will be the
963 * next element, so this element is skipped by for loops.
965 PR_INIT_CLIST((PRCList
*)list
);
966 /* Collect all of the cert db entries for this type into a list. */
967 nsslowcert_TraverseDBEntries(handle
, type
, SEC_GetCertDBEntryList
, list
);
969 for (elem
= PR_LIST_HEAD(&list
->link
);
970 elem
!= &list
->link
; elem
= PR_NEXT_LINK(elem
)) {
971 /* Iterate over the entries and ... */
972 node
= (certDBEntryListNode
*)elem
;
973 if (type
!= certDBEntryTypeSubject
) {
974 arena
= PORT_NewArena(sizeof(*mnode
));
975 mnode
= PORT_ArenaZNew(arena
, certDBEntryMap
);
976 mnode
->arena
= arena
;
977 /* ... assign a unique index number to each node, and ... */
978 mnode
->index
= count
;
979 /* ... set the map pointer for the node. */
980 node
->appData
= (void *)mnode
;
982 /* allocate some room for the cert pointers also */
983 arena
= PORT_NewArena(sizeof(*smnode
) + 20*sizeof(void *));
984 smnode
= PORT_ArenaZNew(arena
, certDBSubjectEntryMap
);
985 smnode
->arena
= arena
;
986 smnode
->index
= count
;
987 node
->appData
= (void *)smnode
;
995 freeDBEntryList(PRCList
*list
)
997 PRCList
*next
, *elem
;
998 certDBEntryListNode
*node
;
1001 for (elem
= PR_LIST_HEAD(list
); elem
!= list
;) {
1002 next
= PR_NEXT_LINK(elem
);
1003 node
= (certDBEntryListNode
*)elem
;
1004 map
= (certDBEntryMap
*)node
->appData
;
1005 PR_REMOVE_LINK(&node
->link
);
1006 PORT_FreeArena(map
->arena
, PR_TRUE
);
1007 PORT_FreeArena(node
->entry
.common
.arena
, PR_TRUE
);
1013 DBCK_DebugDB(NSSLOWCERTCertDBHandle
*handle
, PRFileDesc
*out
,
1014 PRFileDesc
*mailfile
)
1016 int i
, nCertsFound
, nSubjFound
, nErr
;
1017 int nCerts
, nSubjects
, nSubjCerts
, nNicknames
, nSMime
, nRevocation
;
1021 certDBArray dbArray
;
1023 PORT_Memset(&dbArray
, 0, sizeof(dbArray
));
1024 PORT_Memset(&info
, 0, sizeof(info
));
1025 info
.verbose
= (PRBool
)(out
!= NULL
);
1026 info
.dograph
= info
.verbose
;
1027 info
.out
= (out
) ? out
: PR_STDOUT
;
1028 info
.graphfile
= mailfile
? mailfile
: PR_STDOUT
;
1030 /* Fill the array structure with cert/subject/nickname/smime entries. */
1031 dbArray
.numCerts
= fillDBEntryArray(handle
, certDBEntryTypeCert
,
1033 dbArray
.numSubjects
= fillDBEntryArray(handle
, certDBEntryTypeSubject
,
1035 dbArray
.numNicknames
= fillDBEntryArray(handle
, certDBEntryTypeNickname
,
1036 &dbArray
.nicknames
);
1037 dbArray
.numSMime
= fillDBEntryArray(handle
, certDBEntryTypeSMimeProfile
,
1039 dbArray
.numRevocation
= fillDBEntryArray(handle
, certDBEntryTypeRevocation
,
1040 &dbArray
.revocation
);
1042 /* Compute the map between the database entries. */
1043 mapSubjectEntries(&dbArray
);
1044 mapCertEntries(&dbArray
);
1045 computeDBGraph(&dbArray
, &info
);
1047 /* Store the totals for later reference. */
1048 nCerts
= dbArray
.numCerts
;
1049 nSubjects
= dbArray
.numSubjects
;
1050 nNicknames
= dbArray
.numNicknames
;
1051 nSMime
= dbArray
.numSMime
;
1052 nRevocation
= dbArray
.numRevocation
;
1054 for (elem
= PR_LIST_HEAD(&dbArray
.subjects
.link
);
1055 elem
!= &dbArray
.subjects
.link
; elem
= PR_NEXT_LINK(elem
)) {
1056 certDBSubjectEntryMap
*smap
;
1057 smap
= (certDBSubjectEntryMap
*)LISTNODE_CAST(elem
)->appData
;
1058 nSubjCerts
+= smap
->numCerts
;
1062 /* Dump the database contents. */
1063 verboseOutput(&dbArray
, &info
);
1066 freeDBEntryList(&dbArray
.certs
.link
);
1067 freeDBEntryList(&dbArray
.subjects
.link
);
1068 freeDBEntryList(&dbArray
.nicknames
.link
);
1069 freeDBEntryList(&dbArray
.smime
.link
);
1070 freeDBEntryList(&dbArray
.revocation
.link
);
1072 PR_fprintf(info
.out
, "\n");
1073 PR_fprintf(info
.out
, "Database statistics:\n");
1074 PR_fprintf(info
.out
, "N0: Found %4d Certificate entries.\n",
1076 PR_fprintf(info
.out
, "N1: Found %4d Subject entries (unique DN's).\n",
1078 PR_fprintf(info
.out
, "N2: Found %4d Cert keys within Subject entries.\n",
1080 PR_fprintf(info
.out
, "N3: Found %4d Nickname entries.\n",
1082 PR_fprintf(info
.out
, "N4: Found %4d S/MIME entries.\n",
1084 PR_fprintf(info
.out
, "N5: Found %4d CRL entries.\n",
1086 PR_fprintf(info
.out
, "\n");
1089 for (i
=0; i
< NUM_ERROR_TYPES
; i
++) {
1090 PR_fprintf(info
.out
, "E%d: Found %4d %s\n",
1091 i
, info
.dbErrors
[i
], errResult
[i
]);
1092 nErr
+= info
.dbErrors
[i
];
1094 PR_fprintf(info
.out
, "--------------\n Found %4d errors in database.\n",
1097 PR_fprintf(info
.out
, "\nCertificates:\n");
1098 PR_fprintf(info
.out
, "N0 == N2 + E%d + E%d\n", NoSubjectForCert
,
1099 SubjectHasNoKeyForCert
);
1100 nCertsFound
= nSubjCerts
+
1101 info
.dbErrors
[NoSubjectForCert
] +
1102 info
.dbErrors
[SubjectHasNoKeyForCert
];
1103 c
= (nCertsFound
== nCerts
) ? '=' : '!';
1104 PR_fprintf(info
.out
, "%d %c= %d + %d + %d\n", nCerts
, c
, nSubjCerts
,
1105 info
.dbErrors
[NoSubjectForCert
],
1106 info
.dbErrors
[SubjectHasNoKeyForCert
]);
1107 PR_fprintf(info
.out
, "\nSubjects:\n");
1108 PR_fprintf(info
.out
,
1109 "N1 == N3 + N4 + E%d + E%d + E%d + E%d + E%d - E%d - E%d - E%d\n",
1110 NoNicknameOrSMimeForSubject
,
1111 WrongNicknameForSubject
,
1113 WrongSMimeForSubject
,
1115 NoSubjectForNickname
,
1117 NicknameAndSMimeEntries
);
1118 nSubjFound
= nNicknames
+ nSMime
+
1119 info
.dbErrors
[NoNicknameOrSMimeForSubject
] +
1120 info
.dbErrors
[WrongNicknameForSubject
] +
1121 info
.dbErrors
[NoNicknameEntry
] +
1122 info
.dbErrors
[WrongSMimeForSubject
] +
1123 info
.dbErrors
[NoSMimeEntry
] -
1124 info
.dbErrors
[NoSubjectForNickname
] -
1125 info
.dbErrors
[NoSubjectForSMime
] -
1126 info
.dbErrors
[NicknameAndSMimeEntries
];
1127 c
= (nSubjFound
== nSubjects
) ? '=' : '!';
1128 PR_fprintf(info
.out
,
1129 "%2d %c= %2d + %2d + %2d + %2d + %2d + %2d + %2d - %2d - %2d - %2d\n",
1130 nSubjects
, c
, nNicknames
, nSMime
,
1131 info
.dbErrors
[NoNicknameOrSMimeForSubject
],
1132 info
.dbErrors
[WrongNicknameForSubject
],
1133 info
.dbErrors
[NoNicknameEntry
],
1134 info
.dbErrors
[WrongSMimeForSubject
],
1135 info
.dbErrors
[NoSMimeEntry
],
1136 info
.dbErrors
[NoSubjectForNickname
],
1137 info
.dbErrors
[NoSubjectForSMime
],
1138 info
.dbErrors
[NicknameAndSMimeEntries
]);
1139 PR_fprintf(info
.out
, "\n");
1143 #include "dbrecover.c"
1144 #endif /* DORECOVER */
1161 opt_KeepNoSMimeProfile
,
1166 static secuCommandFlag dbck_commands
[] =
1168 { /* cmd_Debug, */ 'D', PR_FALSE
, 0, PR_FALSE
},
1169 { /* cmd_LongUsage,*/ 'H', PR_FALSE
, 0, PR_FALSE
},
1170 { /* cmd_Recover, */ 'R', PR_FALSE
, 0, PR_FALSE
}
1173 static secuCommandFlag dbck_options
[] =
1175 { /* opt_KeepAll, */ 'a', PR_FALSE
, 0, PR_FALSE
},
1176 { /* opt_CertDir, */ 'd', PR_TRUE
, 0, PR_FALSE
},
1177 { /* opt_Dumpfile, */ 'f', PR_TRUE
, 0, PR_FALSE
},
1178 { /* opt_InputDB, */ 'i', PR_TRUE
, 0, PR_FALSE
},
1179 { /* opt_OutputDB, */ 'o', PR_TRUE
, 0, PR_FALSE
},
1180 { /* opt_Mailfile, */ 'm', PR_FALSE
, 0, PR_FALSE
},
1181 { /* opt_Prompt, */ 'p', PR_FALSE
, 0, PR_FALSE
},
1182 { /* opt_KeepRedundant, */ 'r', PR_FALSE
, 0, PR_FALSE
},
1183 { /* opt_KeepNoSMimeProfile,*/ 's', PR_FALSE
, 0, PR_FALSE
},
1184 { /* opt_Verbose, */ 'v', PR_FALSE
, 0, PR_FALSE
},
1185 { /* opt_KeepExpired, */ 'x', PR_FALSE
, 0, PR_FALSE
}
1188 #define CERT_DB_FMT "%s/cert%s.db"
1191 dbck_certdb_name_cb(void *arg
, int dbVersion
)
1193 const char *configdir
= (const char *)arg
;
1195 char *smpname
= NULL
;
1196 char *dbname
= NULL
;
1198 switch (dbVersion
) {
1217 /* make sure we return something allocated with PORT_ so we have properly
1218 * matched frees at the end */
1219 smpname
= PR_smprintf(CERT_DB_FMT
, configdir
, dbver
);
1221 dbname
= PORT_Strdup(smpname
);
1222 PR_smprintf_free(smpname
);
1229 main(int argc
, char **argv
)
1231 NSSLOWCERTCertDBHandle
*certHandle
;
1233 PRFileDesc
*mailfile
= NULL
;
1234 PRFileDesc
*dumpfile
= NULL
;
1236 char * pathname
= 0;
1237 char * fullname
= 0;
1238 char * newdbname
= 0;
1240 PRBool removeExpired
, requireProfile
, singleEntry
;
1244 dbck
.numCommands
= sizeof(dbck_commands
) / sizeof(secuCommandFlag
);
1245 dbck
.numOptions
= sizeof(dbck_options
) / sizeof(secuCommandFlag
);
1246 dbck
.commands
= dbck_commands
;
1247 dbck
.options
= dbck_options
;
1249 progName
= strrchr(argv
[0], '/');
1250 progName
= progName
? progName
+1 : argv
[0];
1252 rv
= SECU_ParseCommandLine(argc
, argv
, progName
, &dbck
);
1254 if (rv
!= SECSuccess
)
1257 if (dbck
.commands
[cmd_LongUsage
].activated
)
1258 LongUsage(progName
);
1260 if (!dbck
.commands
[cmd_Debug
].activated
&&
1261 !dbck
.commands
[cmd_Recover
].activated
) {
1262 PR_fprintf(PR_STDERR
, "Please specify -H, -D or -R.\n");
1266 removeExpired
= !(dbck
.options
[opt_KeepAll
].activated
||
1267 dbck
.options
[opt_KeepExpired
].activated
);
1269 requireProfile
= !(dbck
.options
[opt_KeepAll
].activated
||
1270 dbck
.options
[opt_KeepNoSMimeProfile
].activated
);
1272 singleEntry
= !(dbck
.options
[opt_KeepAll
].activated
||
1273 dbck
.options
[opt_KeepRedundant
].activated
);
1275 if (dbck
.options
[opt_OutputDB
].activated
) {
1276 newdbname
= PL_strdup(dbck
.options
[opt_OutputDB
].arg
);
1278 newdbname
= PL_strdup("new_cert8.db");
1281 /* Create a generic graph of the database. */
1282 if (dbck
.options
[opt_Mailfile
].activated
) {
1283 mailfile
= PR_Open("./mailfile", PR_RDWR
| PR_CREATE_FILE
, 00660);
1285 fprintf(stderr
, "Unable to create mailfile.\n");
1290 /* Dump all debugging info while running. */
1291 if (dbck
.options
[opt_Verbose
].activated
) {
1292 if (dbck
.options
[opt_Dumpfile
].activated
) {
1293 dumpfile
= PR_Open(dbck
.options
[opt_Dumpfile
].arg
,
1294 PR_RDWR
| PR_CREATE_FILE
, 00660);
1296 fprintf(stderr
, "Unable to create dumpfile.\n");
1300 dumpfile
= PR_STDOUT
;
1304 /* Set the cert database directory. */
1305 if (dbck
.options
[opt_CertDir
].activated
) {
1306 SECU_ConfigDirectory(dbck
.options
[opt_CertDir
].arg
);
1309 pathname
= SECU_ConfigDirectory(NULL
);
1311 PR_Init(PR_SYSTEM_THREAD
, PR_PRIORITY_NORMAL
, 1);
1312 rv
= NSS_NoDB_Init(pathname
);
1313 if (rv
!= SECSuccess
) {
1314 fprintf(stderr
, "NSS_NoDB_Init failed\n");
1318 certHandle
= PORT_ZNew(NSSLOWCERTCertDBHandle
);
1320 SECU_PrintError(progName
, "unable to get database handle");
1323 certHandle
->ref
= 1;
1326 /* Open the possibly corrupt database. */
1327 if (dbck
.options
[opt_InputDB
].activated
) {
1328 PRFileInfo fileInfo
;
1329 fullname
= PR_smprintf("%s/%s", pathname
,
1330 dbck
.options
[opt_InputDB
].arg
);
1331 if (PR_GetFileInfo(fullname
, &fileInfo
) != PR_SUCCESS
) {
1332 fprintf(stderr
, "Unable to read file \"%s\".\n", fullname
);
1335 rv
= CERT_OpenCertDBFilename(certHandle
, fullname
, PR_TRUE
);
1339 /* Use the default. */
1341 fullname
= SECU_CertDBNameCallback(NULL
, CERT_DB_FILE_VERSION
);
1342 if (PR_GetFileInfo(fullname
, &fileInfo
) != PR_SUCCESS
) {
1343 fprintf(stderr
, "Unable to read file \"%s\".\n", fullname
);
1347 rv
= nsslowcert_OpenCertDB(certHandle
,
1348 PR_TRUE
, /* readOnly */
1349 NULL
, /* rdb appName */
1350 "", /* rdb prefix */
1351 dbck_certdb_name_cb
, /* namecb */
1352 pathname
, /* configDir */
1353 PR_FALSE
); /* volatile */
1357 SECU_PrintError(progName
, "unable to open cert database");
1361 if (dbck
.commands
[cmd_Debug
].activated
) {
1362 DBCK_DebugDB(certHandle
, dumpfile
, mailfile
);
1367 if (dbck
.commands
[cmd_Recover
].activated
) {
1368 DBCK_ReconstructDBFromCerts(certHandle
, newdbname
,
1369 dumpfile
, removeExpired
,
1370 requireProfile
, singleEntry
,
1371 dbck
.options
[opt_Prompt
].activated
);
1381 nsslowcert_ClosePermCertDB(certHandle
);
1382 PORT_Free(certHandle
);