]> git.saurik.com Git - apple/security.git/blob - SecurityTool/keychain_list.c
Security-57740.51.3.tar.gz
[apple/security.git] / SecurityTool / keychain_list.c
1 /*
2 * Copyright (c) 2003-2010,2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * keychain_list.c
24 */
25
26 #include "keychain_list.h"
27
28 #include "keychain_utilities.h"
29 #include "security_tool.h"
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <sys/param.h>
34 #include <unistd.h>
35 #include <CoreFoundation/CFArray.h>
36 #include <Security/SecKeychain.h>
37
38 // SecKeychainCopyLogin
39 #include <Security/SecKeychainPriv.h>
40 #include <Security/SecItem.h>
41
42 typedef enum
43 {
44 kList,
45 kAdd,
46 kRemove,
47 kSet,
48 } list_operation;
49
50 static void
51 display_name(const void *value, void *context)
52 {
53 SecKeychainRef keychain = (SecKeychainRef)value;
54 UInt32 pathLength = MAXPATHLEN;
55 char pathName[MAXPATHLEN + 1];
56 OSStatus result = SecKeychainGetPath(keychain, &pathLength, pathName);
57 if (result)
58 sec_error("SecKeychainGetPath %p: %s", keychain, sec_errstr(result));
59 else
60 fprintf(stdout, " \"%*s\"\n", (int)pathLength, pathName);
61 }
62
63
64 static void
65 display_list(const char *desc, CFTypeRef keychainOrArray)
66 {
67 if (desc && strlen(desc))
68 fprintf(stdout, "%s\n", desc);
69
70 if (!keychainOrArray)
71 {
72 fprintf(stdout, " <NULL>\n");
73 }
74 else if (CFGetTypeID(keychainOrArray) == SecKeychainGetTypeID())
75 {
76 display_name(keychainOrArray, NULL);
77 }
78 else
79 {
80 CFArrayRef array = (CFArrayRef)keychainOrArray;
81 CFRange range = { 0, CFArrayGetCount(array) };
82 CFArrayApplyFunction(array, range, display_name, NULL);
83 }
84 }
85
86 static int
87 parse_domain(const char *name, SecPreferencesDomain *domain)
88 {
89 size_t len = strlen(name);
90
91 if (!strncmp("user", name, len))
92 *domain = kSecPreferencesDomainUser;
93 else if (!strncmp("system", name, len))
94 *domain = kSecPreferencesDomainSystem;
95 else if (!strncmp("common", name, len))
96 *domain = kSecPreferencesDomainCommon;
97 else if (!strncmp("dynamic", name, len))
98 *domain = kSecPreferencesDomainDynamic;
99 else
100 {
101 sec_error("Invalid domain: %s", name);
102 return 2;
103 }
104
105 return 0;
106 }
107
108 static const char *
109 domain2str(SecPreferencesDomain domain)
110 {
111 switch (domain)
112 {
113 case kSecPreferencesDomainUser:
114 return "user";
115 case kSecPreferencesDomainSystem:
116 return "system";
117 case kSecPreferencesDomainCommon:
118 return "common";
119 case kSecPreferencesDomainDynamic:
120 return "dynamic";
121 default:
122 return "unknown";
123 }
124 }
125
126 static void
127 keychain_ctk_list_item(CFTypeRef item)
128 {
129 char buf[128] = { 0 };
130
131 CFTypeID tid = CFGetTypeID(item);
132 if (tid == CFDictionaryGetTypeID()) {
133 CFStringRef tkid = CFDictionaryGetValue((CFDictionaryRef)item, CFSTR("tkid"));
134 if (CFStringGetCString(tkid, buf, sizeof(buf), kCFStringEncodingUTF8)) {
135 fprintf(stdout, "%s\n", buf);
136 }
137 } else {
138 fprintf(stderr, "Unexpected item.");
139 }
140 }
141
142 static void
143 keychain_ctk_list_items(CFArrayRef items)
144 {
145 CFMutableSetRef displayedItemsRef = CFSetCreateMutable(kCFAllocatorDefault, CFArrayGetCount(items), &kCFTypeSetCallBacks);
146
147 for (CFIndex i = 0; i < CFArrayGetCount(items); i++) {
148 CFDictionaryRef item = CFArrayGetValueAtIndex(items, i);
149
150 if (CFGetTypeID(item) == CFDictionaryGetTypeID()) {
151 CFStringRef tkid = CFDictionaryGetValue((CFDictionaryRef)item, CFSTR("tkid"));
152
153 if (tkid && !CFSetContainsValue(displayedItemsRef, tkid)) {
154 keychain_ctk_list_item(CFArrayGetValueAtIndex(items, i));
155 CFSetAddValue(displayedItemsRef, tkid);
156 }
157 } else {
158 keychain_ctk_list_item(item);
159 }
160 }
161
162 CFRelease(displayedItemsRef);
163 }
164
165 int
166 keychain_list(int argc, char * const *argv)
167 {
168 CFTypeRef keychainOrArray = NULL;
169 CFArrayRef searchList = NULL;
170 list_operation operation = kList;
171 SecPreferencesDomain domain = kSecPreferencesDomainUser;
172 Boolean use_domain = false;
173 int ch, result = 0;
174 OSStatus status;
175
176 while ((ch = getopt(argc, argv, "d:hs")) != -1)
177 {
178 switch (ch)
179 {
180 case 'd':
181 result = parse_domain(optarg, &domain);
182 if (result)
183 return result;
184 use_domain = true;
185 break;
186 case 's':
187 operation = kSet;
188 break;
189 case '?':
190 default:
191 return 2; /* @@@ Return 2 triggers usage message. */
192 }
193 }
194
195 argc -= optind;
196 argv += optind;
197
198 switch (operation)
199 {
200 case kAdd:
201 result = 1;
202 break;
203 case kRemove:
204 result = 1;
205 break;
206 case kList:
207 if (argc > 0)
208 result = 2; // Show usage
209 else
210 {
211 if (use_domain)
212 {
213 status = SecKeychainCopyDomainSearchList(domain, &searchList);
214 if (status)
215 {
216 sec_error("SecKeychainCopyDomainSearchList %s: %s", domain2str(domain), sec_errstr(status));
217 result = 1;
218 }
219 else
220 {
221 #if 0
222 fprintf(stdout, "%s search list: ", domain2str(domain));
223 #endif
224 display_list("", searchList);
225 }
226 }
227 else
228 {
229 status = SecKeychainCopySearchList(&searchList);
230 if (status)
231 {
232 sec_perror("SecKeychainCopySearchList", status);
233 result = 1;
234 }
235 else
236 {
237 #if 0
238 display_list("search list:", searchList);
239 #else
240 display_list("", searchList);
241 #endif
242 }
243 }
244 }
245 break;
246 case kSet:
247 keychainOrArray = keychain_create_array(argc, argv);
248 if (argc == 0)
249 searchList = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
250 else if (argc == 1)
251 searchList = CFArrayCreate(NULL, &keychainOrArray, 1, &kCFTypeArrayCallBacks);
252 else
253 searchList = (CFArrayRef)CFRetain(keychainOrArray);
254
255 if (use_domain)
256 {
257 status = SecKeychainSetDomainSearchList(domain, searchList);
258 if (status)
259 {
260 sec_error("SecKeychainSetDomainSearchList %s: %s", domain2str(domain), sec_errstr(status));
261 result = 1;
262 }
263 }
264 else
265 {
266 status = SecKeychainSetSearchList(searchList);
267 if (status)
268 {
269 sec_perror("SecKeychainSetSearchList", status);
270 result = 1;
271 }
272 }
273 break;
274 }
275
276 if (keychainOrArray)
277 CFRelease(keychainOrArray);
278 if (searchList)
279 CFRelease(searchList);
280
281 return result;
282 }
283
284 int
285 ctk_list(int argc, char * const *argv)
286 {
287 OSStatus stat = errSecSuccess;
288 CFDictionaryRef query = NULL;
289 CFTypeRef result = NULL;
290
291 const void *keys[] = {
292 kSecClass,
293 kSecMatchLimit,
294 kSecAttrAccessGroup,
295 kSecReturnAttributes
296 };
297
298 const void *values[] = {
299 kSecClassIdentity,
300 kSecMatchLimitAll,
301 kSecAttrAccessGroupToken,
302 kCFBooleanTrue
303 };
304
305 query = CFDictionaryCreate(kCFAllocatorDefault,
306 keys,
307 values,
308 sizeof(values) / sizeof(values[0]),
309 &kCFTypeDictionaryKeyCallBacks,
310 &kCFTypeDictionaryValueCallBacks);
311
312 stat = SecItemCopyMatching(query, (CFTypeRef *)&result);
313 if(stat) {
314 if (stat == errSecItemNotFound) {
315 fprintf(stderr, "No smartcards found.\n");
316 } else {
317 sec_error("SecItemCopyMatching: %x (%d) - %s", stat, stat, sec_errstr(stat));
318 }
319 goto cleanup;
320 }
321
322
323 if (CFGetTypeID(result) == CFArrayGetTypeID()) {
324 keychain_ctk_list_items((CFArrayRef)result);
325 } else {
326 keychain_ctk_list_item(result);
327 }
328
329 cleanup:
330 if(query) {
331 CFRelease(query);
332 }
333
334 if(result) {
335 CFRelease(result);
336 }
337
338 return stat;
339 }
340
341 int
342 keychain_default(int argc, char * const *argv)
343 {
344 SecPreferencesDomain domain = kSecPreferencesDomainUser;
345 SecKeychainRef keychain = NULL;
346 Boolean use_domain = false;
347 Boolean do_set = false;
348 int ch, result = 0;
349 OSStatus status;
350
351 while ((ch = getopt(argc, argv, "d:hs")) != -1)
352 {
353 switch (ch)
354 {
355 case 'd':
356 result = parse_domain(optarg, &domain);
357 if (result)
358 return result;
359 use_domain = true;
360 break;
361 case 's':
362 do_set = true;
363 break;
364 case '?':
365 default:
366 return 2; /* @@@ Return 2 triggers usage message. */
367 }
368 }
369
370 argc -= optind;
371 argv += optind;
372
373 if (do_set)
374 {
375 if (argc == 1)
376 keychain = (SecKeychainRef)keychain_create_array(argc, argv);
377 else if (argc > 0)
378 return 2;
379
380 if (use_domain)
381 {
382 status = SecKeychainSetDomainDefault(domain, keychain);
383 if (status)
384 {
385 sec_error("SecKeychainSetDomainDefault %s: %s", domain2str(domain), sec_errstr(status));
386 result = 1;
387 }
388 }
389 else
390 {
391 status = SecKeychainSetDefault(keychain);
392 if (status)
393 {
394 sec_perror("SecKeychainSetDefault", status);
395 result = 1;
396 }
397 }
398 }
399 else
400 {
401 if (argc > 0)
402 return 2;
403
404 if (use_domain)
405 {
406 status = SecKeychainCopyDomainDefault(domain, &keychain);
407 if (status)
408 {
409 sec_error("SecKeychainCopyDomainDefault %s: %s", domain2str(domain), sec_errstr(status));
410 result = 1;
411 }
412 else
413 {
414 #if 0
415 fprintf(stdout, "default %s keychain: ", domain2str(domain));
416 #endif
417 display_list("", keychain);
418 }
419 }
420 else
421 {
422 status = SecKeychainCopyDefault(&keychain);
423 if (status)
424 {
425 sec_perror("SecKeychainCopyDefault", status);
426 result = 1;
427 }
428 else
429 {
430 #if 0
431 display_list("default keychain: ", keychain);
432 #else
433 display_list("", keychain);
434 #endif
435 }
436 }
437 }
438
439 if (keychain)
440 CFRelease(keychain);
441
442 return result;
443 }
444
445 int
446 keychain_login(int argc, char * const *argv)
447 {
448 SecPreferencesDomain domain = kSecPreferencesDomainUser;
449 SecKeychainRef keychain = NULL;
450 Boolean use_domain = false;
451 Boolean do_set = false;
452 int ch, result = 0;
453 OSStatus status;
454
455 while ((ch = getopt(argc, argv, "d:hs")) != -1)
456 {
457 switch (ch)
458 {
459 case 'd':
460 result = parse_domain(optarg, &domain);
461 if (result)
462 return result;
463 use_domain = true;
464 break;
465 case 's':
466 do_set = true;
467 break;
468 case '?':
469 default:
470 return 2; /* @@@ Return 2 triggers usage message. */
471 }
472 }
473
474 argc -= optind;
475 argv += optind;
476
477 if (do_set)
478 {
479 if (argc == 1)
480 keychain = (SecKeychainRef)keychain_create_array(argc, argv);
481 else if (argc > 0)
482 return 2;
483
484 #if 0
485 if (use_domain)
486 {
487 status = SecKeychainSetDomainLogin(domain, keychain);
488 if (status)
489 {
490 sec_error("SecKeychainSetDomainLogin %s: %s", domain2str(domain), sec_errstr(status));
491 result = 1;
492 }
493 }
494 else
495 {
496 status = SecKeychainSetLogin(keychain);
497 if (status)
498 {
499 sec_perror("SecKeychainSetLogin", status);
500 result = 1;
501 }
502 }
503 #else
504 result = 1;
505 #endif
506 }
507 else
508 {
509 if (argc > 0)
510 return 2;
511
512 if (use_domain)
513 {
514 #if 0
515 status = SecKeychainCopyDomainLogin(domain, &keychain);
516 if (status)
517 {
518 sec_error("SecKeychainCopyDomainLogin %s: %s", domain2str(domain), sec_errstr(status));
519 result = 1;
520 }
521 else
522 {
523 #if 0
524 fprintf(stdout, "login %s keychain: ", domain2str(domain));
525 #endif
526 display_list("", keychain);
527 }
528 #else
529 result = 1;
530 #endif
531 }
532 else
533 {
534 status = SecKeychainCopyLogin(&keychain);
535 if (status)
536 {
537 sec_perror("SecKeychainCopyLogin", status);
538 result = 1;
539 }
540 else
541 {
542 #if 0
543 display_list("login keychain: ", keychain);
544 #else
545 display_list("", keychain);
546 #endif
547 }
548 }
549 }
550
551 if (keychain)
552 CFRelease(keychain);
553
554 return result;
555 }