📄 dbck.c
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//*** dbck.c**** utility for fixing corrupt cert databases***/#include <stdio.h>#include <string.h>#include "secutil.h"#include "cdbhdl.h"#include "certdb.h"#include "cert.h"#include "nspr.h"#include "prtypes.h"#include "prtime.h"#include "prlong.h"static char *progName;/* placeholders for pointer error types */static void *WrongEntry;static void *NoNickname;static void *NoSMime;enum { GOBOTH = 0, GORIGHT, GOLEFT};typedef struct{ PRBool verbose; PRBool dograph; PRFileDesc *out; PRFileDesc *graphfile; int dbErrors[10];} dbDebugInfo;/* * A list node for a cert db entry. The index is a unique identifier * to use for creating generic maps of a db. This struct handles * the cert, nickname, and smime db entry types, as all three have a * single handle to a subject entry. * This structure is pointed to by certDBEntryListNode->appData. */typedef struct { PRArenaPool *arena; int index; certDBEntryListNode *pSubject;} certDBEntryMap;/* * Subject entry is special case, it has bidirectional handles. One * subject entry can point to several certs (using the same DN), and * a nickname and/or smime entry. * This structure is pointed to by certDBEntryListNode->appData. */typedef struct{ PRArenaPool *arena; int index; int numCerts; certDBEntryListNode **pCerts; certDBEntryListNode *pNickname; certDBEntryListNode *pSMime;} certDBSubjectEntryMap;/* * A map of a certdb. */typedef struct{ int numCerts; int numSubjects; int numNicknames; int numSMime; certDBEntryListNode certs; /* pointer to head of cert list */ certDBEntryListNode subjects; /* pointer to head of subject list */ certDBEntryListNode nicknames; /* pointer to head of nickname list */ certDBEntryListNode smime; /* pointer to head of smime list */} certDBArray;/* Cast list to the base element, a certDBEntryListNode. */#define LISTNODE_CAST(node) \ ((certDBEntryListNode *)(node))static void Usage(char *progName){#define FPS fprintf(stderr, FPS "Type %s -H for more detailed descriptions\n", progName); FPS "Usage: %s -D [-d certdir] [-i dbname] [-m] [-v [-f dumpfile]]\n", progName); FPS " %s -R -o newdbname [-d certdir] [-i dbname] [-aprsx] [-v [-f dumpfile]]\n", progName); exit(-1);}static voidLongUsage(char *progName){ FPS "%-15s Display this help message.\n", "-H"); FPS "%-15s Dump analysis. No changes will be made to the database.\n", "-D"); FPS "%-15s Cert database directory (default is ~/.netscape)\n", " -d certdir"); FPS "%-15s Input cert database name (default is cert7.db)\n", " -i dbname"); FPS "%-15s Mail a graph of the database to certdb@netscape.com.\n", " -m"); FPS "%-15s This will produce an index graph of your cert db and send\n", ""); FPS "%-15s it to Netscape for analysis. Personal info will be removed.\n", ""); FPS "%-15s Verbose mode. Dumps the entire contents of your cert7.db.\n", " -v"); FPS "%-15s File to dump verbose output into.\n", " -f dumpfile"); FPS "%-15s Repair the database. The program will look for broken\n", "-R"); FPS "%-15s dependencies between subject entries and certificates,\n", ""); FPS "%-15s between nickname entries and subjects, and between SMIME\n", ""); FPS "%-15s profiles and subjects. Any duplicate entries will be\n", ""); FPS "%-15s removed, any missing entries will be created.\n", ""); FPS "%-15s File to store new database in (default is new_cert7.db)\n", " -o newdbname"); FPS "%-15s Cert database directory (default is ~/.netscape)\n", " -d certdir"); FPS "%-15s Input cert database name (default is cert7.db)\n", " -i dbname"); FPS "%-15s Prompt before removing any certificates.\n", " -p"); FPS "%-15s Keep all possible certificates. Only remove certificates\n", " -a"); FPS "%-15s which prevent creation of a consistent database. Thus any\n", ""); FPS "%-15s expired or redundant entries will be kept.\n", ""); FPS "%-15s Keep redundant nickname/email entries. It is possible\n", " -r"); FPS "%-15s only one such entry will be usable.\n", ""); FPS "%-15s Don't require an S/MIME profile in order to keep an S/MIME\n", " -s"); FPS "%-15s cert. An empty profile will be created.\n", ""); FPS "%-15s Keep expired certificates.\n", " -x"); FPS "%-15s Verbose mode - report all activity while recovering db.\n", " -v"); FPS "%-15s File to dump verbose output into.\n", " -f dumpfile"); FPS "\n"); exit(-1);#undef FPS}/******************************************************************* * * Functions for dbck. * ******************************************************************/voidprintHexString(PRFileDesc *out, SECItem *hexval){ int i; for (i = 0; i < hexval->len; i++) { if (i != hexval->len - 1) { PR_fprintf(out, "%02x:", hexval->data[i]); } else { PR_fprintf(out, "%02x", hexval->data[i]); } } PR_fprintf(out, "\n");}typedef enum {/* 0*/ NoSubjectForCert = 0,/* 1*/ SubjectHasNoKeyForCert,/* 2*/ NoNicknameOrSMimeForSubject,/* 3*/ WrongNicknameForSubject,/* 4*/ NoNicknameEntry,/* 5*/ WrongSMimeForSubject,/* 6*/ NoSMimeEntry,/* 7*/ NoSubjectForNickname,/* 8*/ NoSubjectForSMime,/* 9*/ NicknameAndSMimeEntry} dbErrorType;static char *dbErrorString[] = {/* 0*/ "<CERT ENTRY>\nDid not find a subject entry for this certificate.",/* 1*/ "<SUBJECT ENTRY>\nSubject has certKey which is not in db.",/* 2*/ "<SUBJECT ENTRY>\nSubject does not have a nickname or email address.",/* 3*/ "<SUBJECT ENTRY>\nUsing this subject's nickname, found a nickname entry for a different subject.",/* 4*/ "<SUBJECT ENTRY>\nDid not find a nickname entry for this subject.",/* 5*/ "<SUBJECT ENTRY>\nUsing this subject's email, found an S/MIME entry for a different subject.",/* 6*/ "<SUBJECT ENTRY>\nDid not find an S/MIME entry for this subject.",/* 7*/ "<NICKNAME ENTRY>\nDid not find a subject entry for this nickname.",/* 8*/ "<S/MIME ENTRY>\nDid not find a subject entry for this S/MIME profile.",};SECStatusdumpCertificate(CERTCertificate *cert, int num, PRFileDesc *outfile){ int userCert = 0; CERTCertTrust *trust = cert->trust; userCert = (SEC_GET_TRUST_FLAGS(trust, trustSSL) & CERTDB_USER) || (SEC_GET_TRUST_FLAGS(trust, trustEmail) & CERTDB_USER) || (SEC_GET_TRUST_FLAGS(trust, trustObjectSigning) & CERTDB_USER); if (num >= 0) { PR_fprintf(outfile, "Certificate: %3d\n", num); } else { PR_fprintf(outfile, "Certificate:\n"); } PR_fprintf(outfile, "----------------\n"); if (userCert) PR_fprintf(outfile, "(User Cert)\n"); PR_fprintf(outfile, "## SUBJECT: %s\n", cert->subjectName); PR_fprintf(outfile, "## ISSUER: %s\n", cert->issuerName); PR_fprintf(outfile, "## SERIAL NUMBER: "); printHexString(outfile, &cert->serialNumber); { /* XXX should be separate function. */ int64 timeBefore, timeAfter; PRExplodedTime beforePrintable, afterPrintable; char *beforestr, *afterstr; DER_UTCTimeToTime(&timeBefore, &cert->validity.notBefore); DER_UTCTimeToTime(&timeAfter, &cert->validity.notAfter); PR_ExplodeTime(timeBefore, PR_GMTParameters, &beforePrintable); PR_ExplodeTime(timeAfter, PR_GMTParameters, &afterPrintable); beforestr = PORT_Alloc(100); afterstr = PORT_Alloc(100); PR_FormatTime(beforestr, 100, "%a %b %d %H:%M:%S %Y", &beforePrintable); PR_FormatTime(afterstr, 100, "%a %b %d %H:%M:%S %Y", &afterPrintable); PR_fprintf(outfile, "## VALIDITY: %s to %s\n", beforestr, afterstr); } PR_fprintf(outfile, "\n"); return SECSuccess;}SECStatusdumpCertEntry(certDBEntryCert *entry, int num, PRFileDesc *outfile){ CERTCertificate *cert; cert = CERT_DecodeDERCertificate(&entry->derCert, PR_FALSE, NULL); if (!cert) { fprintf(stderr, "Failed to decode certificate.\n"); return SECFailure; } cert->trust = &entry->trust; dumpCertificate(cert, num, outfile); CERT_DestroyCertificate(cert); return SECSuccess;}SECStatusdumpSubjectEntry(certDBEntrySubject *entry, int num, PRFileDesc *outfile){ char *subjectName; subjectName = CERT_DerNameToAscii(&entry->derSubject); PR_fprintf(outfile, "Subject: %3d\n", num); PR_fprintf(outfile, "------------\n"); PR_fprintf(outfile, "## %s\n", subjectName); if (entry->nickname) PR_fprintf(outfile, "## Subject nickname: %s\n", entry->nickname); if (entry->emailAddr) PR_fprintf(outfile, "## Subject email address: %s\n", entry->emailAddr); PR_fprintf(outfile, "## This subject has %d cert(s).\n", entry->ncerts); PR_fprintf(outfile, "\n"); PORT_Free(subjectName); return SECSuccess;}SECStatusdumpNicknameEntry(certDBEntryNickname *entry, int num, PRFileDesc *outfile){ PR_fprintf(outfile, "Nickname: %3d\n", num); PR_fprintf(outfile, "-------------\n"); PR_fprintf(outfile, "## \"%s\"\n\n", entry->nickname); return SECSuccess;}SECStatusdumpSMimeEntry(certDBEntrySMime *entry, int num, PRFileDesc *outfile){ PR_fprintf(outfile, "S/MIME Profile: %3d\n", num); PR_fprintf(outfile, "-------------------\n"); PR_fprintf(outfile, "## \"%s\"\n", entry->emailAddr); PR_fprintf(outfile, "## OPTIONS: "); printHexString(outfile, &entry->smimeOptions); PR_fprintf(outfile, "## TIMESTAMP: "); printHexString(outfile, &entry->optionsDate); PR_fprintf(outfile, "\n"); return SECSuccess;}SECStatusmapCertEntries(certDBArray *dbArray){ certDBEntryCert *certEntry; certDBEntrySubject *subjectEntry; certDBEntryListNode *certNode, *subjNode; certDBSubjectEntryMap *smap; certDBEntryMap *map; PRArenaPool *tmparena; SECItem derSubject; SECItem certKey; PRCList *cElem, *sElem; int i; /* Arena for decoded entries */ tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (tmparena == NULL) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } /* Iterate over cert entries and map them to subject entries. * NOTE: mapSubjectEntries must be called first to alloc memory * for array of subject->cert map. */ for (cElem = PR_LIST_HEAD(&dbArray->certs.link); cElem != &dbArray->certs.link; cElem = PR_NEXT_LINK(cElem)) { certNode = LISTNODE_CAST(cElem); certEntry = (certDBEntryCert *)&certNode->entry; map = (certDBEntryMap *)certNode->appData; CERT_NameFromDERCert(&certEntry->derCert, &derSubject); CERT_KeyFromDERCert(tmparena, &certEntry->derCert, &certKey); /* Loop over found subjects for cert's DN. */ for (sElem = PR_LIST_HEAD(&dbArray->subjects.link); sElem != &dbArray->subjects.link; sElem = PR_NEXT_LINK(sElem)) { subjNode = LISTNODE_CAST(sElem);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -