#include "aclUtils.h"
#include <Security/SecTrustedApplicationPriv.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
char *
readline(char *buffer, int buffer_size)
{
int ix = 0, bytes_malloced = 0;
if (!buffer)
{
bytes_malloced = 64;
buffer = (char *)malloc(bytes_malloced);
buffer_size = bytes_malloced;
}
for (;;++ix)
{
int ch;
if (ix == buffer_size - 1)
{
if (!bytes_malloced)
break;
bytes_malloced += bytes_malloced;
buffer = (char *)realloc(buffer, bytes_malloced);
buffer_size = bytes_malloced;
}
ch = getchar();
if (ch == EOF)
{
if (bytes_malloced)
free(buffer);
return NULL;
}
if (ch == '\n')
break;
buffer[ix] = ch;
}
buffer[ix] = '\0';
return buffer;
}
void
print_buffer_hex(FILE *stream, UInt32 length, const void *data)
{
unsigned i;
const unsigned char *cp = (const unsigned char *)data;
printf("\n ");
for(i=0; i<length; i++) {
fprintf(stream, "%02X ", cp[i]);
if((i % 24) == 23) {
printf("\n ");
}
}
}
void
print_buffer_ascii(FILE *stream, UInt32 length, const void *data)
{
uint8 *p = (uint8 *) data;
while (length--)
{
int ch = *p++;
if (ch >= ' ' && ch <= '~' && ch != '\\')
{
fputc(ch, stream);
}
else
{
fputc('\\', stream);
fputc('0' + ((ch >> 6) & 7), stream);
fputc('0' + ((ch >> 3) & 7), stream);
fputc('0' + ((ch >> 0) & 7), stream);
}
}
}
void
print_buffer(FILE *stream, UInt32 length, const void *data)
{
uint8 *p = (uint8 *) data;
Boolean ascii = TRUE; UInt32 ix;
for (ix = 0; ix < length; ++ix) {
int ch = *p++;
if ((ch < ' ') || (ch > '~')) {
if((ch == 0) && (ix == (length - 1))) {
length--;
break;
}
ascii = FALSE;
break;
}
}
if (ascii) {
fputc('"', stream);
print_buffer_ascii(stream, length, data);
fputc('"', stream);
}
else {
print_buffer_hex(stream, length, data);
}
}
void
print_cfdata(FILE *stream, CFDataRef data)
{
if (data)
return print_buffer(stream, CFDataGetLength(data), CFDataGetBytePtr(data));
else
fprintf(stream, "<NULL>");
}
void
print_cfstring(FILE *stream, CFStringRef string)
{
if (!string)
fprintf(stream, "<NULL>");
else
{
const char *utf8 = CFStringGetCStringPtr(string, kCFStringEncodingUTF8);
if (utf8)
fprintf(stream, "%s", utf8);
else
{
CFRange rangeToProcess = CFRangeMake(0, CFStringGetLength(string));
while (rangeToProcess.length > 0)
{
UInt8 localBuffer[256];
CFIndex usedBufferLength;
CFIndex numChars = CFStringGetBytes(string, rangeToProcess,
kCFStringEncodingUTF8, '?', FALSE, localBuffer,
sizeof(localBuffer), &usedBufferLength);
if (numChars == 0)
break;
fprintf(stream, "%.*s", (int)usedBufferLength, localBuffer);
rangeToProcess.location += numChars;
rangeToProcess.length -= numChars;
}
}
}
}
int
print_access(FILE *stream, SecAccessRef access, Boolean interactive)
{
CFArrayRef aclList = NULL;
CFIndex aclix, aclCount;
int result = 0;
OSStatus status;
status = SecAccessCopyACLList(access, &aclList);
if (status)
{
cssmPerror("SecAccessCopyACLList", status);
result = 1;
goto loser;
}
aclCount = CFArrayGetCount(aclList);
fprintf(stream, "access: %lu entries\n", aclCount);
for (aclix = 0; aclix < aclCount; ++aclix)
{
CFArrayRef applicationList = NULL;
CFStringRef description = NULL;
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector = {};
CFIndex appix, appCount;
SecACLRef acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, aclix);
CSSM_ACL_AUTHORIZATION_TAG tags[64]; uint32 tagix, tagCount = sizeof(tags) / sizeof(*tags);
status = SecACLGetAuthorizations(acl, tags, &tagCount);
if (status)
{
cssmPerror("SecACLGetAuthorizations", status);
result = 1;
goto loser;
}
fprintf(stream, " entry %lu:\n authorizations (%lu):", aclix, (unsigned long)tagCount);
for (tagix = 0; tagix < tagCount; ++tagix)
{
CSSM_ACL_AUTHORIZATION_TAG tag = tags[tagix];
switch (tag)
{
case CSSM_ACL_AUTHORIZATION_ANY:
fputs(" any", stream);
break;
case CSSM_ACL_AUTHORIZATION_LOGIN:
fputs(" login", stream);
break;
case CSSM_ACL_AUTHORIZATION_GENKEY:
fputs(" genkey", stream);
break;
case CSSM_ACL_AUTHORIZATION_DELETE:
fputs(" delete", stream);
break;
case CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED:
fputs(" export_wrapped", stream);
break;
case CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR:
fputs(" export_clear", stream);
break;
case CSSM_ACL_AUTHORIZATION_IMPORT_WRAPPED:
fputs(" import_wrapped", stream);
break;
case CSSM_ACL_AUTHORIZATION_IMPORT_CLEAR:
fputs(" import_clear", stream);
break;
case CSSM_ACL_AUTHORIZATION_SIGN:
fputs(" sign", stream);
break;
case CSSM_ACL_AUTHORIZATION_ENCRYPT:
fputs(" encrypt", stream);
break;
case CSSM_ACL_AUTHORIZATION_DECRYPT:
fputs(" decrypt", stream);
break;
case CSSM_ACL_AUTHORIZATION_MAC:
fputs(" mac", stream);
break;
case CSSM_ACL_AUTHORIZATION_DERIVE:
fputs(" derive", stream);
break;
case CSSM_ACL_AUTHORIZATION_DBS_CREATE:
fputs(" dbs_create", stream);
break;
case CSSM_ACL_AUTHORIZATION_DBS_DELETE:
fputs(" dbs_delete", stream);
break;
case CSSM_ACL_AUTHORIZATION_DB_READ:
fputs(" db_read", stream);
break;
case CSSM_ACL_AUTHORIZATION_DB_INSERT:
fputs(" db_insert", stream);
break;
case CSSM_ACL_AUTHORIZATION_DB_MODIFY:
fputs(" db_modify", stream);
break;
case CSSM_ACL_AUTHORIZATION_DB_DELETE:
fputs(" db_delete", stream);
break;
case CSSM_ACL_AUTHORIZATION_CHANGE_ACL:
fputs(" change_acl", stream);
break;
case CSSM_ACL_AUTHORIZATION_CHANGE_OWNER:
fputs(" change_owner", stream);
break;
default:
fprintf(stream, " tag=%lu", (unsigned long)tag);
break;
}
}
fputc('\n', stream);
status = SecACLCopySimpleContents(acl, &applicationList, &description, &promptSelector);
if (status)
{
cssmPerror("SecACLCopySimpleContents", status);
continue;
}
if (promptSelector.flags & CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE)
fputs(" require-password\n", stream);
else
fputs(" don't-require-password\n", stream);
fputs(" description: ", stream);
print_cfstring(stream, description);
fputc('\n', stream);
if (applicationList)
{
appCount = CFArrayGetCount(applicationList);
fprintf(stream, " applications (%lu):\n", appCount);
}
else
{
appCount = 0;
fprintf(stream, " applications: <null>\n");
}
for (appix = 0; appix < appCount; ++appix)
{
const UInt8* bytes;
SecTrustedApplicationRef app = (SecTrustedApplicationRef)CFArrayGetValueAtIndex(applicationList, appix);
CFDataRef data = NULL;
fprintf(stream, " %lu: ", appix);
status = SecTrustedApplicationCopyData(app, &data);
if (status)
{
cssmPerror("SecTrustedApplicationCopyData", status);
continue;
}
bytes = CFDataGetBytePtr(data);
if (bytes && bytes[0] == 0x2f) {
fprintf(stream, "%s", (const char *)bytes);
if ((status = SecTrustedApplicationValidateWithPath(app, (const char *)bytes)) == noErr) {
fprintf(stream, " (OK)");
} else {
fprintf(stream, " (status %ld)", status);
}
fprintf(stream, "\n");
} else {
print_cfdata(stream, data);
fputc('\n', stream);
}
if (data)
CFRelease(data);
}
if (interactive)
{
char buffer[10] = {};
if(applicationList != NULL) {
fprintf(stderr, "NULL out this application list? ");
if (readline(buffer, sizeof(buffer)) && buffer[0] == 'y')
{
fprintf(stderr, "setting app list to NULL\n");
status = SecACLSetSimpleContents(acl, NULL, description, &promptSelector);
if (status)
{
cssmPerror("SecACLSetSimpleContents", status);
continue;
}
}
else {
fprintf(stderr, "Set this application list to empty array? ");
if (readline(buffer, sizeof(buffer)) && buffer[0] == 'y')
{
fprintf(stderr, "setting app list to empty array\n");
status = SecACLSetSimpleContents(acl,
CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks),
description, &promptSelector);
if (status)
{
cssmPerror("SecACLSetSimpleContents", status);
continue;
}
}
}
}
else {
fprintf(stderr, "Remove this acl? ");
if (readline(buffer, sizeof(buffer)) && buffer[0] == 'y')
{
fprintf(stderr, "removing acl\n");
status = SecACLRemove(acl);
if (status)
{
cssmPerror("SecACLRemove", status);
continue;
}
}
}
}
if (description)
CFRelease(description);
if (applicationList)
CFRelease(applicationList);
}
loser:
if (aclList)
CFRelease(aclList);
return result;
}
static OSStatus srUpdateAcl(
SecAccessRef accessRef,
CSSM_ACL_AUTHORIZATION_TAG whichAcl, CFArrayRef appArray,
bool requirePassphrase)
{
OSStatus ortn;
CFArrayRef aclList = NULL;
ortn = SecAccessCopySelectedACLList(accessRef, whichAcl, &aclList);
if(ortn) {
cssmPerror("SecAccessCopySelectedACLList", ortn);
return ortn;
}
if(CFArrayGetCount(aclList) != 1) {
printf("StickyRecord::updateAcl - unexpected ACL list count (%d)",
(int)CFArrayGetCount(aclList));
return internalComponentErr;
}
SecACLRef acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
CFArrayRef applicationList = NULL;
CFStringRef description = NULL;
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector = {};
ortn = SecACLCopySimpleContents(acl, &applicationList, &description, &promptSelector);
if(ortn) {
cssmPerror("SecACLCopySimpleContents", ortn);
return ortn;
}
if(applicationList != NULL) {
CFRelease(applicationList);
}
if(requirePassphrase) {
promptSelector.flags |= CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
}
else {
promptSelector.flags &= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
}
ortn = SecACLSetSimpleContents(acl, appArray, description, &promptSelector);
if(description != NULL) {
CFRelease(description);
}
if(ortn) {
cssmPerror("SecACLSetSimpleContents", ortn);
}
if(aclList != NULL) {
CFRelease(aclList);
}
return ortn;
}
OSStatus stickyRecordUpdateAcl(
SecAccessRef accessRef)
{
OSStatus ortn;
printf("...updating ACL to simulate a StickyRecord\n");
ortn = srUpdateAcl(accessRef, CSSM_ACL_AUTHORIZATION_DECRYPT, NULL, false);
if(ortn) {
return ortn;
}
CFArrayRef nullArray = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
return srUpdateAcl(accessRef, CSSM_ACL_AUTHORIZATION_ENCRYPT, nullArray, true);
}