]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/extendAttrTool/extendAttrTool.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / SecurityTests / clxutils / extendAttrTool / extendAttrTool.cpp
1 /*
2 * extendAttrTool.cpp
3 */
4
5 #include <stdlib.h>
6 #include <strings.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include "singleItemPicker.h"
10 #include <Security/SecKeychainItemExtendedAttributes.h>
11 #include <Security/SecKeychainItemPriv.h>
12 #include <Security/cssmapple.h>
13
14 #define DEFAULT_ATTR_NAME "someAttr"
15
16 static void usage(char **argv)
17 {
18 printf("usage: %s op [options]\n", argv[0]);
19 printf("Op: set, get, delete, getall, dump\n");
20 printf("Options:\n");
21 printf(" -t itemType -- type = priv|pub|cert; default is public\n");
22 printf(" -k keychain -- default is default KC list\n");
23 printf(" -p -- use item picker; default is first matching item in keychain\n");
24 printf(" -a attrName -- default is %s\n", DEFAULT_ATTR_NAME);
25 printf(" -A attrValue\n");
26 printf(" -n -- no values retrieved on op getall\n");
27 printf(" -l -- loop/pause for malloc debug\n");
28 exit(1);
29 }
30
31 #define CFRELEASE(cf) if(cf) { CFRelease(cf); }
32
33 /*
34 * Print contents of a CFData assuming it's printable
35 */
36 static void printCfData(CFDataRef cfd)
37 {
38 CFIndex len = CFDataGetLength(cfd);
39 const UInt8 *cp = CFDataGetBytePtr(cfd);
40 for(CFIndex dex=0; dex<len; dex++) {
41 char c = cp[dex];
42 if(isprint(c)) {
43 putchar(c);
44 }
45 else {
46 printf(".%02X.", c);
47 }
48 }
49 }
50
51 /* print the contents of a CFString */
52 void printCfStr(
53 CFStringRef cfstr)
54 {
55 CFDataRef strData = CFStringCreateExternalRepresentation(NULL, cfstr,
56 kCFStringEncodingUTF8, true);
57 if(strData == NULL) {
58 printf("<<string decode error>>");
59 return;
60 }
61 const char *cp = (const char *)CFDataGetBytePtr(strData);
62 CFIndex len = CFDataGetLength(strData);
63 for(CFIndex dex=0; dex<len; dex++) {
64 putchar(*cp++);
65 }
66 CFRelease(strData);
67 }
68
69 /*
70 * Print contents of a SecKeychainAttribute assuming it's printable
71 */
72 static void printAttribute(SecKeychainAttribute *kca)
73 {
74 unsigned len = kca->length;
75 const char *cp = (const char *)kca->data;
76 for(unsigned dex=0; dex<len; dex++) {
77 char c = cp[dex];
78 if(isprint(c)) {
79 putchar(c);
80 }
81 else {
82 printf(".%02X.", c);
83 }
84 }
85 }
86
87 /*
88 * Print parallel arrays of CFStringRefs (attribute names) and optional CFDataRefs
89 * (attribute values).
90 */
91 static int printAttrs(
92 CFArrayRef nameArray,
93 CFArrayRef valuesArray) /* optional */
94 {
95 CFIndex numNames = CFArrayGetCount(nameArray);
96 if(valuesArray) {
97 if(numNames != CFArrayGetCount(valuesArray)) {
98 printf("***Mismatch on sizes of nameArray (%ld) and valuesArray (%ld)\n",
99 numNames, CFArrayGetCount(valuesArray));
100 return -1;
101 }
102 }
103
104 for(CFIndex dex=0; dex<numNames; dex++) {
105 printf("Attribute %ld:\n", (long)dex);
106 CFStringRef attrName = (CFStringRef)CFArrayGetValueAtIndex(nameArray, dex);
107 printf(" name : ");
108 printCfStr(attrName);
109 printf("\n");
110 if(valuesArray) {
111 CFDataRef attrValue = (CFDataRef)CFArrayGetValueAtIndex(valuesArray, dex);
112 printf(" value : ");
113 printCfData(attrValue);
114 printf("\n");
115 }
116 }
117 return 0;
118 }
119
120 /* entry in a table to map a uint32 to a string */
121 typedef struct {
122 uint32 value;
123 const char *name;
124 } NameValuePair;
125
126 /* declare one entry in a table of nameValuePairs */
127 #define NVP(attr) {attr, #attr}
128
129 /* the NULL entry which terminates all nameValuePair tables */
130 #define NVP_END {0, NULL}
131
132 /* CSSM_DB_RECORDTYPE names */
133 const NameValuePair recordTypeNames[] =
134 {
135 NVP(CSSM_DL_DB_SCHEMA_INFO),
136 NVP(CSSM_DL_DB_SCHEMA_INDEXES),
137 NVP(CSSM_DL_DB_SCHEMA_ATTRIBUTES),
138 NVP(CSSM_DL_DB_SCHEMA_PARSING_MODULE),
139 NVP(CSSM_DL_DB_RECORD_ANY),
140 NVP(CSSM_DL_DB_RECORD_CERT),
141 NVP(CSSM_DL_DB_RECORD_CRL),
142 NVP(CSSM_DL_DB_RECORD_POLICY),
143 NVP(CSSM_DL_DB_RECORD_GENERIC),
144 NVP(CSSM_DL_DB_RECORD_PUBLIC_KEY),
145 NVP(CSSM_DL_DB_RECORD_PRIVATE_KEY),
146 NVP(CSSM_DL_DB_RECORD_SYMMETRIC_KEY),
147 NVP(CSSM_DL_DB_RECORD_ALL_KEYS),
148 /* Apple-specific */
149 NVP(CSSM_DL_DB_RECORD_GENERIC_PASSWORD),
150 NVP(CSSM_DL_DB_RECORD_INTERNET_PASSWORD),
151 NVP(CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD),
152 NVP(CSSM_DL_DB_RECORD_X509_CERTIFICATE),
153 NVP(CSSM_DL_DB_RECORD_X509_CRL),
154 NVP(CSSM_DL_DB_RECORD_USER_TRUST),
155 /* private to Sec layer */
156 NVP(CSSM_DL_DB_RECORD_UNLOCK_REFERRAL),
157 NVP_END
158 };
159
160 static void printRecordType(
161 const void *recordTypeAttr)
162 {
163 UInt32 recordType = *((UInt32 *)recordTypeAttr);
164 for(const NameValuePair *nvp=recordTypeNames; nvp->name; nvp++) {
165 if(recordType == nvp->value) {
166 printf("%s", nvp->name);
167 return;
168 }
169 }
170 printf("Unknown recordType (0x%x)\n", (unsigned)recordType);
171 return;
172 }
173
174
175 static int dumpExtendAttrRecords(
176 SecKeychainRef kcRef)
177 {
178 OSStatus ortn;
179 SecKeychainSearchRef srchRef = NULL;
180
181 ortn = SecKeychainSearchCreateFromAttributes(kcRef,
182 CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE,
183 NULL, // no attrs - give me everything
184 &srchRef);
185 if(ortn) {
186 cssmPerror("SecKeychainSearchCreateFromAttributes", ortn);
187 return -1;
188 }
189
190 SecKeychainItemRef itemRef = NULL;
191 unsigned numItems = 0;
192 for(;;) {
193 ortn = SecKeychainSearchCopyNext(srchRef, &itemRef);
194 if(ortn) {
195 if(ortn == errSecItemNotFound) {
196 /* normal end of search */
197 break;
198 }
199 else {
200 cssmPerror("SecKeychainSearchCopyNext", ortn);
201 break;
202 }
203 }
204
205 /* get some info about the EA record - RecordType (that it's bound to) and
206 * AttributeName */
207 UInt32 tags[2] = { kExtendedAttrRecordTypeAttr, kExtendedAttrAttributeNameAttr };
208 UInt32 formats[2] = {0};
209 SecKeychainAttributeList *attrList = NULL;
210 SecKeychainAttributeInfo attrInfo = {2, tags, formats};
211 ortn = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo,
212 NULL, &attrList, NULL, NULL);
213 if(ortn) {
214 cssmPerror("SecKeychainItemCopyAttributesAndData", ortn);
215 return -1;
216 }
217 printf("Extended Attribute %u:\n", numItems);
218 for(unsigned dex=0; dex<2; dex++) {
219 SecKeychainAttribute *attr = &attrList->attr[dex];
220 switch(attr->tag) {
221 case kExtendedAttrRecordTypeAttr:
222 printf(" Record type : ");
223 printRecordType(attr->data);
224 printf("\n");
225 break;
226
227 case kExtendedAttrAttributeNameAttr:
228 printf(" Attribute Name : ");
229 printAttribute(attr);
230 printf("\n");
231 break;
232 break;
233 default:
234 /* should never happen, right? */
235 printf("***Unexpected attr tag when parsing an ExtendedAttr record\n");
236 return -1;
237 }
238 }
239 numItems++;
240 SecKeychainItemFreeAttributesAndData(attrList, NULL);
241 CFRelease(itemRef);
242 }
243 if(numItems == 0) {
244 printf("...no Extended Attribute records found.\n");
245 }
246 CFRelease(srchRef);
247 return 0;
248 }
249
250 typedef enum {
251 OP_None,
252 OP_Set,
253 OP_Get,
254 OP_Delete,
255 OP_GetAll,
256 OP_Dump // search for EXTENDED_ATTRIBUTE records, dump contents
257 } Op;
258
259 int main(int argc, char **argv)
260 {
261 const char *attrName = DEFAULT_ATTR_NAME;
262 const char *attrValue = NULL;
263 const char *kcName = NULL;
264 KP_ItemType itemType = KPI_PublicKey;
265 bool takeFirst = true;
266 bool noValues = false;
267 bool loopPause = false;
268 Op op = OP_None;
269
270 if(argc < 2) {
271 usage(argv);
272 }
273 if(!strcmp(argv[1], "set")) {
274 op = OP_Set;
275 }
276 else if(!strcmp(argv[1], "get")) {
277 op = OP_Get;
278 }
279 else if(!strcmp(argv[1], "delete")) {
280 op = OP_Delete;
281 }
282 else if(!strcmp(argv[1], "getall")) {
283 op = OP_GetAll;
284 }
285 else if(!strcmp(argv[1], "dump")) {
286 op = OP_Dump;
287 }
288 else {
289 usage(argv);
290
291 }
292
293 extern int optind;
294 optind = 2;
295 extern char *optarg;
296 int arg;
297 while ((arg = getopt(argc, argv, "t:k:pa:A:nlh")) != -1) {
298 switch (arg) {
299 case 't':
300 if(!strcmp(optarg, "priv")) {
301 itemType = KPI_PrivateKey;
302 }
303 else if(!strcmp(optarg, "pub")) {
304 itemType = KPI_PublicKey;
305 }
306 else if(!strcmp(optarg, "cert")) {
307 itemType = KPI_Cert;
308 }
309 else {
310 printf("***Bad itemType specification.\n");
311 usage(argv);
312 }
313 break;
314 case 'k':
315 kcName = optarg;
316 break;
317 case 'p':
318 takeFirst = false;
319 break;
320 case 'a':
321 attrName = optarg;
322 break;
323 case 'A':
324 attrValue = optarg;
325 break;
326 case 'n':
327 noValues = true;
328 break;
329 case 'l':
330 loopPause = true;
331 break;
332 case 'h':
333 usage(argv);
334 }
335 }
336 if(optind != argc) {
337 usage(argv);
338 }
339
340 if((op == OP_Set) && (attrValue == NULL)) {
341 printf("***I Need an attribute values (-A) to set\n");
342 exit(1);
343 }
344
345 OSStatus ortn;
346 SecKeychainItemRef theItem = NULL;
347 SecKeychainRef kcRef = NULL;
348
349 if(kcName) {
350 ortn = SecKeychainOpen(kcName, &kcRef);
351 if(ortn) {
352 cssmPerror("SecKeychainOpen", ortn);
353 exit(1);
354 }
355 }
356
357 if(op == OP_Dump) {
358 /* we're ready to roll */
359 return dumpExtendAttrRecords(kcRef);
360 }
361 ortn = singleItemPicker(kcRef, itemType, takeFirst, &theItem);
362 if(ortn) {
363 printf("***Error picking item. Aborting.\n");
364 exit(1);
365 }
366
367 CFStringRef attrNameStr = NULL;
368 CFDataRef attrValueData = NULL;
369 if(op != OP_GetAll) {
370 attrNameStr = CFStringCreateWithCString(NULL, attrName, kCFStringEncodingASCII);
371 }
372
373 do {
374 switch(op) {
375 case OP_Set:
376 attrValueData = CFDataCreate(NULL, (const UInt8 *)attrValue, strlen(attrValue));
377 ortn = SecKeychainItemSetExtendedAttribute(theItem, attrNameStr, attrValueData);
378 if(ortn) {
379 cssmPerror("SecKeychainItemSetExtendedAttribute", ortn);
380 }
381 else {
382 printf("attribute '%s' set to '%s'.\n", attrName, attrValue);
383 }
384 break;
385 case OP_Get:
386 ortn = SecKeychainItemCopyExtendedAttribute(theItem,
387 attrNameStr, &attrValueData);
388 if(ortn) {
389 cssmPerror("SecKeychainItemCopyExtendedAttribute", ortn);
390 }
391 else {
392 printf("Attribute '%s' found; value = '", attrName);
393 printCfData(attrValueData);
394 printf("'\n");
395 }
396 break;
397 case OP_Delete:
398 ortn = SecKeychainItemSetExtendedAttribute(theItem, attrNameStr, NULL);
399 if(ortn) {
400 cssmPerror("SecKeychainItemSetExtendedAttribute", ortn);
401 }
402 else {
403 printf("attribute '%s' deleted.\n", attrName);
404 }
405 break;
406 case OP_GetAll:
407 {
408 CFArrayRef nameArray = NULL;
409 CFArrayRef valuesArray = NULL;
410 CFArrayRef *valuesArrayPtr = noValues ? NULL : &valuesArray;
411
412 ortn = SecKeychainItemCopyAllExtendedAttributes(theItem,
413 &nameArray, valuesArrayPtr);
414 if(ortn) {
415 cssmPerror("SecKeychainItemCopyAllExtendedAttributes", ortn);
416 break;
417 }
418 if(nameArray == NULL) {
419 printf("***NULL nameArray after successful "
420 "SecKeychainItemCopyAllExtendedAttributes\n");
421 ortn = -1;
422 break;
423 }
424 if(!noValues) {
425 if(valuesArray == NULL) {
426 printf("***NULL valuesArray after successful "
427 "SecKeychainItemCopyAllExtendedAttributes\n");
428 ortn = -1;
429 break;
430 }
431 }
432 ortn = printAttrs(nameArray, valuesArray);
433 CFRELEASE(nameArray);
434 CFRELEASE(valuesArray);
435 break;
436 }
437 case OP_Dump:
438 /* already handled this; satisfy compiler */
439 break;
440 case OP_None:
441 printf("***BRRRZAP!\n");
442 exit(1);
443 }
444 if(ortn) {
445 break;
446 }
447 CFRELEASE(attrValueData);
448 attrValueData = NULL;
449
450 if(loopPause) {
451 fpurge(stdin);
452 printf("End of loop; a to abort, anything else to continue: ");
453 if(getchar() == 'a') {
454 break;
455 }
456 }
457 } while(loopPause);
458 return ortn ? -1 : 0;
459 }