]> git.saurik.com Git - apple/security.git/blob - SecurityTests/cspxutils/mdsLookup/mdsLookup.cpp
Security-57031.10.10.tar.gz
[apple/security.git] / SecurityTests / cspxutils / mdsLookup / mdsLookup.cpp
1 /*
2 * mdsLookup.cpp - demonstrate some MDS lookups
3 */
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <Security/mds.h>
8 #include <Security/mds_schema.h>
9 #include <Security/oidsalg.h> // for TP OIDs
10 #include "common.h"
11 #include <strings.h>
12
13 /* the memory functions themselves are in utilLib/common.c. */
14 static CSSM_MEMORY_FUNCS memFuncs = {
15 appMalloc,
16 appFree,
17 appRealloc,
18 appCalloc,
19 NULL
20 };
21
22 static void usage(char **argv)
23 {
24 printf("Usage: %s [options]\n", argv[0]);
25 printf("Options:\n");
26 printf(" k keep connected and go again\n");
27 exit(1);
28 }
29
30 #define NORM_KEY_LEN 10
31
32 /* print a key name, padding out to NORM_KEY_LEN columns */
33 static void printName(
34 const char *attrName)
35 {
36 printf(" %s", attrName);
37 int len = strlen(attrName);
38 if(len > NORM_KEY_LEN) {
39 return;
40 }
41 int numSpaces = NORM_KEY_LEN - len;
42 for(int i=0; i<numSpaces; i++) {
43 putchar(' ');
44 }
45
46 }
47
48 /* print value string, surrounded by single quotes, then a newline */
49 static void printValue(
50 const CSSM_DATA *attrValue)
51 {
52 printf("'");
53 for(uint32 dex=0; dex<attrValue->Length; dex++) {
54 printf("%c", attrValue->Data[dex]);
55 }
56 printf("'\n");
57 }
58
59 /* Print one attribute value */
60 static void dumpAttr(
61 CSSM_DB_ATTRIBUTE_FORMAT attrForm,
62 const CSSM_DATA *attrData)
63 {
64 if((attrData == NULL) || (attrData->Data == NULL)) {
65 printf("<NULL DATA>\n");
66 return;
67 }
68 void *data = attrData->Data;
69 switch(attrForm) {
70 case CSSM_DB_ATTRIBUTE_FORMAT_STRING:
71 printValue(attrData);
72 break;
73 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32: // not really supported in MDS
74 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
75 {
76 unsigned val = *(unsigned *)data;
77 printf("0x%x\n", val);
78 break;
79 }
80 case CSSM_DB_ATTRIBUTE_FORMAT_BLOB:
81 {
82 printf("BLOB length %u : ", (unsigned)attrData->Length);
83 for(unsigned i=0; i<attrData->Length; i++) {
84 unsigned dat = attrData->Data[i];
85 printf("%02X ", dat);
86 }
87 printf("\n");
88 break;
89 }
90 case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32:
91 {
92 printf("multi_int[");
93 uint32 numInts = attrData->Length / sizeof(uint32);
94 uint32 *uip = (uint32 *)data;
95 for(unsigned i=0; i<numInts; i++) {
96 if(i > 0) {
97 printf(", ");
98 }
99 printf("0x%x", (unsigned)*uip++);
100 }
101 printf("]\n");
102 break;
103 }
104 default:
105 printf("***UNKNOWN FORMAT (%u), Length %u\n",
106 (unsigned)attrForm, (unsigned)attrData->Length);
107 break;
108 }
109 }
110
111 /*
112 * Vanilla "dump one record" routine. Assumes format of all attribute labels
113 * as string.
114 */
115 static void dumpRecord(
116 const CSSM_DB_RECORD_ATTRIBUTE_DATA *recordAttrs)
117 {
118 unsigned dex;
119 for(dex=0; dex<recordAttrs->NumberOfAttributes; dex++) {
120 const CSSM_DB_ATTRIBUTE_DATA *attrData = &recordAttrs->AttributeData[dex];
121 if(attrData->Info.AttributeNameFormat !=
122 CSSM_DB_ATTRIBUTE_NAME_AS_STRING) {
123 printf("***BAD ATTR_NAME FORMAT (%u)\n",
124 (unsigned)attrData->Info.AttributeNameFormat);
125 continue;
126 }
127 const char *attrName = attrData->Info.Label.AttributeName;
128 printName(attrName);
129 printf(": ");
130 for(unsigned attrNum=0; attrNum<attrData->NumberOfValues; attrNum++) {
131 dumpAttr(attrData->Info.AttributeFormat,
132 &attrData->Value[attrNum]);
133 }
134 if(attrData->NumberOfValues == 0) {
135 printf("<<no values present>>\n");
136 }
137 }
138 }
139
140 /* free attribute(s) allocated by MDS */
141 static void freeAttrs(
142 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR recordAttrs)
143 {
144 unsigned i;
145
146 for(i=0; i<recordAttrs->NumberOfAttributes; i++) {
147 CSSM_DB_ATTRIBUTE_DATA_PTR attrData = &recordAttrs->AttributeData[i];
148 if(attrData == NULL) {
149 /* fault of caller, who allocated the CSSM_DB_ATTRIBUTE_DATA */
150 printf("***freeAttrs screwup: NULL attrData\n");
151 return;
152 }
153 unsigned j;
154 for(j=0; j<attrData->NumberOfValues; j++) {
155 CSSM_DATA_PTR data = &attrData->Value[j];
156 if(data == NULL) {
157 /* fault of MDS, who said there was a value here */
158 printf("***freeAttrs screwup: NULL data\n");
159 return;
160 }
161 appFree(data->Data, NULL);
162 data->Data = NULL;
163 data->Length = 0;
164 }
165 appFree(attrData->Value, NULL);
166 attrData->Value = NULL;
167 }
168 }
169
170 /*
171 * Core MDS lookup routine. Used in two situations. It's called by main() to perform
172 * a lookup in the CDSA Directory Database based one one key/value pair; this
173 * call fetches one attribute from the associated record - the GUID ("ModuleID"
174 * in MDS lingo). Then the function calls itself to do a lookup in the Object DB,
175 * based on that GUID, in order to fetch the path of the module associated with
176 * that GUID. The first call (from main()) corresponds to an application's
177 * typical use of MDS. The recursive call, which does a lookup in the Object
178 * DB, corresponds to CSSM's typical use of MDS, which is to map a GUID to a
179 * bundle path.
180 *
181 * The ModuleID and Path of all modules satisfying the initial search criteria
182 * are displayed on stdout.
183 *
184 * Caller specifies one search attribute, by name, value,Êand value format.
185 * Whether this is the first or second (recursive) call is indicated by the
186 * cdsaLookup argument. That determines both the DB to search and the attribute
187 * to fetch (ModuleID or Path).
188 */
189 static void doLookup(
190 MDS_FUNCS *mdsFuncs,
191
192 /* Two DBs and a flag indicating which one to use */
193 MDS_DB_HANDLE objDlDb,
194 MDS_DB_HANDLE cdsaDlDb,
195 bool cdsaLookup, // true - use cdsaDlDb; false - objDlDb
196
197 /* Record type, a.k.a. Relation, e.g. MDS_CDSADIR_CSP_PRIMARY_RECORDTYPE */
198 CSSM_DB_RECORDTYPE recordType,
199
200 /* key, value, valForm, and valOp are the thing we search on */
201 /* Note CSSM_DB_ATTRIBUTE_NAME_FORMAT - the format of the attribute name -
202 * is always CSSM_DB_ATTRIBUTE_NAME_AS_STRING for MDS. */
203 const char *key, // e.g. "AlgType"
204 const void *valPtr,
205 unsigned valLen,
206 CSSM_DB_ATTRIBUTE_FORMAT valForm, // CSSM_DB_ATTRIBUTE_FORMAT_STRING, etc.
207 CSSM_DB_OPERATOR valOp, // normally CSSM_DB_EQUAL
208
209 /* for display only */
210 const char *srchStr)
211 {
212 CSSM_QUERY query;
213 CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
214 CSSM_HANDLE resultHand;
215 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
216 CSSM_SELECTION_PREDICATE predicate;
217 CSSM_DATA predData;
218 CSSM_DB_ATTRIBUTE_DATA outAttr;
219 CSSM_DB_ATTRIBUTE_INFO_PTR attrInfo;
220 CSSM_RETURN crtn;
221 MDS_DB_HANDLE dlDb;
222 const char *attrName;
223
224 if(cdsaLookup) {
225 /* first call, fetching guid from the CDSA Directory DB */
226 dlDb = cdsaDlDb;
227 attrName = "ModuleID";
228 }
229 else {
230 /* recursive call, fetching path from Object DB */
231 dlDb = objDlDb;
232 attrName = "Path";
233 }
234
235 /* We want one attributes back, name and format specified by caller */
236 recordAttrs.DataRecordType = recordType;
237 recordAttrs.SemanticInformation = 0;
238 recordAttrs.NumberOfAttributes = 1;
239 recordAttrs.AttributeData = &outAttr;
240
241 memset(&outAttr, 0, sizeof(CSSM_DB_ATTRIBUTE_DATA));
242 attrInfo = &outAttr.Info;
243 attrInfo->AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
244 attrInfo->Label.AttributeName = (char *)attrName;
245 attrInfo->AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_STRING;
246
247 /* one predicate - the caller's key and CSSM_DB_OPERATOR */
248 predicate.DbOperator = valOp;
249 predicate.Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
250 predicate.Attribute.Info.Label.AttributeName = (char *)key;
251 predicate.Attribute.Info.AttributeFormat = valForm;
252 predData.Data = (uint8 *)valPtr;
253 predData.Length = valLen;
254 predicate.Attribute.Value = &predData;
255 predicate.Attribute.NumberOfValues = 1;
256
257 query.RecordType = recordType;
258 query.Conjunctive = CSSM_DB_NONE;
259 query.NumSelectionPredicates = 1;
260 query.SelectionPredicate = &predicate;
261 query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
262 query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
263 query.QueryFlags = 0; // CSSM_QUERY_RETURN_DATA...FIXME - used?
264
265 crtn = mdsFuncs->DataGetFirst(dlDb,
266 &query,
267 &resultHand,
268 &recordAttrs,
269 NULL, // No data
270 &record);
271 switch(crtn) {
272 case CSSM_OK:
273 break; // proceed
274 case CSSMERR_DL_ENDOFDATA:
275 printf("%s: no record found\n", srchStr);
276 return;
277 default:
278 printError("DataGetFirst", crtn);
279 return;
280 }
281 /* dump this record, one attribute */
282 if(srchStr) {
283 /* not done on recursive call */
284 printf("%s found:\n", srchStr);
285 }
286 dumpRecord(&recordAttrs);
287 mdsFuncs->FreeUniqueRecord(dlDb, record);
288
289 if(srchStr != NULL) {
290 /*
291 * Now do a lookup in Object DB of this guid, looking for path.
292 * Apps normally don't do this; this is what CSSM does when given
293 * the GUID of a module.
294 */
295 if(outAttr.Value == NULL) {
296 printf("***Screwup: DataGetFirst worked, but no outAttr\n");
297 return;
298 }
299 doLookup(mdsFuncs,
300 objDlDb,
301 cdsaDlDb,
302 false, // use objDlDb
303 MDS_OBJECT_RECORDTYPE,
304 "ModuleID", // key
305 outAttr.Value->Data, // valPtr, ModuleID, as string
306 outAttr.Value->Length, // valLen
307 CSSM_DB_ATTRIBUTE_FORMAT_STRING,
308 CSSM_DB_EQUAL,
309 NULL); // srchStr
310 }
311 freeAttrs(&recordAttrs);
312
313 /* now the rest of them */
314 for(;;) {
315 crtn = mdsFuncs->DataGetNext(dlDb,
316 resultHand,
317 &recordAttrs,
318 NULL,
319 &record);
320 switch(crtn) {
321 case CSSM_OK:
322 dumpRecord(&recordAttrs);
323 mdsFuncs->FreeUniqueRecord(cdsaDlDb, record);
324 if(srchStr != NULL) {
325 if(outAttr.Value == NULL) {
326 printf("***Screwup: DataGetNext worked, but no outAttr\n");
327 return;
328 }
329 doLookup(mdsFuncs,
330 objDlDb,
331 cdsaDlDb,
332 false, // use objDlDb
333 MDS_OBJECT_RECORDTYPE,
334 "ModuleID", // key
335 outAttr.Value->Data, // valPtr, ModuleID, as string
336 outAttr.Value->Length, // valLen
337 CSSM_DB_ATTRIBUTE_FORMAT_STRING,
338 CSSM_DB_EQUAL,
339 NULL); // srchStr
340 }
341 freeAttrs(&recordAttrs);
342 break; // and go again
343 case CSSMERR_DL_ENDOFDATA:
344 /* normal termination */
345 break;
346 default:
347 printError("DataGetNext", crtn);
348 break;
349 }
350 if(crtn != CSSM_OK) {
351 break;
352 }
353 }
354 }
355
356 int main(int argc, char **argv)
357 {
358 MDS_FUNCS mdsFuncs;
359 MDS_HANDLE mdsHand;
360 CSSM_RETURN crtn;
361 int arg;
362 CSSM_DB_HANDLE dbHand = 0;
363 MDS_DB_HANDLE objDlDb;
364 MDS_DB_HANDLE cdsaDlDb;
365 bool keepConnected = false;
366 uint32 val;
367
368 for(arg=2; arg<argc; arg++) {
369 switch(argv[arg][0]) {
370 case 'k':
371 keepConnected = true;
372 break;
373 default:
374 usage(argv);
375 }
376 }
377 crtn = MDS_Initialize(NULL, // callerGuid
378 &memFuncs,
379 &mdsFuncs,
380 &mdsHand);
381 if(crtn) {
382 printError("MDS_Initialize", crtn);
383 exit(1);
384 }
385
386 do {
387 /*
388 * Open both MDS DBs - apps normally only have to open
389 * MDS_CDSA_DIRECTORY_NAME.
390 */
391 crtn = mdsFuncs.DbOpen(mdsHand,
392 MDS_OBJECT_DIRECTORY_NAME,
393 NULL, // DbLocation
394 CSSM_DB_ACCESS_READ,
395 NULL, // AccessCred - hopefully optional
396 NULL, // OpenParameters
397 &dbHand);
398 if(crtn) {
399 printError("DbOpen(MDS_OBJECT_DIRECTORY_NAME)", crtn);
400 exit(1);
401 }
402 objDlDb.DLHandle = mdsHand;
403 objDlDb.DBHandle = dbHand;
404
405 crtn = mdsFuncs.DbOpen(mdsHand,
406 MDS_CDSA_DIRECTORY_NAME,
407 NULL, // DbLocation
408 CSSM_DB_ACCESS_READ,
409 NULL, // AccessCred - hopefully optional
410 NULL, // OpenParameters
411 &dbHand);
412 if(crtn) {
413 printError("DbOpen(MDS_CDSA_DIRECTORY_NAME)", crtn);
414 exit(1);
415 }
416 cdsaDlDb.DLHandle = mdsHand;
417 cdsaDlDb.DBHandle = dbHand;
418
419 /*
420 * Do some typical lookups.
421 */
422
423 /* a CSP which can do SHA1 digest */
424 val = CSSM_ALGID_SHA1;
425 doLookup(&mdsFuncs,
426 objDlDb,
427 cdsaDlDb,
428 true,
429 MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE,
430 "AlgType",
431 &val,
432 sizeof(uint32),
433 CSSM_DB_ATTRIBUTE_FORMAT_UINT32,
434 CSSM_DB_EQUAL,
435 "CSP for SHA1 digest");
436
437 /* a TP which can do iSign verification */
438 doLookup(&mdsFuncs,
439 objDlDb,
440 cdsaDlDb,
441 true,
442 MDS_CDSADIR_TP_OIDS_RECORDTYPE,
443 "OID",
444 CSSMOID_APPLE_ISIGN.Data,
445 CSSMOID_APPLE_ISIGN.Length,
446 CSSM_DB_ATTRIBUTE_FORMAT_BLOB,
447 CSSM_DB_EQUAL,
448 "TP for CSSMOID_APPLE_ISIGN policy");
449
450 /* an X509-savvy CL */
451 /* Very weird data form - two fields in one 32-bit word */
452 val = (CSSM_CERT_X_509v3 << 16) | CSSM_CERT_ENCODING_DER;
453 doLookup(&mdsFuncs,
454 objDlDb,
455 cdsaDlDb,
456 true,
457 MDS_CDSADIR_CL_PRIMARY_RECORDTYPE,
458 "CertTypeFormat",
459 &val,
460 sizeof(uint32),
461 CSSM_DB_ATTRIBUTE_FORMAT_UINT32,
462 CSSM_DB_EQUAL,
463 "X509 CL");
464
465 /* A DL which can do CSSM_DB_AND */
466 val = CSSM_DB_AND;
467 doLookup(&mdsFuncs,
468 objDlDb,
469 cdsaDlDb,
470 true,
471 MDS_CDSADIR_DL_PRIMARY_RECORDTYPE,
472 "ConjunctiveOps",
473 &val,
474 sizeof(uint32),
475 CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32,
476 /* This is a multi-uint32, meaning we want to search for a
477 * ConjunctiveOps which contains the specified value */
478 CSSM_DB_CONTAINS,
479 "DL with ConjunctiveOp CSSM_DB_AND");
480
481 /* a CSP which can do CSSM_ALGID_IDEA, should fail */
482 val = CSSM_ALGID_IDEA;
483 doLookup(&mdsFuncs,
484 objDlDb,
485 cdsaDlDb,
486 true,
487 MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE,
488 "AlgType",
489 &val,
490 sizeof(uint32),
491 CSSM_DB_ATTRIBUTE_FORMAT_UINT32,
492 CSSM_DB_EQUAL,
493 "CSP for CSSM_ALGID_BLOWFISH, expect failure");
494
495 /* a TP which can obtain a .mac signing certificate */
496 doLookup(&mdsFuncs,
497 objDlDb,
498 cdsaDlDb,
499 true,
500 MDS_CDSADIR_TP_OIDS_RECORDTYPE,
501 "OID",
502 CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN.Data,
503 CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN.Length,
504 CSSM_DB_ATTRIBUTE_FORMAT_BLOB,
505 CSSM_DB_EQUAL,
506 "TP for .mac signing certificate policy");
507
508 crtn = mdsFuncs.DbClose(objDlDb);
509 if(crtn) {
510 printError("DbClose(objDlDb)", crtn);
511 }
512 crtn = mdsFuncs.DbClose(cdsaDlDb);
513 if(crtn) {
514 printError("DbClose(cdsaDlDb)", crtn);
515 }
516 if(keepConnected) {
517 printf("\n");
518 fpurge(stdin);
519 printf("Enter CR to go again: ");
520 getchar();
521 }
522 } while(keepConnected);
523 crtn = MDS_Terminate(mdsHand);
524 if(crtn) {
525 printError("MDS_Terminate", crtn);
526 }
527 return 0;
528 }