]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/cspxutils/mdsLookup/mdsLookup.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / cspxutils / mdsLookup / mdsLookup.cpp
diff --git a/SecurityTests/cspxutils/mdsLookup/mdsLookup.cpp b/SecurityTests/cspxutils/mdsLookup/mdsLookup.cpp
new file mode 100644 (file)
index 0000000..b8649d0
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ * mdsLookup.cpp - demonstrate some MDS lookups
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <Security/mds.h>
+#include <Security/mds_schema.h>
+#include <Security/oidsalg.h>          // for TP OIDs
+#include "common.h"
+#include <strings.h>
+
+/* the memory functions themselves are in utilLib/common.c. */
+static CSSM_MEMORY_FUNCS memFuncs = {
+       appMalloc,
+       appFree,
+       appRealloc,
+       appCalloc,
+       NULL
+ };
+static void usage(char **argv)
+{
+       printf("Usage: %s [options]\n", argv[0]);
+       printf("Options:\n");
+       printf("   k   keep connected and go again\n");
+       exit(1);
+}
+
+#define NORM_KEY_LEN   10
+
+/* print a key name, padding out to NORM_KEY_LEN columns */
+static void printName(
+       const char *attrName)
+{
+       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(' ');
+       }
+
+}
+
+/* print value string, surrounded by single quotes, then a newline */
+static void printValue(
+       const CSSM_DATA *attrValue)
+{
+       printf("'");
+       for(uint32 dex=0; dex<attrValue->Length; dex++) {
+               printf("%c", attrValue->Data[dex]);
+       } 
+       printf("'\n");
+}
+
+/* Print one attribute value */
+static void dumpAttr(
+       CSSM_DB_ATTRIBUTE_FORMAT attrForm,
+       const CSSM_DATA *attrData)
+{
+       if((attrData == NULL) || (attrData->Data == NULL)) {
+               printf("<NULL DATA>\n");
+               return;
+       }
+       void *data = attrData->Data;
+       switch(attrForm) {
+               case CSSM_DB_ATTRIBUTE_FORMAT_STRING:
+                       printValue(attrData);
+                       break;
+               case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:   // not really supported in MDS
+               case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
+               {
+                       unsigned val = *(unsigned *)data;
+                       printf("0x%x\n", val);
+                       break;
+               }
+               case CSSM_DB_ATTRIBUTE_FORMAT_BLOB:
+               {
+                       printf("BLOB length %u : ", (unsigned)attrData->Length);
+                       for(unsigned i=0; i<attrData->Length; i++) {
+                               unsigned dat = attrData->Data[i];
+                               printf("%02X ", dat);
+                       }
+                       printf("\n");
+                       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(", ");
+                               }
+                               printf("0x%x", (unsigned)*uip++);
+                       }
+                       printf("]\n");
+                       break;
+               }
+               default:
+                       printf("***UNKNOWN FORMAT (%u), Length %u\n",
+                               (unsigned)attrForm, (unsigned)attrData->Length);
+                       break;
+       }
+}
+
+/*
+ * Vanilla "dump one record" routine. Assumes format of all attribute labels 
+ * as string.  
+ */
+static void dumpRecord(
+       const CSSM_DB_RECORD_ATTRIBUTE_DATA *recordAttrs)
+{
+       unsigned dex;
+       for(dex=0; dex<recordAttrs->NumberOfAttributes; dex++) {
+               const CSSM_DB_ATTRIBUTE_DATA *attrData = &recordAttrs->AttributeData[dex];
+               if(attrData->Info.AttributeNameFormat != 
+                               CSSM_DB_ATTRIBUTE_NAME_AS_STRING) {
+                       printf("***BAD ATTR_NAME FORMAT (%u)\n", 
+                               (unsigned)attrData->Info.AttributeNameFormat);
+                               continue;
+               }
+               const char *attrName = attrData->Info.Label.AttributeName;
+               printName(attrName);
+               printf(": ");
+               for(unsigned attrNum=0; attrNum<attrData->NumberOfValues; attrNum++) {
+                       dumpAttr(attrData->Info.AttributeFormat,        
+                               &attrData->Value[attrNum]);
+               }
+               if(attrData->NumberOfValues == 0) {
+                       printf("<<no values present>>\n");
+               }
+       }
+}
+
+/* free attribute(s) allocated by MDS */
+static void freeAttrs(
+       CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR       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;
+                       }
+                       appFree(data->Data, NULL);
+                       data->Data = NULL;
+                       data->Length = 0;
+               }
+               appFree(attrData->Value, NULL);
+               attrData->Value = NULL;
+       }
+}
+
+/*
+ * Core MDS lookup routine. Used in two situations. It's called by main() to perform
+ * a lookup in the CDSA Directory Database based one one key/value pair; this
+ * call fetches one attribute from the associated record - the GUID ("ModuleID" 
+ * in MDS lingo). Then the function calls itself to do a lookup in the Object DB,
+ * based on that GUID, in order to fetch the path of the module associated with
+ * that GUID. The first call (from main()) corresponds to an application's
+ * typical use of MDS. The recursive call, which does a lookup in the Object
+ * DB, corresponds to CSSM's typical use of MDS, which is to map a GUID to a 
+ * bundle path.
+ *
+ * The ModuleID and Path of all modules satisfying the initial search criteria
+ * are displayed on stdout. 
+ *
+ * Caller specifies one search attribute, by name, value,Êand value format. 
+ * Whether this is the first or second (recursive) call is indicated by the 
+ * cdsaLookup argument. That determines both the DB to search and the attribute
+ * to fetch (ModuleID or Path).
+ */
+static void doLookup(
+       MDS_FUNCS                                       *mdsFuncs,
+       
+       /* Two DBs and a flag indicating which one to use */
+       MDS_DB_HANDLE                           objDlDb,
+       MDS_DB_HANDLE                           cdsaDlDb,
+       bool                                            cdsaLookup,     // true - use cdsaDlDb; false - objDlDb
+       
+       /* Record type, a.k.a. Relation, e.g. MDS_CDSADIR_CSP_PRIMARY_RECORDTYPE */
+       CSSM_DB_RECORDTYPE                      recordType,     
+       
+       /* key, value, valForm, and valOp are the thing we search on */
+       /* Note CSSM_DB_ATTRIBUTE_NAME_FORMAT - the format of the attribute name - 
+        *    is always CSSM_DB_ATTRIBUTE_NAME_AS_STRING for MDS. */
+       const char                                      *key,           // e.g. "AlgType"
+       const void                                      *valPtr,        
+       unsigned                                        valLen,
+       CSSM_DB_ATTRIBUTE_FORMAT        valForm,        // CSSM_DB_ATTRIBUTE_FORMAT_STRING, etc.
+       CSSM_DB_OPERATOR                        valOp,          // normally CSSM_DB_EQUAL
+       
+       /* for display only */
+       const char                                      *srchStr)
+{
+       CSSM_QUERY                                              query;
+       CSSM_DB_UNIQUE_RECORD_PTR               record = NULL;
+       CSSM_HANDLE                                             resultHand;
+       CSSM_DB_RECORD_ATTRIBUTE_DATA   recordAttrs;
+       CSSM_SELECTION_PREDICATE                predicate;
+       CSSM_DATA                                               predData;
+       CSSM_DB_ATTRIBUTE_DATA                  outAttr;
+       CSSM_DB_ATTRIBUTE_INFO_PTR              attrInfo;
+       CSSM_RETURN                                             crtn;
+       MDS_DB_HANDLE                                   dlDb;
+       const char                                              *attrName;
+       
+       if(cdsaLookup) {
+               /* first call, fetching guid from the CDSA Directory DB */
+               dlDb = cdsaDlDb;
+               attrName = "ModuleID";
+       }
+       else {
+               /* recursive call, fetching path from Object DB */
+               dlDb = objDlDb;
+               attrName = "Path";
+       }
+       
+       /* We want one attributes back, name and format specified by caller */
+       recordAttrs.DataRecordType = recordType;
+       recordAttrs.SemanticInformation = 0;
+       recordAttrs.NumberOfAttributes = 1;
+       recordAttrs.AttributeData = &outAttr;
+
+       memset(&outAttr, 0, sizeof(CSSM_DB_ATTRIBUTE_DATA));
+       attrInfo = &outAttr.Info;
+       attrInfo->AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
+       attrInfo->Label.AttributeName = (char *)attrName;
+       attrInfo->AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_STRING;
+
+       /* one predicate - the caller's key and CSSM_DB_OPERATOR */
+       predicate.DbOperator = valOp;
+       predicate.Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
+       predicate.Attribute.Info.Label.AttributeName = (char *)key;
+       predicate.Attribute.Info.AttributeFormat = valForm;
+       predData.Data = (uint8 *)valPtr;
+       predData.Length = valLen;
+       predicate.Attribute.Value = &predData;
+       predicate.Attribute.NumberOfValues = 1;
+       
+       query.RecordType = recordType;
+       query.Conjunctive = CSSM_DB_NONE;
+       query.NumSelectionPredicates = 1;
+       query.SelectionPredicate = &predicate;
+       query.QueryLimits.TimeLimit = 0;                        // FIXME - meaningful?
+       query.QueryLimits.SizeLimit = 1;                        // FIXME - meaningful?
+       query.QueryFlags = 0;           // CSSM_QUERY_RETURN_DATA...FIXME - used?
+
+       crtn = mdsFuncs->DataGetFirst(dlDb,
+               &query,
+               &resultHand,
+               &recordAttrs,
+               NULL,                   // No data
+               &record);
+       switch(crtn) {
+               case CSSM_OK:
+                       break;          // proceed
+               case CSSMERR_DL_ENDOFDATA:
+                       printf("%s: no record found\n", srchStr);
+                       return;
+               default:
+                       printError("DataGetFirst", crtn);
+                       return;
+       }
+       /* dump this record, one attribute */
+       if(srchStr) {
+               /* not done on recursive call */
+               printf("%s found:\n", srchStr);         
+       }
+       dumpRecord(&recordAttrs);
+       mdsFuncs->FreeUniqueRecord(dlDb, record);
+       
+       if(srchStr != NULL) {
+               /* 
+                * Now do a lookup in Object DB of this guid, looking for path. 
+                * Apps normally don't do this; this is what CSSM does when given
+                * the GUID of a module.
+                */
+               if(outAttr.Value == NULL) {
+                       printf("***Screwup: DataGetFirst worked, but no outAttr\n");
+                       return;
+               }
+               doLookup(mdsFuncs,
+                       objDlDb,
+                       cdsaDlDb,
+                       false,                                  // use objDlDb
+                       MDS_OBJECT_RECORDTYPE,
+                       "ModuleID",                             // key
+                       outAttr.Value->Data,    // valPtr, ModuleID, as string
+                       outAttr.Value->Length,  // valLen
+                       CSSM_DB_ATTRIBUTE_FORMAT_STRING,
+                       CSSM_DB_EQUAL,
+                       NULL);                                  // srchStr
+       }
+       freeAttrs(&recordAttrs);
+
+       /* now the rest of them */
+       for(;;) {
+               crtn = mdsFuncs->DataGetNext(dlDb,
+                       resultHand, 
+                       &recordAttrs,
+                       NULL,
+                       &record);
+               switch(crtn) {
+                       case CSSM_OK:
+                               dumpRecord(&recordAttrs);
+                               mdsFuncs->FreeUniqueRecord(cdsaDlDb, record);
+                               if(srchStr != NULL) {
+                                       if(outAttr.Value == NULL) {
+                                               printf("***Screwup: DataGetNext worked, but no outAttr\n");
+                                               return;
+                                       }
+                                       doLookup(mdsFuncs,
+                                               objDlDb,
+                                               cdsaDlDb,
+                                               false,                                  // use objDlDb
+                                               MDS_OBJECT_RECORDTYPE,
+                                               "ModuleID",                             // key
+                                               outAttr.Value->Data,    // valPtr, ModuleID, as string
+                                               outAttr.Value->Length,  // valLen
+                                               CSSM_DB_ATTRIBUTE_FORMAT_STRING,
+                                               CSSM_DB_EQUAL,
+                                               NULL);                                  // srchStr
+                               }
+                               freeAttrs(&recordAttrs);
+                               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)
+{
+       MDS_FUNCS                       mdsFuncs;
+       MDS_HANDLE                      mdsHand;
+       CSSM_RETURN             crtn;
+       int                             arg;
+       CSSM_DB_HANDLE          dbHand = 0;
+       MDS_DB_HANDLE           objDlDb;
+       MDS_DB_HANDLE           cdsaDlDb;
+       bool                            keepConnected = false;
+       uint32                          val;
+       
+       for(arg=2; arg<argc; arg++) {
+               switch(argv[arg][0]) {
+                       case 'k':
+                               keepConnected = true;
+                               break;
+                       default:
+                               usage(argv);
+               }
+       }
+       crtn = MDS_Initialize(NULL,             // callerGuid
+               &memFuncs,
+               &mdsFuncs,
+               &mdsHand);
+       if(crtn) {
+               printError("MDS_Initialize", crtn);
+               exit(1);
+       }
+
+       do {
+               /* 
+                * Open both MDS DBs - apps normally only have to open 
+                * MDS_CDSA_DIRECTORY_NAME.
+                */
+               crtn = mdsFuncs.DbOpen(mdsHand,
+                       MDS_OBJECT_DIRECTORY_NAME,
+                       NULL,                           // DbLocation
+                       CSSM_DB_ACCESS_READ,
+                       NULL,                           // AccessCred - hopefully optional 
+                       NULL,                           // OpenParameters
+                       &dbHand);
+               if(crtn) {
+                       printError("DbOpen(MDS_OBJECT_DIRECTORY_NAME)", crtn);
+                       exit(1);
+               }
+               objDlDb.DLHandle = mdsHand;
+               objDlDb.DBHandle = dbHand;
+               
+               crtn = mdsFuncs.DbOpen(mdsHand,
+                       MDS_CDSA_DIRECTORY_NAME,
+                       NULL,                           // DbLocation
+                       CSSM_DB_ACCESS_READ,
+                       NULL,                           // AccessCred - hopefully optional 
+                       NULL,                           // OpenParameters
+                       &dbHand);
+               if(crtn) {
+                       printError("DbOpen(MDS_CDSA_DIRECTORY_NAME)", crtn);
+                       exit(1);
+               }
+               cdsaDlDb.DLHandle = mdsHand;
+               cdsaDlDb.DBHandle = dbHand;
+               
+               /* 
+                * Do some typical lookups.
+                */
+
+               /* a CSP which can do SHA1 digest */
+               val = CSSM_ALGID_SHA1;
+               doLookup(&mdsFuncs,
+                       objDlDb,
+                       cdsaDlDb,
+                       true,
+                       MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE,
+                       "AlgType",
+                       &val,
+                       sizeof(uint32),
+                       CSSM_DB_ATTRIBUTE_FORMAT_UINT32,
+                       CSSM_DB_EQUAL,
+                       "CSP for SHA1 digest");
+               
+               /* a TP which can do iSign verification */
+               doLookup(&mdsFuncs,
+                       objDlDb,
+                       cdsaDlDb,
+                       true,
+                       MDS_CDSADIR_TP_OIDS_RECORDTYPE,
+                       "OID",
+                       CSSMOID_APPLE_ISIGN.Data,
+                       CSSMOID_APPLE_ISIGN.Length,
+                       CSSM_DB_ATTRIBUTE_FORMAT_BLOB,
+                       CSSM_DB_EQUAL,
+                       "TP for CSSMOID_APPLE_ISIGN policy");
+
+               /* an X509-savvy CL */
+               /* Very weird data form - two fields in one 32-bit word */
+               val = (CSSM_CERT_X_509v3 << 16) | CSSM_CERT_ENCODING_DER;
+               doLookup(&mdsFuncs,
+                       objDlDb,
+                       cdsaDlDb,
+                       true,
+                       MDS_CDSADIR_CL_PRIMARY_RECORDTYPE,
+                       "CertTypeFormat",
+                       &val,
+                       sizeof(uint32),
+                       CSSM_DB_ATTRIBUTE_FORMAT_UINT32,
+                       CSSM_DB_EQUAL,
+                       "X509 CL");
+
+               /* A DL which can do CSSM_DB_AND */
+               val = CSSM_DB_AND;
+               doLookup(&mdsFuncs,
+                       objDlDb,
+                       cdsaDlDb,
+                       true,
+                       MDS_CDSADIR_DL_PRIMARY_RECORDTYPE,
+                       "ConjunctiveOps",
+                       &val,
+                       sizeof(uint32),
+                       CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32,
+                       /* This is a multi-uint32, meaning we want to search for a
+                        * ConjunctiveOps which contains the specified value */
+                       CSSM_DB_CONTAINS,
+                       "DL with ConjunctiveOp CSSM_DB_AND");
+
+               /* a CSP which can do CSSM_ALGID_IDEA, should fail */
+               val = CSSM_ALGID_IDEA;
+               doLookup(&mdsFuncs,
+                       objDlDb,
+                       cdsaDlDb,
+                       true,
+                       MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE,
+                       "AlgType",
+                       &val,
+                       sizeof(uint32),
+                       CSSM_DB_ATTRIBUTE_FORMAT_UINT32,
+                       CSSM_DB_EQUAL,
+                       "CSP for CSSM_ALGID_BLOWFISH, expect failure");
+
+               /* a TP which can obtain a .mac signing certificate */
+               doLookup(&mdsFuncs,
+                       objDlDb,
+                       cdsaDlDb,
+                       true,
+                       MDS_CDSADIR_TP_OIDS_RECORDTYPE,
+                       "OID",
+                       CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN.Data,
+                       CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN.Length,
+                       CSSM_DB_ATTRIBUTE_FORMAT_BLOB,
+                       CSSM_DB_EQUAL,
+                       "TP for .mac signing certificate policy");
+
+               crtn = mdsFuncs.DbClose(objDlDb);
+               if(crtn) {
+                       printError("DbClose(objDlDb)", crtn);
+               }
+               crtn = mdsFuncs.DbClose(cdsaDlDb);
+               if(crtn) {
+                       printError("DbClose(cdsaDlDb)", crtn);
+               }
+               if(keepConnected) {
+                       printf("\n");
+                       fpurge(stdin);
+                       printf("Enter CR to go again: ");
+                       getchar();
+               }
+       } while(keepConnected);
+       crtn = MDS_Terminate(mdsHand);
+       if(crtn) {
+               printError("MDS_Terminate", crtn);
+       }
+       return 0;
+}