]> git.saurik.com Git - apple/security.git/blob - SecurityTests/cspxutils/acltool/aclUtils.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / cspxutils / acltool / aclUtils.cpp
1 /*
2 * Copyright (c) 2004-2006 Apple Computer, 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
24 /*
25 * aclUtils.cpp - ACL utility functions, copied from the SecurityTool project.
26 */
27
28 #include "aclUtils.h"
29 #include <Security/SecTrustedApplicationPriv.h>
30 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
31
32 /* Read a line from stdin into buffer as a null terminated string. If buffer is
33 non NULL use at most buffer_size bytes and return a pointer to buffer. Otherwise
34 return a newly malloced buffer.
35 if EOF is read this function returns NULL. */
36 char *
37 readline(char *buffer, int buffer_size)
38 {
39 int ix = 0, bytes_malloced = 0;
40
41 if (!buffer)
42 {
43 bytes_malloced = 64;
44 buffer = (char *)malloc(bytes_malloced);
45 buffer_size = bytes_malloced;
46 }
47
48 for (;;++ix)
49 {
50 int ch;
51
52 if (ix == buffer_size - 1)
53 {
54 if (!bytes_malloced)
55 break;
56 bytes_malloced += bytes_malloced;
57 buffer = (char *)realloc(buffer, bytes_malloced);
58 buffer_size = bytes_malloced;
59 }
60
61 ch = getchar();
62 if (ch == EOF)
63 {
64 if (bytes_malloced)
65 free(buffer);
66 return NULL;
67 }
68 if (ch == '\n')
69 break;
70 buffer[ix] = ch;
71 }
72
73 /* 0 terminate buffer. */
74 buffer[ix] = '\0';
75
76 return buffer;
77 }
78
79 void
80 print_buffer_hex(FILE *stream, UInt32 length, const void *data)
81 {
82 unsigned i;
83 const unsigned char *cp = (const unsigned char *)data;
84
85 printf("\n ");
86 for(i=0; i<length; i++) {
87 fprintf(stream, "%02X ", cp[i]);
88 if((i % 24) == 23) {
89 printf("\n ");
90 }
91 }
92 }
93
94 void
95 print_buffer_ascii(FILE *stream, UInt32 length, const void *data)
96 {
97 uint8 *p = (uint8 *) data;
98 while (length--)
99 {
100 int ch = *p++;
101 if (ch >= ' ' && ch <= '~' && ch != '\\')
102 {
103 fputc(ch, stream);
104 }
105 else
106 {
107 fputc('\\', stream);
108 fputc('0' + ((ch >> 6) & 7), stream);
109 fputc('0' + ((ch >> 3) & 7), stream);
110 fputc('0' + ((ch >> 0) & 7), stream);
111 }
112 }
113 }
114
115 void
116 print_buffer(FILE *stream, UInt32 length, const void *data)
117 {
118 uint8 *p = (uint8 *) data;
119 Boolean ascii = TRUE; // unless we determine otherwise
120 UInt32 ix;
121 for (ix = 0; ix < length; ++ix) {
122 int ch = *p++;
123 if ((ch < ' ') || (ch > '~')) {
124 if((ch == 0) && (ix == (length - 1))) {
125 /* ignore trailing null */
126 length--;
127 break;
128 }
129 ascii = FALSE;
130 break;
131 }
132 }
133
134 if (ascii) {
135 fputc('"', stream);
136 print_buffer_ascii(stream, length, data);
137 fputc('"', stream);
138 }
139 else {
140 print_buffer_hex(stream, length, data);
141 }
142 }
143
144 void
145 print_cfdata(FILE *stream, CFDataRef data)
146 {
147 if (data)
148 return print_buffer(stream, CFDataGetLength(data), CFDataGetBytePtr(data));
149 else
150 fprintf(stream, "<NULL>");
151 }
152
153 void
154 print_cfstring(FILE *stream, CFStringRef string)
155 {
156 if (!string)
157 fprintf(stream, "<NULL>");
158 else
159 {
160 const char *utf8 = CFStringGetCStringPtr(string, kCFStringEncodingUTF8);
161 if (utf8)
162 fprintf(stream, "%s", utf8);
163 else
164 {
165 CFRange rangeToProcess = CFRangeMake(0, CFStringGetLength(string));
166 while (rangeToProcess.length > 0)
167 {
168 UInt8 localBuffer[256];
169 CFIndex usedBufferLength;
170 CFIndex numChars = CFStringGetBytes(string, rangeToProcess,
171 kCFStringEncodingUTF8, '?', FALSE, localBuffer,
172 sizeof(localBuffer), &usedBufferLength);
173 if (numChars == 0)
174 break; // Failed to convert anything...
175
176 fprintf(stream, "%.*s", (int)usedBufferLength, localBuffer);
177 rangeToProcess.location += numChars;
178 rangeToProcess.length -= numChars;
179 }
180 }
181 }
182 }
183
184
185 int
186 print_access(FILE *stream, SecAccessRef access, Boolean interactive)
187 {
188 CFArrayRef aclList = NULL;
189 CFIndex aclix, aclCount;
190 int result = 0;
191 OSStatus status;
192
193 status = SecAccessCopyACLList(access, &aclList);
194 if (status)
195 {
196 cssmPerror("SecAccessCopyACLList", status);
197 result = 1;
198 goto loser;
199 }
200
201 aclCount = CFArrayGetCount(aclList);
202 fprintf(stream, "access: %lu entries\n", aclCount);
203 for (aclix = 0; aclix < aclCount; ++aclix)
204 {
205 CFArrayRef applicationList = NULL;
206 CFStringRef description = NULL;
207 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector = {};
208 CFIndex appix, appCount;
209
210 SecACLRef acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, aclix);
211 CSSM_ACL_AUTHORIZATION_TAG tags[64]; // Pick some upper limit
212 uint32 tagix, tagCount = sizeof(tags) / sizeof(*tags);
213 status = SecACLGetAuthorizations(acl, tags, &tagCount);
214 if (status)
215 {
216 cssmPerror("SecACLGetAuthorizations", status);
217 result = 1;
218 goto loser;
219 }
220
221 fprintf(stream, " entry %lu:\n authorizations (%lu):", aclix, (unsigned long)tagCount);
222 for (tagix = 0; tagix < tagCount; ++tagix)
223 {
224 CSSM_ACL_AUTHORIZATION_TAG tag = tags[tagix];
225 switch (tag)
226 {
227 case CSSM_ACL_AUTHORIZATION_ANY:
228 fputs(" any", stream);
229 break;
230 case CSSM_ACL_AUTHORIZATION_LOGIN:
231 fputs(" login", stream);
232 break;
233 case CSSM_ACL_AUTHORIZATION_GENKEY:
234 fputs(" genkey", stream);
235 break;
236 case CSSM_ACL_AUTHORIZATION_DELETE:
237 fputs(" delete", stream);
238 break;
239 case CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED:
240 fputs(" export_wrapped", stream);
241 break;
242 case CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR:
243 fputs(" export_clear", stream);
244 break;
245 case CSSM_ACL_AUTHORIZATION_IMPORT_WRAPPED:
246 fputs(" import_wrapped", stream);
247 break;
248 case CSSM_ACL_AUTHORIZATION_IMPORT_CLEAR:
249 fputs(" import_clear", stream);
250 break;
251 case CSSM_ACL_AUTHORIZATION_SIGN:
252 fputs(" sign", stream);
253 break;
254 case CSSM_ACL_AUTHORIZATION_ENCRYPT:
255 fputs(" encrypt", stream);
256 break;
257 case CSSM_ACL_AUTHORIZATION_DECRYPT:
258 fputs(" decrypt", stream);
259 break;
260 case CSSM_ACL_AUTHORIZATION_MAC:
261 fputs(" mac", stream);
262 break;
263 case CSSM_ACL_AUTHORIZATION_DERIVE:
264 fputs(" derive", stream);
265 break;
266 case CSSM_ACL_AUTHORIZATION_DBS_CREATE:
267 fputs(" dbs_create", stream);
268 break;
269 case CSSM_ACL_AUTHORIZATION_DBS_DELETE:
270 fputs(" dbs_delete", stream);
271 break;
272 case CSSM_ACL_AUTHORIZATION_DB_READ:
273 fputs(" db_read", stream);
274 break;
275 case CSSM_ACL_AUTHORIZATION_DB_INSERT:
276 fputs(" db_insert", stream);
277 break;
278 case CSSM_ACL_AUTHORIZATION_DB_MODIFY:
279 fputs(" db_modify", stream);
280 break;
281 case CSSM_ACL_AUTHORIZATION_DB_DELETE:
282 fputs(" db_delete", stream);
283 break;
284 case CSSM_ACL_AUTHORIZATION_CHANGE_ACL:
285 fputs(" change_acl", stream);
286 break;
287 case CSSM_ACL_AUTHORIZATION_CHANGE_OWNER:
288 fputs(" change_owner", stream);
289 break;
290 default:
291 fprintf(stream, " tag=%lu", (unsigned long)tag);
292 break;
293 }
294 }
295 fputc('\n', stream);
296
297 status = SecACLCopySimpleContents(acl, &applicationList, &description, &promptSelector);
298 if (status)
299 {
300 cssmPerror("SecACLCopySimpleContents", status);
301 continue;
302 }
303
304 if (promptSelector.flags & CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE)
305 fputs(" require-password\n", stream);
306 else
307 fputs(" don't-require-password\n", stream);
308
309 fputs(" description: ", stream);
310 print_cfstring(stream, description);
311 fputc('\n', stream);
312
313 if (applicationList)
314 {
315 appCount = CFArrayGetCount(applicationList);
316 fprintf(stream, " applications (%lu):\n", appCount);
317 }
318 else
319 {
320 appCount = 0;
321 fprintf(stream, " applications: <null>\n");
322 }
323
324 for (appix = 0; appix < appCount; ++appix)
325 {
326 const UInt8* bytes;
327 SecTrustedApplicationRef app = (SecTrustedApplicationRef)CFArrayGetValueAtIndex(applicationList, appix);
328 CFDataRef data = NULL;
329 fprintf(stream, " %lu: ", appix);
330 status = SecTrustedApplicationCopyData(app, &data);
331 if (status)
332 {
333 cssmPerror("SecTrustedApplicationCopyData", status);
334 continue;
335 }
336
337 bytes = CFDataGetBytePtr(data);
338 if (bytes && bytes[0] == 0x2f) {
339 fprintf(stream, "%s", (const char *)bytes);
340 if ((status = SecTrustedApplicationValidateWithPath(app, (const char *)bytes)) == noErr) {
341 fprintf(stream, " (OK)");
342 } else {
343 fprintf(stream, " (status %ld)", status);
344 }
345 fprintf(stream, "\n");
346 } else {
347 print_cfdata(stream, data);
348 fputc('\n', stream);
349 }
350 if (data)
351 CFRelease(data);
352 }
353
354
355 if (interactive)
356 {
357 char buffer[10] = {};
358 if(applicationList != NULL) {
359 fprintf(stderr, "NULL out this application list? ");
360 if (readline(buffer, sizeof(buffer)) && buffer[0] == 'y')
361 {
362 /*
363 * This makes the ops in this entry wide-open, no dialog or confirmation
364 * other than requiring the keychain be open.
365 */
366 fprintf(stderr, "setting app list to NULL\n");
367 status = SecACLSetSimpleContents(acl, NULL, description, &promptSelector);
368 if (status)
369 {
370 cssmPerror("SecACLSetSimpleContents", status);
371 continue;
372 }
373 }
374 else {
375 fprintf(stderr, "Set this application list to empty array? ");
376 if (readline(buffer, sizeof(buffer)) && buffer[0] == 'y')
377 {
378 /*
379 * This means "always get confirmation, from all apps".
380 */
381 fprintf(stderr, "setting app list to empty array\n");
382 status = SecACLSetSimpleContents(acl,
383 CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks),
384 description, &promptSelector);
385 if (status)
386 {
387 cssmPerror("SecACLSetSimpleContents", status);
388 continue;
389 }
390 }
391 }
392 }
393 else {
394 fprintf(stderr, "Remove this acl? ");
395 if (readline(buffer, sizeof(buffer)) && buffer[0] == 'y')
396 {
397 /*
398 * This make ths ops in this entry completely inaccessible.
399 */
400 fprintf(stderr, "removing acl\n");
401 status = SecACLRemove(acl);
402 if (status)
403 {
404 cssmPerror("SecACLRemove", status);
405 continue;
406 }
407 }
408 }
409 }
410 if (description)
411 CFRelease(description);
412 if (applicationList)
413 CFRelease(applicationList);
414
415 }
416
417 loser:
418 if (aclList)
419 CFRelease(aclList);
420
421 return result;
422 }
423
424 /* Simluate what StickyRecord is trying to do.... */
425
426 /*
427 * Given an Access object:
428 * -- extract the ACL for the specified CSSM_ACL_AUTHORIZATION_TAG. We expect there
429 * to exactly one of these - if the form of a default ACL changes we'll have to
430 * revisit this.
431 * -- set the ACL's app list to the provided CFArray, which may be NULL (meaning
432 * "any app can access this, no problem"), an empty array (meaning "always
433 * prompt"), or an actual app list.
434 * -- set or clear the PROMPT_REQUIRE_PASSPHRASE bit per the requirePassphrase
435 * argument
436 */
437 static OSStatus srUpdateAcl(
438 SecAccessRef accessRef,
439 CSSM_ACL_AUTHORIZATION_TAG whichAcl, // e.g. CSSM_ACL_AUTHORIZATION_DECRYPT
440 CFArrayRef appArray,
441 bool requirePassphrase)
442 {
443 OSStatus ortn;
444 CFArrayRef aclList = NULL;
445
446 ortn = SecAccessCopySelectedACLList(accessRef, whichAcl, &aclList);
447 if(ortn) {
448 cssmPerror("SecAccessCopySelectedACLList", ortn);
449 return ortn;
450 }
451
452 if(CFArrayGetCount(aclList) != 1) {
453 printf("StickyRecord::updateAcl - unexpected ACL list count (%d)",
454 (int)CFArrayGetCount(aclList));
455 return internalComponentErr;
456 }
457 SecACLRef acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
458
459 CFArrayRef applicationList = NULL;
460 CFStringRef description = NULL;
461 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector = {};
462 ortn = SecACLCopySimpleContents(acl, &applicationList, &description, &promptSelector);
463 if(ortn) {
464 cssmPerror("SecACLCopySimpleContents", ortn);
465 return ortn;
466 }
467 if(applicationList != NULL) {
468 CFRelease(applicationList);
469 }
470 if(requirePassphrase) {
471 promptSelector.flags |= CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
472 }
473 else {
474 promptSelector.flags &= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
475 }
476 /* update */
477 ortn = SecACLSetSimpleContents(acl, appArray, description, &promptSelector);
478
479 /* we got this from SecACLCopySimpleContents - release it regardless */
480 if(description != NULL) {
481 CFRelease(description);
482 }
483 if(ortn) {
484 cssmPerror("SecACLSetSimpleContents", ortn);
485 }
486 if(aclList != NULL) {
487 CFRelease(aclList);
488 }
489 return ortn;
490 }
491
492 OSStatus stickyRecordUpdateAcl(
493 SecAccessRef accessRef)
494 {
495 OSStatus ortn;
496
497 printf("...updating ACL to simulate a StickyRecord\n");
498
499 /* First: decrypt. Wide open (NULL app list), !REQUIRE_PASSPHRASE. */
500 ortn = srUpdateAcl(accessRef, CSSM_ACL_AUTHORIZATION_DECRYPT, NULL, false);
501 if(ortn) {
502 return ortn;
503 }
504
505 /* encrypt: always ask (empty app list, require passphrase */
506 CFArrayRef nullArray = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
507 return srUpdateAcl(accessRef, CSSM_ACL_AUTHORIZATION_ENCRYPT, nullArray, true);
508
509 }