+++ /dev/null
-/* Copyright (c) 2002-2006 Apple Computer, Inc.
- *
- * dbTool.cpp - DL/DB tool.
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <time.h>
-#include <strings.h>
-#include <ctype.h>
-#include <Security/cssm.h>
-#include <Security/cssmapple.h>
-#include <Security/cssmapplePriv.h>
-#include "cspwrap.h"
-#include "common.h"
-#include "dbAttrs.h"
-#include "dbCert.h"
-#include "cspdlTesting.h"
-
-
-static void usage(char **argv)
-{
- printf("usage: %s dbFileName command [options]\n", argv[0]);
- printf("Commands:\n");
- printf(" r Dump Schema Relations\n");
- printf(" k Dump all keys\n");
- printf(" c Dump certs\n");
- printf(" a Dump all records\n");
- printf(" d Delete records (interactively)\n");
- printf(" D Delete records (noninteractively, requires really arg)\n");
- printf(" i Import bad cert and its (good) private key\n");
- printf("Options:\n");
- printf(" v verbose\n");
- printf(" q quiet\n");
- printf(" R really! (for D command)\n");
- printf(" d dump data\n");
- printf(" c=certFile\n");
- printf(" k=keyFile\n");
- exit(1);
-}
-
-
-static unsigned indentVal = 0;
-static void indentIncr()
-{
- indentVal += 3;
-}
-
-static void indentDecr()
-{
- if(indentVal) {
- indentVal -= 3;
- }
-}
-
-static void doIndent()
-{
- unsigned i;
- for(i=0; i<indentVal; i++) {
- printf(" ");
- }
-}
-
-#define NORM_KEY_LEN 20
-
-/* print an attribute name, padding out to NORM_KEY_LEN columns */
-static void printName(
- const CSSM_DB_ATTRIBUTE_INFO *attrInfo)
-{
- switch(attrInfo->AttributeNameFormat) {
- case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
- {
- char *attrName = attrInfo->Label.AttributeName;
- printf("%s", attrName);
- int len = strlen(attrName);
- if(len > NORM_KEY_LEN) {
- return;
- }
- int numSpaces = NORM_KEY_LEN - len;
- for(int i=0; i<numSpaces; i++) {
- putchar(' ');
- }
- break;
- }
- case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
- {
- /* OSType, endian dependent... */
- char *cp = (char *)&(attrInfo->Label.AttributeID);
- for(unsigned i=0; i<4; i++) {
- putchar(*cp++);
- }
- printf(" ");
- break;
- }
- default:
- printf("Unknown attribute name format (%u)\n",
- (unsigned)attrInfo->AttributeNameFormat);
- break;
- }
-}
-
-/*
- * Attempt to print a numeric value as a string, per a NameValuePair table.
- * If the value is in fact a collection of legal values (per the nameValues
- * array), the value will just be printed in hex.
- */
-static void printValueAsString(
- unsigned val,
- const NameValuePair *nameValues)
-{
- if(nameValues != NULL) {
- while(nameValues->name != NULL) {
- if(nameValues->value == val) {
- printf("%s", nameValues->name);
- return;
- }
- nameValues++;
- }
- }
- /* Oh well */
- printf("0x%x", val);
-}
-
-static void safePrint(
- uint8 *cp,
- uint32 len)
-{
- for(unsigned i=0; i<len; i++) {
- printf("%c", *cp++);
- }
-}
-
-/* See if a blob is printable. Used for BLOB and UINT32 types, the latter of
- * which is sometimes used for OSType representation of attr name. */
-bool isPrintable(
- const CSSM_DATA *dp)
-{
- bool printable = true;
- uint8 *cp = dp->Data;
- for(unsigned i=0; i<dp->Length; i++) {
- if(*cp == 0) {
- if(i != (dp->Length - 1)) {
- /* data contains NULL character before end */
- printable = false;
- }
- /* else end of string */
- break;
- }
- if(!isprint(*cp)) {
- printable = false;
- break;
- }
- cp++;
- }
- return printable;
-}
-
-#define MAX_BLOB_TO_PRINT 12
-static void printBlob(
- const CSSM_DATA *data)
-{
- unsigned toPrint = data->Length;
- if(toPrint > MAX_BLOB_TO_PRINT) {
- toPrint = MAX_BLOB_TO_PRINT;
- }
- for(unsigned i=0; i<toPrint; i++) {
- unsigned dat = data->Data[i];
- printf("%02X ", dat);
- }
- if(toPrint < data->Length) {
- printf("...");
- }
-}
-
-static void printAttrData(
- const CSSM_DB_ATTRIBUTE_INFO *attrInfo,
- const CSSM_DATA *attrData,
- const NameValuePair *nameValues) // optional
-{
- void *data = attrData->Data;
-
- switch(attrInfo->AttributeFormat) {
-
- case CSSM_DB_ATTRIBUTE_FORMAT_STRING:
- putchar('\'');
- safePrint(attrData->Data, attrData->Length);
- putchar('\'');
- break;
- case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:
- case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
- {
- unsigned val = *(unsigned *)data;
- printValueAsString(val, nameValues);
- break;
- }
- case CSSM_DB_ATTRIBUTE_FORMAT_BLOB:
- {
- printf("BLOB length %u : ", (unsigned)attrData->Length);
- /* see if it happens to be a printable string */
- if(isPrintable(attrData)) {
- putchar('\'');
- safePrint(attrData->Data, attrData->Length);
- putchar('\'');
- }
- else {
- printBlob(attrData);
- }
- break;
- }
- case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32:
- {
- printf("multi_int[");
- uint32 numInts = attrData->Length / sizeof(uint32);
- uint32 *uip = (uint32 *)data;
- for(unsigned i=0; i<numInts; i++) {
- if(i > 0) {
- printf(", ");
- }
- printValueAsString(*uip++, nameValues);
- }
- printf("]");
- break;
- }
- case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE:
- putchar('\'');
- safePrint(attrData->Data, attrData->Length);
- putchar('\'');
- break;
-
- default:
- printf("***UNKNOWN FORMAT (%u), Length %u",
- (unsigned)attrInfo->AttributeFormat, (unsigned)attrData->Length);
- break;
- }
-}
-
-/* free attribute(s) allocated by DL */
-static void freeAttrs(
- CSSM_DB_RECORD_ATTRIBUTE_DATA *recordAttrs)
-{
- unsigned i;
-
- for(i=0; i<recordAttrs->NumberOfAttributes; i++) {
- CSSM_DB_ATTRIBUTE_DATA_PTR attrData = &recordAttrs->AttributeData[i];
- if(attrData == NULL) {
- /* fault of caller, who allocated the CSSM_DB_ATTRIBUTE_DATA */
- printf("***freeAttrs screwup: NULL attrData\n");
- return;
- }
- unsigned j;
- for(j=0; j<attrData->NumberOfValues; j++) {
- CSSM_DATA_PTR data = &attrData->Value[j];
- if(data == NULL) {
- /* fault of MDS, who said there was a value here */
- printf("***freeAttrs screwup: NULL data\n");
- return;
- }
- CSSM_FREE(data->Data);
- data->Data = NULL;
- data->Length = 0;
- }
- CSSM_FREE(attrData->Value);
- attrData->Value = NULL;
- }
-}
-
-static void dumpDataBlob(
- const CSSM_DATA *datap)
-{
- doIndent();
- printf("Record data length %lu ", datap->Length);
- if(datap->Length != 0) {
- printf(" : ");
- printBlob(datap);
- }
- printf("\n");
-}
-
-static void dumpRecordAttrs(
- const CSSM_DB_RECORD_ATTRIBUTE_DATA *recordAttrs,
- const NameValuePair **nameValues, // parallel to recordAttrs
- const CSSM_DATA *recordData = NULL) // optional data
-{
- unsigned valNum;
- unsigned dex;
-
- for(dex=0; dex<recordAttrs->NumberOfAttributes; dex++) {
- const CSSM_DB_ATTRIBUTE_DATA *attrData = &recordAttrs->AttributeData[dex];
- doIndent();
- printName(&attrData->Info);
- printf(": ");
- if(attrData->NumberOfValues == 0) {
- printf("<<not present>>\n");
- continue;
- }
- for(valNum=0; valNum<attrData->NumberOfValues; valNum++) {
- printAttrData(&attrData->Info, &attrData->Value[valNum], nameValues[dex]);
- if(valNum < (attrData->NumberOfValues - 1)) {
- printf(", ");
- }
- }
- printf("\n");
- }
- if(recordData) {
- dumpDataBlob(recordData);
- }
-}
-
-static void dumpRelation(
- CSSM_DL_DB_HANDLE dlDbHand,
- const RelationInfo *relInfo,
- CSSM_BOOL dumpData)
-{
- CSSM_QUERY query;
- CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
- CSSM_RETURN crtn;
- CSSM_HANDLE resultHand;
- CSSM_DB_ATTRIBUTE_DATA *attrs;
- CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
- unsigned attrDex;
- unsigned recNum = 0;
- uint32 numAttrs = relInfo->NumberOfAttributes;
- CSSM_DATA data = {0, NULL};
- CSSM_DATA_PTR datap = NULL;
-
- if(dumpData) {
- datap = &data;
- }
-
- /* build an attr array from known schema */
- attrs = (CSSM_DB_ATTRIBUTE_DATA *)CSSM_MALLOC(
- sizeof(CSSM_DB_ATTRIBUTE_DATA) * numAttrs);
- memset(attrs, 0, sizeof(CSSM_DB_ATTRIBUTE_DATA) * numAttrs);
- for(attrDex=0; attrDex<numAttrs; attrDex++) {
- attrs[attrDex].Info = relInfo->AttributeInfo[attrDex];
- }
- recordAttrs.DataRecordType = relInfo->DataRecordType;
- recordAttrs.NumberOfAttributes = numAttrs;
- recordAttrs.AttributeData = attrs;
-
- /* just search by recordType, no predicates */
- query.RecordType = relInfo->DataRecordType;
- query.Conjunctive = CSSM_DB_NONE;
- query.NumSelectionPredicates = 0;
- query.SelectionPredicate = NULL;
- query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
- query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
- query.QueryFlags = 0; // CSSM_QUERY_RETURN_DATA...FIXME - used?
-
- crtn = CSSM_DL_DataGetFirst(dlDbHand,
- &query,
- &resultHand,
- &recordAttrs,
- datap,
- &record);
- switch(crtn) {
- case CSSM_OK:
- break; // proceed
- case CSSMERR_DL_ENDOFDATA:
- printf("%s: no record found\n", relInfo->relationName);
- CSSM_FREE(attrs);
- return;
- default:
- printError("DataGetFirst", crtn);
- CSSM_FREE(attrs);
- return;
- }
- printf("%s:\n", relInfo->relationName);
- printf(" record %d; numAttrs %d:\n",
- recNum++, (int)recordAttrs.NumberOfAttributes);
- indentIncr();
-
- dumpRecordAttrs(&recordAttrs, relInfo->nameValues, datap);
- CSSM_DL_FreeUniqueRecord(dlDbHand, record);
- freeAttrs(&recordAttrs);
- if(datap) {
- CSSM_FREE(datap->Data);
- }
-
- /* now the rest of them */
- /* hopefully we don't have to re-init the recordAttr array */
- for(;;) {
- crtn = CSSM_DL_DataGetNext(dlDbHand,
- resultHand,
- &recordAttrs,
- datap,
- &record);
- switch(crtn) {
- case CSSM_OK:
- printf(" record %d; numAttrs %d:\n",
- recNum++, (int)recordAttrs.NumberOfAttributes);
- dumpRecordAttrs(&recordAttrs, relInfo->nameValues, datap);
- CSSM_DL_FreeUniqueRecord(dlDbHand, record);
- freeAttrs(&recordAttrs);
- if(datap) {
- CSSM_FREE(datap->Data);
- }
- break; // and go again
- case CSSMERR_DL_ENDOFDATA:
- /* normal termination */
- break;
- default:
- printError("DataGetNext", crtn);
- break;
- }
- if(crtn != CSSM_OK) {
- break;
- }
- }
- indentDecr();
- CSSM_FREE(attrs);
-}
-
-/*
- * Given a record type and a CSSM_DB_UNIQUE_RECORD, fetch and parse all the
- * attributes we can.
- */
-static void fetchParseRecord(
- CSSM_DL_DB_HANDLE dlDbHand,
- CSSM_DB_RECORD_ATTRIBUTE_DATA *inRecordAttrs,
- CSSM_DB_UNIQUE_RECORD_PTR record,
- const CSSM_DATA_PTR datap,
- CSSM_BOOL dumpData)
-{
- const RelationInfo *relInfo = NULL;
-
- /* infer RelationInfo from recordType */
- switch(inRecordAttrs->DataRecordType) {
- case CSSM_DL_DB_RECORD_PUBLIC_KEY:
- case CSSM_DL_DB_RECORD_PRIVATE_KEY:
- case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
- relInfo = &allKeysRelation;
- break;
- case CSSM_DL_DB_RECORD_GENERIC_PASSWORD:
- case CSSM_DL_DB_RECORD_INTERNET_PASSWORD:
- case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD:
- relInfo = &genericKcRelation;
- break;
- case CSSM_DL_DB_RECORD_CERT:
- relInfo = &certRecordRelation;
- break;
- case CSSM_DL_DB_RECORD_X509_CERTIFICATE:
- relInfo = &x509CertRecordRelation;
- break;
- case CSSM_DL_DB_RECORD_X509_CRL:
- relInfo = &x509CrlRecordRelation;
- break;
- case CSSM_DL_DB_RECORD_USER_TRUST:
- relInfo = &userTrustRelation;
- break;
- case CSSM_DL_DB_RECORD_UNLOCK_REFERRAL:
- relInfo = &referralRecordRelation;
- break;
- case CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE:
- relInfo = &extendedAttrRelation;
- break;
- case DBBlobRelationID:
- relInfo = NULL;
- doIndent();
- printf("--- No attributes ---\n");
- if(dumpData) {
- dumpDataBlob(datap);
- }
- return;
- default:
- doIndent();
- printf("<<unparsed>>\n");
- if(dumpData) {
- doIndent();
- printf("Record blob (length %ld): ", datap->Length);
- printBlob(datap);
- printf("\n");
- }
- return;
- }
-
- CSSM_DB_ATTRIBUTE_DATA *attrs = NULL;
- CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
- unsigned attrDex;
- uint32 numAttrs = relInfo->NumberOfAttributes;
- CSSM_RETURN crtn;
- CSSM_DATA recordData = {0, NULL};
- CSSM_DATA_PTR recordDataP = dumpData ? &recordData : NULL;
-
- /* build an attr array from known schema */
- attrs = (CSSM_DB_ATTRIBUTE_DATA *)CSSM_MALLOC(
- sizeof(CSSM_DB_ATTRIBUTE_DATA) * numAttrs);
- memset(attrs, 0, sizeof(CSSM_DB_ATTRIBUTE_DATA) * numAttrs);
- for(attrDex=0; attrDex<numAttrs; attrDex++) {
- attrs[attrDex].Info = relInfo->AttributeInfo[attrDex];
- }
-
- /* from inRecordAttrs, not the relInfo, which could be a typeless template */
- recordAttrs.DataRecordType = relInfo->DataRecordType;
- recordAttrs.NumberOfAttributes = numAttrs;
- recordAttrs.AttributeData = attrs;
-
- crtn = CSSM_DL_DataGetFromUniqueRecordId(dlDbHand,
- record,
- &recordAttrs,
- recordDataP);
- if(crtn) {
- printError("CSSM_DL_DataGetFromUniqueRecordId", crtn);
- goto abort;
- }
- dumpRecordAttrs(&recordAttrs, relInfo->nameValues, recordDataP);
- freeAttrs(&recordAttrs);
- if(recordData.Data) {
- CSSM_FREE(recordData.Data);
- }
-abort:
- if(attrs) {
- CSSM_FREE(attrs);
- }
- return;
-}
-
-static void deleteRecord(
- CSSM_DL_DB_HANDLE dlDbHand,
- CSSM_DB_UNIQUE_RECORD_PTR record,
- CSSM_BOOL interact)
-{
- if(interact) {
- fpurge(stdin);
- printf("\nDelete this record [y/anything] ? ");
- char resp = getchar();
- if(resp != 'y') {
- return;
- }
- }
- CSSM_RETURN crtn;
- crtn = CSSM_DL_DataDelete(dlDbHand, record);
- if(crtn) {
- printError("CSSM_DL_DataDelete", crtn);
- }
- else if(interact) {
- printf("...record deleted\n\n");
- }
-}
-
-/*
- * In this case we search for CSSM_DL_DB_RECORD_ANY. The current schema results
- * in no single attribute which all interesting records have in common, so we
- * can't grab any attributes at GetFirst/GetNext time. Instead we have
- * to deal with the returned record per its record type.
- */
-static void dumpAllRecords(
- CSSM_DL_DB_HANDLE dlDbHand,
- CSSM_BOOL deleteAll,
- CSSM_BOOL interact,
- CSSM_BOOL dumpData)
-{
- CSSM_QUERY query;
- CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
- CSSM_RETURN crtn;
- CSSM_HANDLE resultHand;
- CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
- CSSM_DATA data = {0, NULL};
- CSSM_DATA_PTR datap = NULL;
-
- if(dumpData) {
- datap = &data;
- }
-
- recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_ANY;
- recordAttrs.NumberOfAttributes = 0;
- recordAttrs.AttributeData = NULL;
-
- /* just search by recordType, no predicates */
- query.RecordType = CSSM_DL_DB_RECORD_ANY;
- query.Conjunctive = CSSM_DB_NONE;
- query.NumSelectionPredicates = 0;
- query.SelectionPredicate = NULL;
- query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
- query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
- query.QueryFlags = 0; // CSSM_QUERY_RETURN_DATA...FIXME - used?
-
- crtn = CSSM_DL_DataGetFirst(dlDbHand,
- &query,
- &resultHand,
- &recordAttrs,
- datap,
- &record);
- switch(crtn) {
- case CSSM_OK:
- break; // proceed
- case CSSMERR_DL_ENDOFDATA:
- printf("CSSM_DL_DB_RECORD_ANY: no record found\n");
- return;
- default:
- printError("DataGetFirst", crtn);
- return;
- }
-
- /* could be anything; check it out */
- if(interact) {
- doIndent();
- printValueAsString(recordAttrs.DataRecordType, recordTypeNames);
- printf("\n");
- indentIncr();
- fetchParseRecord(dlDbHand, &recordAttrs, record, datap, dumpData);
- indentDecr();
- }
- if(deleteAll && (recordAttrs.DataRecordType != DBBlobRelationID)) {
- /* NEVER delete a DBBlob */
- deleteRecord(dlDbHand, record, interact);
- }
- CSSM_DL_FreeUniqueRecord(dlDbHand, record);
-
- /* now the rest of them */
- /* hopefully we don't have to re-init the recordAttr array */
- for(;;) {
- crtn = CSSM_DL_DataGetNext(dlDbHand,
- resultHand,
- &recordAttrs,
- datap,
- &record);
- switch(crtn) {
- case CSSM_OK:
- if(interact) {
- doIndent();
- printValueAsString(recordAttrs.DataRecordType, recordTypeNames);
- printf("\n");
- indentIncr();
- fetchParseRecord(dlDbHand, &recordAttrs, record, datap, dumpData);
- indentDecr();
- }
- if(deleteAll && (recordAttrs.DataRecordType != DBBlobRelationID)) {
- /* NEVER delete a DBBlob */
- deleteRecord(dlDbHand, record, interact);
- }
- CSSM_DL_FreeUniqueRecord(dlDbHand, record);
- break; // and go again
- case CSSMERR_DL_ENDOFDATA:
- /* normal termination */
- break;
- default:
- printError("DataGetNext", crtn);
- break;
- }
- if(crtn != CSSM_OK) {
- break;
- }
- }
-}
-
-int main(
- int argc,
- char **argv)
-{
- int arg;
- char *argp;
- char *dbFileName;
- char cmd;
- CSSM_DL_DB_HANDLE dlDbHand;
- CSSM_BOOL verbose = CSSM_FALSE;
- CSSM_BOOL quiet = CSSM_FALSE;
- char *certFile = NULL;
- char *keyFile = NULL;
- CSSM_BOOL interact = CSSM_TRUE;
- CSSM_BOOL dumpData = CSSM_FALSE;
-
- /* should be cmd line opts */
- CSSM_ALGORITHMS keyAlg = CSSM_ALGID_RSA;
- CSSM_BOOL pemFormat = CSSM_FALSE;
- CSSM_KEYBLOB_FORMAT keyFormat = CSSM_KEYBLOB_RAW_FORMAT_NONE;
- CSSM_RETURN crtn = CSSM_OK;
-
- if(argc < 3) {
- usage(argv);
- }
- dbFileName = argv[1];
- cmd = argv[2][0];
-
- for(arg=3; arg<argc; arg++) {
- argp = argv[arg];
- switch(argp[0]) {
- case 'v':
- verbose = CSSM_TRUE;
- break;
- case 'q':
- quiet = CSSM_TRUE;
- break;
- case 'R':
- if(cmd == 'D') {
- interact = CSSM_FALSE;
- }
- break;
- case 'd':
- dumpData = CSSM_TRUE;
- break;
- case 'c':
- certFile = &argp[2];
- break;
- case 'k':
- keyFile = &argp[2];
- break;
- case 'h':
- default:
- usage(argv);
- }
- }
-
- dlDbHand.DLHandle = dlStartup();
- if(dlDbHand.DLHandle == 0) {
- exit(1);
- }
- if(cmd == 'i') {
- crtn = importBadCert(dlDbHand.DLHandle, dbFileName, certFile,
- keyFile, keyAlg, pemFormat, keyFormat, verbose);
- goto done;
- }
- crtn = dbCreateOpen(dlDbHand.DLHandle, dbFileName,
- CSSM_FALSE, CSSM_FALSE, NULL, &dlDbHand.DBHandle);
- if(crtn) {
- exit(1);
- }
- switch(cmd) {
- case 'r':
- dumpRelation(dlDbHand, &schemaInfoRelation, dumpData);
- break;
- case 'k':
- dumpRelation(dlDbHand, &allKeysRelation, dumpData);
- break;
- case 'c':
- dumpRelation(dlDbHand, &x509CertRecordRelation, dumpData);
- break;
- case 'a':
- dumpAllRecords(dlDbHand, CSSM_FALSE, CSSM_TRUE, dumpData);
- break;
- case 'd':
- case 'D':
- dumpAllRecords(dlDbHand, CSSM_TRUE, interact, dumpData);
- if(!interact) {
- /* we ignored errors.... */
- if(!quiet) {
- printf("...DB %s wiped clean\n", dbFileName);
- }
- }
- break;
- default:
- usage(argv);
- }
- CSSM_DL_DbClose(dlDbHand);
-done:
- CSSM_ModuleDetach(dlDbHand.DLHandle);
- return crtn;
-}