2 * Copyright (c) 2004-2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * aclUtils.cpp - ACL utility functions, copied from the SecurityTool project.
29 #include <Security/SecTrustedApplicationPriv.h>
30 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
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. */
37 readline(char *buffer
, int buffer_size
)
39 int ix
= 0, bytes_malloced
= 0;
44 buffer
= (char *)malloc(bytes_malloced
);
45 buffer_size
= bytes_malloced
;
52 if (ix
== buffer_size
- 1)
56 bytes_malloced
+= bytes_malloced
;
57 buffer
= (char *)realloc(buffer
, bytes_malloced
);
58 buffer_size
= bytes_malloced
;
73 /* 0 terminate buffer. */
80 print_buffer_hex(FILE *stream
, UInt32 length
, const void *data
)
83 const unsigned char *cp
= (const unsigned char *)data
;
86 for(i
=0; i
<length
; i
++) {
87 fprintf(stream
, "%02X ", cp
[i
]);
95 print_buffer_ascii(FILE *stream
, UInt32 length
, const void *data
)
97 uint8
*p
= (uint8
*) data
;
101 if (ch
>= ' ' && ch
<= '~' && ch
!= '\\')
108 fputc('0' + ((ch
>> 6) & 7), stream
);
109 fputc('0' + ((ch
>> 3) & 7), stream
);
110 fputc('0' + ((ch
>> 0) & 7), stream
);
116 print_buffer(FILE *stream
, UInt32 length
, const void *data
)
118 uint8
*p
= (uint8
*) data
;
119 Boolean ascii
= TRUE
; // unless we determine otherwise
121 for (ix
= 0; ix
< length
; ++ix
) {
123 if ((ch
< ' ') || (ch
> '~')) {
124 if((ch
== 0) && (ix
== (length
- 1))) {
125 /* ignore trailing null */
136 print_buffer_ascii(stream
, length
, data
);
140 print_buffer_hex(stream
, length
, data
);
145 print_cfdata(FILE *stream
, CFDataRef data
)
148 return print_buffer(stream
, CFDataGetLength(data
), CFDataGetBytePtr(data
));
150 fprintf(stream
, "<NULL>");
154 print_cfstring(FILE *stream
, CFStringRef string
)
157 fprintf(stream
, "<NULL>");
160 const char *utf8
= CFStringGetCStringPtr(string
, kCFStringEncodingUTF8
);
162 fprintf(stream
, "%s", utf8
);
165 CFRange rangeToProcess
= CFRangeMake(0, CFStringGetLength(string
));
166 while (rangeToProcess
.length
> 0)
168 UInt8 localBuffer
[256];
169 CFIndex usedBufferLength
;
170 CFIndex numChars
= CFStringGetBytes(string
, rangeToProcess
,
171 kCFStringEncodingUTF8
, '?', FALSE
, localBuffer
,
172 sizeof(localBuffer
), &usedBufferLength
);
174 break; // Failed to convert anything...
176 fprintf(stream
, "%.*s", (int)usedBufferLength
, localBuffer
);
177 rangeToProcess
.location
+= numChars
;
178 rangeToProcess
.length
-= numChars
;
186 print_access(FILE *stream
, SecAccessRef access
, Boolean interactive
)
188 CFArrayRef aclList
= NULL
;
189 CFIndex aclix
, aclCount
;
193 status
= SecAccessCopyACLList(access
, &aclList
);
196 cssmPerror("SecAccessCopyACLList", status
);
201 aclCount
= CFArrayGetCount(aclList
);
202 fprintf(stream
, "access: %lu entries\n", aclCount
);
203 for (aclix
= 0; aclix
< aclCount
; ++aclix
)
205 CFArrayRef applicationList
= NULL
;
206 CFStringRef description
= NULL
;
207 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
= {};
208 CFIndex appix
, appCount
;
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
);
216 cssmPerror("SecACLGetAuthorizations", status
);
221 fprintf(stream
, " entry %lu:\n authorizations (%lu):", aclix
, (unsigned long)tagCount
);
222 for (tagix
= 0; tagix
< tagCount
; ++tagix
)
224 CSSM_ACL_AUTHORIZATION_TAG tag
= tags
[tagix
];
227 case CSSM_ACL_AUTHORIZATION_ANY
:
228 fputs(" any", stream
);
230 case CSSM_ACL_AUTHORIZATION_LOGIN
:
231 fputs(" login", stream
);
233 case CSSM_ACL_AUTHORIZATION_GENKEY
:
234 fputs(" genkey", stream
);
236 case CSSM_ACL_AUTHORIZATION_DELETE
:
237 fputs(" delete", stream
);
239 case CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
:
240 fputs(" export_wrapped", stream
);
242 case CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR
:
243 fputs(" export_clear", stream
);
245 case CSSM_ACL_AUTHORIZATION_IMPORT_WRAPPED
:
246 fputs(" import_wrapped", stream
);
248 case CSSM_ACL_AUTHORIZATION_IMPORT_CLEAR
:
249 fputs(" import_clear", stream
);
251 case CSSM_ACL_AUTHORIZATION_SIGN
:
252 fputs(" sign", stream
);
254 case CSSM_ACL_AUTHORIZATION_ENCRYPT
:
255 fputs(" encrypt", stream
);
257 case CSSM_ACL_AUTHORIZATION_DECRYPT
:
258 fputs(" decrypt", stream
);
260 case CSSM_ACL_AUTHORIZATION_MAC
:
261 fputs(" mac", stream
);
263 case CSSM_ACL_AUTHORIZATION_DERIVE
:
264 fputs(" derive", stream
);
266 case CSSM_ACL_AUTHORIZATION_DBS_CREATE
:
267 fputs(" dbs_create", stream
);
269 case CSSM_ACL_AUTHORIZATION_DBS_DELETE
:
270 fputs(" dbs_delete", stream
);
272 case CSSM_ACL_AUTHORIZATION_DB_READ
:
273 fputs(" db_read", stream
);
275 case CSSM_ACL_AUTHORIZATION_DB_INSERT
:
276 fputs(" db_insert", stream
);
278 case CSSM_ACL_AUTHORIZATION_DB_MODIFY
:
279 fputs(" db_modify", stream
);
281 case CSSM_ACL_AUTHORIZATION_DB_DELETE
:
282 fputs(" db_delete", stream
);
284 case CSSM_ACL_AUTHORIZATION_CHANGE_ACL
:
285 fputs(" change_acl", stream
);
287 case CSSM_ACL_AUTHORIZATION_CHANGE_OWNER
:
288 fputs(" change_owner", stream
);
291 fprintf(stream
, " tag=%lu", (unsigned long)tag
);
297 status
= SecACLCopySimpleContents(acl
, &applicationList
, &description
, &promptSelector
);
300 cssmPerror("SecACLCopySimpleContents", status
);
304 if (promptSelector
.flags
& CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE
)
305 fputs(" require-password\n", stream
);
307 fputs(" don't-require-password\n", stream
);
309 fputs(" description: ", stream
);
310 print_cfstring(stream
, description
);
315 appCount
= CFArrayGetCount(applicationList
);
316 fprintf(stream
, " applications (%lu):\n", appCount
);
321 fprintf(stream
, " applications: <null>\n");
324 for (appix
= 0; appix
< appCount
; ++appix
)
327 SecTrustedApplicationRef app
= (SecTrustedApplicationRef
)CFArrayGetValueAtIndex(applicationList
, appix
);
328 CFDataRef data
= NULL
;
329 fprintf(stream
, " %lu: ", appix
);
330 status
= SecTrustedApplicationCopyData(app
, &data
);
333 cssmPerror("SecTrustedApplicationCopyData", status
);
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)");
343 fprintf(stream
, " (status %ld)", status
);
345 fprintf(stream
, "\n");
347 print_cfdata(stream
, data
);
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')
363 * This makes the ops in this entry wide-open, no dialog or confirmation
364 * other than requiring the keychain be open.
366 fprintf(stderr
, "setting app list to NULL\n");
367 status
= SecACLSetSimpleContents(acl
, NULL
, description
, &promptSelector
);
370 cssmPerror("SecACLSetSimpleContents", status
);
375 fprintf(stderr
, "Set this application list to empty array? ");
376 if (readline(buffer
, sizeof(buffer
)) && buffer
[0] == 'y')
379 * This means "always get confirmation, from all apps".
381 fprintf(stderr
, "setting app list to empty array\n");
382 status
= SecACLSetSimpleContents(acl
,
383 CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
),
384 description
, &promptSelector
);
387 cssmPerror("SecACLSetSimpleContents", status
);
394 fprintf(stderr
, "Remove this acl? ");
395 if (readline(buffer
, sizeof(buffer
)) && buffer
[0] == 'y')
398 * This make ths ops in this entry completely inaccessible.
400 fprintf(stderr
, "removing acl\n");
401 status
= SecACLRemove(acl
);
404 cssmPerror("SecACLRemove", status
);
411 CFRelease(description
);
413 CFRelease(applicationList
);
424 /* Simluate what StickyRecord is trying to do.... */
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
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
437 static OSStatus
srUpdateAcl(
438 SecAccessRef accessRef
,
439 CSSM_ACL_AUTHORIZATION_TAG whichAcl
, // e.g. CSSM_ACL_AUTHORIZATION_DECRYPT
441 bool requirePassphrase
)
444 CFArrayRef aclList
= NULL
;
446 ortn
= SecAccessCopySelectedACLList(accessRef
, whichAcl
, &aclList
);
448 cssmPerror("SecAccessCopySelectedACLList", ortn
);
452 if(CFArrayGetCount(aclList
) != 1) {
453 printf("StickyRecord::updateAcl - unexpected ACL list count (%d)",
454 (int)CFArrayGetCount(aclList
));
455 return internalComponentErr
;
457 SecACLRef acl
= (SecACLRef
)CFArrayGetValueAtIndex(aclList
, 0);
459 CFArrayRef applicationList
= NULL
;
460 CFStringRef description
= NULL
;
461 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
= {};
462 ortn
= SecACLCopySimpleContents(acl
, &applicationList
, &description
, &promptSelector
);
464 cssmPerror("SecACLCopySimpleContents", ortn
);
467 if(applicationList
!= NULL
) {
468 CFRelease(applicationList
);
470 if(requirePassphrase
) {
471 promptSelector
.flags
|= CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE
;
474 promptSelector
.flags
&= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE
;
477 ortn
= SecACLSetSimpleContents(acl
, appArray
, description
, &promptSelector
);
479 /* we got this from SecACLCopySimpleContents - release it regardless */
480 if(description
!= NULL
) {
481 CFRelease(description
);
484 cssmPerror("SecACLSetSimpleContents", ortn
);
486 if(aclList
!= NULL
) {
492 OSStatus
stickyRecordUpdateAcl(
493 SecAccessRef accessRef
)
497 printf("...updating ACL to simulate a StickyRecord\n");
499 /* First: decrypt. Wide open (NULL app list), !REQUIRE_PASSPHRASE. */
500 ortn
= srUpdateAcl(accessRef
, CSSM_ACL_AUTHORIZATION_DECRYPT
, NULL
, false);
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);