]> git.saurik.com Git - apple/security.git/blob - SecurityTool/keychain_list.c
Security-57740.1.18.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 sec_error("SecItemCopyMatching: %x (%d) - %s",
315 stat, stat, sec_errstr(stat));
316 goto cleanup;
317 }
318
319
320 if (CFGetTypeID(result) == CFArrayGetTypeID()) {
321 keychain_ctk_list_items((CFArrayRef)result);
322 } else {
323 keychain_ctk_list_item(result);
324 }
325
326 cleanup:
327 if(query) {
328 CFRelease(query);
329 }
330
331 if(result) {
332 CFRelease(result);
333 }
334
335 return stat;
336 }
337
338 int
339 keychain_default(int argc, char * const *argv)
340 {
341 SecPreferencesDomain domain = kSecPreferencesDomainUser;
342 SecKeychainRef keychain = NULL;
343 Boolean use_domain = false;
344 Boolean do_set = false;
345 int ch, result = 0;
346 OSStatus status;
347
348 while ((ch = getopt(argc, argv, "d:hs")) != -1)
349 {
350 switch (ch)
351 {
352 case 'd':
353 result = parse_domain(optarg, &domain);
354 if (result)
355 return result;
356 use_domain = true;
357 break;
358 case 's':
359 do_set = true;
360 break;
361 case '?':
362 default:
363 return 2; /* @@@ Return 2 triggers usage message. */
364 }
365 }
366
367 argc -= optind;
368 argv += optind;
369
370 if (do_set)
371 {
372 if (argc == 1)
373 keychain = (SecKeychainRef)keychain_create_array(argc, argv);
374 else if (argc > 0)
375 return 2;
376
377 if (use_domain)
378 {
379 status = SecKeychainSetDomainDefault(domain, keychain);
380 if (status)
381 {
382 sec_error("SecKeychainSetDomainDefault %s: %s", domain2str(domain), sec_errstr(status));
383 result = 1;
384 }
385 }
386 else
387 {
388 status = SecKeychainSetDefault(keychain);
389 if (status)
390 {
391 sec_perror("SecKeychainSetDefault", status);
392 result = 1;
393 }
394 }
395 }
396 else
397 {
398 if (argc > 0)
399 return 2;
400
401 if (use_domain)
402 {
403 status = SecKeychainCopyDomainDefault(domain, &keychain);
404 if (status)
405 {
406 sec_error("SecKeychainCopyDomainDefault %s: %s", domain2str(domain), sec_errstr(status));
407 result = 1;
408 }
409 else
410 {
411 #if 0
412 fprintf(stdout, "default %s keychain: ", domain2str(domain));
413 #endif
414 display_list("", keychain);
415 }
416 }
417 else
418 {
419 status = SecKeychainCopyDefault(&keychain);
420 if (status)
421 {
422 sec_perror("SecKeychainCopyDefault", status);
423 result = 1;
424 }
425 else
426 {
427 #if 0
428 display_list("default keychain: ", keychain);
429 #else
430 display_list("", keychain);
431 #endif
432 }
433 }
434 }
435
436 if (keychain)
437 CFRelease(keychain);
438
439 return result;
440 }
441
442 int
443 keychain_login(int argc, char * const *argv)
444 {
445 SecPreferencesDomain domain = kSecPreferencesDomainUser;
446 SecKeychainRef keychain = NULL;
447 Boolean use_domain = false;
448 Boolean do_set = false;
449 int ch, result = 0;
450 OSStatus status;
451
452 while ((ch = getopt(argc, argv, "d:hs")) != -1)
453 {
454 switch (ch)
455 {
456 case 'd':
457 result = parse_domain(optarg, &domain);
458 if (result)
459 return result;
460 use_domain = true;
461 break;
462 case 's':
463 do_set = true;
464 break;
465 case '?':
466 default:
467 return 2; /* @@@ Return 2 triggers usage message. */
468 }
469 }
470
471 argc -= optind;
472 argv += optind;
473
474 if (do_set)
475 {
476 if (argc == 1)
477 keychain = (SecKeychainRef)keychain_create_array(argc, argv);
478 else if (argc > 0)
479 return 2;
480
481 #if 0
482 if (use_domain)
483 {
484 status = SecKeychainSetDomainLogin(domain, keychain);
485 if (status)
486 {
487 sec_error("SecKeychainSetDomainLogin %s: %s", domain2str(domain), sec_errstr(status));
488 result = 1;
489 }
490 }
491 else
492 {
493 status = SecKeychainSetLogin(keychain);
494 if (status)
495 {
496 sec_perror("SecKeychainSetLogin", status);
497 result = 1;
498 }
499 }
500 #else
501 result = 1;
502 #endif
503 }
504 else
505 {
506 if (argc > 0)
507 return 2;
508
509 if (use_domain)
510 {
511 #if 0
512 status = SecKeychainCopyDomainLogin(domain, &keychain);
513 if (status)
514 {
515 sec_error("SecKeychainCopyDomainLogin %s: %s", domain2str(domain), sec_errstr(status));
516 result = 1;
517 }
518 else
519 {
520 #if 0
521 fprintf(stdout, "login %s keychain: ", domain2str(domain));
522 #endif
523 display_list("", keychain);
524 }
525 #else
526 result = 1;
527 #endif
528 }
529 else
530 {
531 status = SecKeychainCopyLogin(&keychain);
532 if (status)
533 {
534 sec_perror("SecKeychainCopyLogin", status);
535 result = 1;
536 }
537 else
538 {
539 #if 0
540 display_list("login keychain: ", keychain);
541 #else
542 display_list("", keychain);
543 #endif
544 }
545 }
546 }
547
548 if (keychain)
549 CFRelease(keychain);
550
551 return result;
552 }