]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/Tool/keychain_find.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / sec / Security / Tool / keychain_find.c
1 //
2 //
3 //
4 //
5
6
7
8 #include <CoreFoundation/CoreFoundation.h>
9
10 #include <Security/SecItem.h>
11 #include <Security/SecItemPriv.h>
12
13 #include <SecurityTool/tool_errors.h>
14 #include <SecurityTool/readline.h>
15
16 #include <utilities/SecCFWrappers.h>
17
18 #include "SecurityCommands.h"
19
20 #include "keychain_util.h"
21 #include <Security/SecAccessControl.h>
22 #include <Security/SecAccessControlPriv.h>
23
24 //
25 // Craptastic hacks.
26
27 typedef uint32_t SecProtocolType;
28 typedef uint32_t SecAuthenticationType;
29
30
31 static CFMutableDictionaryRef
32 keychain_create_query_from_string(const char *query) {
33 CFMutableDictionaryRef q;
34
35 q = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
36 if (!keychain_query_parse_cstring(q, query)) {
37 CFReleaseNull(q);
38 }
39 return q;
40 }
41
42 static void add_key(const void *key, const void *value, void *context) {
43 CFArrayAppendValue(context, key);
44 }
45
46 static void display_item(const void *v_item, void *context) {
47 CFDictionaryRef item = (CFDictionaryRef)v_item;
48 CFIndex dict_count, key_ix, key_count;
49 CFMutableArrayRef keys = NULL;
50 CFIndex maxWidth = 10; /* Maybe precompute this or grab from context? */
51
52 dict_count = CFDictionaryGetCount(item);
53 keys = CFArrayCreateMutable(kCFAllocatorDefault, dict_count,
54 &kCFTypeArrayCallBacks);
55 CFDictionaryApplyFunction(item, add_key, keys);
56 key_count = CFArrayGetCount(keys);
57 CFArraySortValues(keys, CFRangeMake(0, key_count),
58 (CFComparatorFunction)CFStringCompare, 0);
59
60 for (key_ix = 0; key_ix < key_count; ++key_ix) {
61 CFStringRef key = (CFStringRef)CFArrayGetValueAtIndex(keys, key_ix);
62 CFTypeRef value = CFDictionaryGetValue(item, key);
63 CFMutableStringRef line = CFStringCreateMutable(NULL, 0);
64
65 CFStringAppend(line, key);
66 CFIndex jx;
67 for (jx = CFStringGetLength(key);
68 jx < maxWidth; ++jx) {
69 CFStringAppend(line, CFSTR(" "));
70 }
71 CFStringAppend(line, CFSTR(" : "));
72 if (CFStringGetTypeID() == CFGetTypeID(value)) {
73 CFStringAppend(line, (CFStringRef)value);
74 } else if (CFNumberGetTypeID() == CFGetTypeID(value)) {
75 CFNumberRef v_n = (CFNumberRef)value;
76 CFStringAppendFormat(line, NULL, CFSTR("%@"), v_n);
77 } else if (CFDateGetTypeID() == CFGetTypeID(value)) {
78 CFDateRef v_d = (CFDateRef)value;
79 CFStringAppendFormat(line, NULL, CFSTR("%@"), v_d);
80 } else if (CFDataGetTypeID() == CFGetTypeID(value)) {
81 CFDataRef v_d = (CFDataRef)value;
82 CFStringRef v_s = CFStringCreateFromExternalRepresentation(
83 kCFAllocatorDefault, v_d, kCFStringEncodingUTF8);
84 if (v_s) {
85 CFStringAppend(line, CFSTR("/"));
86 CFStringAppend(line, v_s);
87 CFStringAppend(line, CFSTR("/ "));
88 CFRelease(v_s);
89 }
90 const uint8_t *bytes = CFDataGetBytePtr(v_d);
91 CFIndex len = CFDataGetLength(v_d);
92 for (jx = 0; jx < len; ++jx) {
93 CFStringAppendFormat(line, NULL, CFSTR("%.02X"), bytes[jx]);
94 }
95 } else if (SecAccessControlGetTypeID() == CFGetTypeID(value)) {
96 display_sac_line((SecAccessControlRef)value, line);
97 } else {
98 CFStringAppendFormat(line, NULL, CFSTR("%@"), value);
99 }
100
101 CFStringWriteToFileWithNewline(line, stdout);
102
103 CFRelease(line);
104 }
105 CFRelease(keys);
106
107 CFStringWriteToFileWithNewline(CFSTR("===="), stdout);
108
109 //CFShow(item);
110 }
111
112
113 static void display_results(CFTypeRef results) {
114 if (CFGetTypeID(results) == CFArrayGetTypeID()) {
115 CFArrayRef r_a = (CFArrayRef)results;
116 CFArrayApplyFunction(r_a, CFRangeMake(0, CFArrayGetCount(r_a)),
117 display_item, NULL);
118 } else if (CFGetTypeID(results) == CFArrayGetTypeID()) {
119 display_item(results, NULL);
120 } else {
121 fprintf(stderr, "SecItemCopyMatching returned unexpected results:");
122 CFShow(results);
123 }
124 }
125
126 static OSStatus do_find_or_delete(CFDictionaryRef query, bool do_delete) {
127 OSStatus result;
128 if (do_delete) {
129 result = SecItemDelete(query);
130 if (result) {
131 sec_perror("SecItemDelete", result);
132 }
133 } else {
134 CFTypeRef results = NULL;
135 result = SecItemCopyMatching(query, &results);
136 if (result) {
137 sec_perror("SecItemCopyMatching", result);
138 } else {
139 display_results(results);
140 }
141 CFReleaseSafe(results);
142 }
143 return result;
144 }
145
146 static int
147 do_keychain_find_or_delete_internet_password(Boolean do_delete,
148 const char *serverName, const char *securityDomain,
149 const char *accountName, const char *path, UInt16 port,
150 SecProtocolType protocol, SecAuthenticationType authenticationType,
151 Boolean get_password)
152 {
153 OSStatus result;
154 CFDictionaryRef query = NULL;
155 const void *keys[11], *values[11];
156 CFIndex ix = 0;
157
158 keys[ix] = kSecClass;
159 values[ix++] = kSecClassInternetPassword;
160 if (serverName) {
161 keys[ix] = kSecAttrServer;
162 values[ix++] = CFStringCreateWithCStringNoCopy(NULL, serverName,
163 kCFStringEncodingUTF8, kCFAllocatorNull);
164 }
165 if (securityDomain) {
166 keys[ix] = kSecAttrSecurityDomain;
167 values[ix++] = CFStringCreateWithCStringNoCopy(NULL, securityDomain,
168 kCFStringEncodingUTF8, kCFAllocatorNull);
169 }
170 if (accountName) {
171 keys[ix] = kSecAttrAccount;
172 values[ix++] = CFStringCreateWithCStringNoCopy(NULL, accountName,
173 kCFStringEncodingUTF8, kCFAllocatorNull);
174 }
175 if (path) {
176 keys[ix] = kSecAttrPath;
177 values[ix++] = CFStringCreateWithCStringNoCopy(NULL, path,
178 kCFStringEncodingUTF8, kCFAllocatorNull);
179 }
180 if (port != 0) {
181 keys[ix] = kSecAttrPort;
182 values[ix++] = CFNumberCreate(NULL, kCFNumberSInt16Type, &port);
183 }
184 if (protocol != 0) {
185 /* Protocol is a 4 char code, perhaps we should use a string rep
186 instead. */
187 keys[ix] = kSecAttrProtocol;
188 values[ix++] = CFNumberCreate(NULL, kCFNumberSInt32Type, &protocol);
189 }
190 if (authenticationType != 0) {
191 keys[ix] = kSecAttrAuthenticationType;
192 values[ix++] = CFNumberCreate(NULL, kCFNumberSInt32Type,
193 &authenticationType);
194 }
195 if (get_password) {
196 /* Only ask for the data if so required. */
197 keys[ix] = kSecReturnData;
198 values[ix++] = kCFBooleanTrue;
199 }
200 keys[ix] = kSecReturnAttributes;
201 values[ix++] = kCFBooleanTrue;
202 if (!do_delete) {
203 /* If we aren't deleting ask for all items. */
204 keys[ix] = kSecMatchLimit;
205 values[ix++] = kSecMatchLimitAll;
206 }
207
208 query = CFDictionaryCreate(NULL, keys, values, ix,
209 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
210 result = do_find_or_delete(query, do_delete);
211 CFReleaseSafe(query);
212
213 return result;
214 }
215
216 static int
217 parse_fourcharcode(const char *name, uint32_t *code)
218 {
219 /* @@@ Check for errors. */
220 char *p = (char *)code;
221 strncpy(p, name, 4);
222 return 0;
223 }
224
225 static int
226 keychain_find_or_delete_internet_password(Boolean do_delete, int argc, char * const *argv)
227 {
228 char *serverName = NULL, *securityDomain = NULL, *accountName = NULL, *path = NULL;
229 UInt16 port = 0;
230 SecProtocolType protocol = 0;
231 SecAuthenticationType authenticationType = 0;
232 int ch, result = 0;
233 Boolean get_password = FALSE;
234
235 while ((ch = getopt(argc, argv, "a:d:hgp:P:r:s:t:")) != -1)
236 {
237 switch (ch)
238 {
239 case 'a':
240 accountName = optarg;
241 break;
242 case 'd':
243 securityDomain = optarg;
244 break;
245 case 'g':
246 if (do_delete)
247 return 2;
248 get_password = TRUE;
249 break;
250 case 'p':
251 path = optarg;
252 break;
253 case 'P':
254 port = atoi(optarg);
255 break;
256 case 'r':
257 result = parse_fourcharcode(optarg, &protocol);
258 if (result)
259 goto loser;
260 break;
261 case 's':
262 serverName = optarg;
263 break;
264 case 't':
265 result = parse_fourcharcode(optarg, &authenticationType);
266 if (result)
267 goto loser;
268 break;
269 case '?':
270 default:
271 return 2; /* @@@ Return 2 triggers usage message. */
272 }
273 }
274
275 result = do_keychain_find_or_delete_internet_password(do_delete, serverName, securityDomain,
276 accountName, path, port, protocol,authenticationType, get_password);
277
278
279 loser:
280
281 return result;
282 }
283
284 int
285 keychain_find_internet_password(int argc, char * const *argv) {
286 return keychain_find_or_delete_internet_password(0, argc, argv);
287 }
288
289 int
290 keychain_delete_internet_password(int argc, char * const *argv) {
291 return keychain_find_or_delete_internet_password(1, argc, argv);
292 }
293
294 static int
295 do_keychain_find_or_delete_generic_password(Boolean do_delete,
296 const char *serviceName, const char *accountName,
297 Boolean get_password)
298 {
299 OSStatus result;
300 CFDictionaryRef query = NULL;
301 const void *keys[6], *values[6];
302 CFIndex ix = 0;
303
304 keys[ix] = kSecClass;
305 values[ix++] = kSecClassGenericPassword;
306 if (serviceName) {
307 keys[ix] = kSecAttrService;
308 values[ix++] = CFStringCreateWithCStringNoCopy(NULL, serviceName,
309 kCFStringEncodingUTF8, kCFAllocatorNull);
310 }
311 if (accountName) {
312 keys[ix] = kSecAttrAccount;
313 values[ix++] = CFStringCreateWithCStringNoCopy(NULL, accountName,
314 kCFStringEncodingUTF8, kCFAllocatorNull);
315 }
316 if (get_password) {
317 /* Only ask for the data if so required. */
318 keys[ix] = kSecReturnData;
319 values[ix++] = kCFBooleanTrue;
320 }
321 keys[ix] = kSecReturnAttributes;
322 values[ix++] = kCFBooleanTrue;
323 if (!do_delete) {
324 /* If we aren't deleting ask for all items. */
325 keys[ix] = kSecMatchLimit;
326 values[ix++] = kSecMatchLimitAll;
327 }
328
329 query = CFDictionaryCreate(NULL, keys, values, ix,
330 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
331
332 result = do_find_or_delete(query, do_delete);
333
334 CFReleaseSafe(query);
335
336 return result;
337 }
338
339 int keychain_item(int argc, char * const *argv) {
340 int ch, result = 0;
341 CFMutableDictionaryRef query, update = NULL;
342 bool get_password = false;
343 bool do_delete = false;
344 bool do_add = false;
345 bool verbose = false;
346 int limit = 0;
347
348 query = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
349 while ((ch = getopt(argc, argv, "ad:Df:gq:u:vl:")) != -1)
350 {
351 switch (ch)
352 {
353 case 'a':
354 do_add = true;
355 break;
356 case 'D':
357 do_delete = true;
358 break;
359 case 'd':
360 {
361 CFStringRef dataString = CFStringCreateWithCString(0, optarg, kCFStringEncodingUTF8);
362 if (dataString) {
363 CFDataRef data = CFStringCreateExternalRepresentation(kCFAllocatorDefault, dataString, kCFStringEncodingUTF8, 0);
364 if (data) {
365 CFDictionarySetValue(update ? update : query, kSecValueData, data);
366 CFRelease(data);
367 }
368 CFRelease(dataString);
369 } else {
370 result = 1;
371 goto out;
372 }
373 break;
374 }
375 case 'f':
376 {
377 CFDataRef data = copyFileContents(optarg);
378 CFDictionarySetValue(update ? update : query, kSecValueData, data);
379 CFRelease(data);
380 break;
381 }
382 case 'g':
383 get_password = true;
384 break;
385 case 'q':
386 if (!keychain_query_parse_cstring(query, optarg)) {
387 result = 1;
388 goto out;
389 }
390 break;
391 case 'u':
392 {
393 bool success = true;
394 if (!update)
395 update = keychain_create_query_from_string(optarg);
396 else
397 success = keychain_query_parse_cstring(update, optarg);
398 if (update == NULL || !success) {
399 result = 1;
400 goto out;
401 }
402 }
403 break;
404 case 'v':
405 verbose = true;
406 break;
407 case 'l':
408 limit = atoi(optarg);
409 break;
410 case '?':
411 default:
412 /* Return 2 triggers usage message. */
413 result = 2;
414 goto out;
415 }
416 }
417
418 if (((do_add || do_delete) && (get_password || update)) || !query) {
419 result = 2;
420 goto out;
421 }
422
423 argc -= optind;
424 argv += optind;
425
426 int ix;
427 for (ix = 0; ix < argc; ++ix) {
428 if (!keychain_query_parse_cstring(query, argv[ix])) {
429 result = 1;
430 goto out;
431 }
432 }
433
434 if (!update && !do_add && !do_delete) {
435 CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue);
436 if(limit) {
437 CFNumberRef cfLimit = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &limit);
438 CFDictionarySetValue(query, kSecMatchLimit, cfLimit);
439 CFReleaseSafe(cfLimit);
440 } else {
441 CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
442 }
443 if (get_password)
444 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
445 }
446
447 if (verbose)
448 CFShow(query);
449
450 OSStatus error;
451 if (do_add) {
452 error = SecItemAdd(query, NULL);
453 if (error) {
454 sec_perror("SecItemAdd", error);
455 result = 1;
456 }
457 } else if (update) {
458 error = SecItemUpdate(query, update);
459 if (error) {
460 sec_perror("SecItemUpdate", error);
461 result = 1;
462 }
463 } else if (do_delete) {
464 error = SecItemDelete(query);
465 if (error) {
466 sec_perror("SecItemDelete", error);
467 result = 1;
468 }
469 } else {
470 do_find_or_delete(query, do_delete);
471 }
472
473 out:
474 CFReleaseSafe(query);
475 CFReleaseSafe(update);
476 return result;
477 }
478
479 static int
480 keychain_find_or_delete_generic_password(Boolean do_delete,
481 int argc, char * const *argv)
482 {
483 char *serviceName = NULL, *accountName = NULL;
484 int ch, result = 0;
485 Boolean get_password = FALSE;
486
487 while ((ch = getopt(argc, argv, "a:s:g")) != -1)
488 {
489 switch (ch)
490 {
491 case 'a':
492 accountName = optarg;
493 break;
494 case 'g':
495 if (do_delete)
496 return 2;
497 get_password = TRUE;
498 break;
499 case 's':
500 serviceName = optarg;
501 break;
502 case '?':
503 default:
504 return 2; /* @@@ Return 2 triggers usage message. */
505 }
506 }
507
508 result = do_keychain_find_or_delete_generic_password(do_delete,
509 serviceName, accountName, get_password);
510
511 return result;
512 }
513
514 int
515 keychain_find_generic_password(int argc, char * const *argv) {
516 return keychain_find_or_delete_generic_password(0, argc, argv);
517 }
518
519 int
520 keychain_delete_generic_password(int argc, char * const *argv) {
521 return keychain_find_or_delete_generic_password(1, argc, argv);
522 }
523
524 #if TARGET_OS_EMBEDDED
525
526 int
527 keychain_roll_keys(int argc, char * const *argv) {
528 int ch, result = 0;
529 bool force = false;
530
531 while ((ch = getopt(argc, argv, "f")) != -1)
532 {
533 switch (ch)
534 {
535 case 'f':
536 force = true;
537 break;
538 default:
539 return 2;
540 }
541 }
542 // argc -= optind;
543 // argv += optind;
544
545 (void) argc; // These are set so folks could use them
546 (void) argv; // silence the analyzer since they're not used
547
548 CFErrorRef error = NULL;
549 bool ok = _SecKeychainRollKeys(force, &error);
550
551 fprintf(stderr, "Keychain keys up to date: %s\n", ok ? "yes" : "no");
552 if (!ok && error) {
553 result = (int)CFErrorGetCode(error);
554 CFShow(error);
555 }
556
557 return result;
558 }
559
560 #endif