#include <stdlib.h>
#include <strings.h>
#include <stdio.h>
#include <unistd.h>
#include <Security/Security.h>
#include "aclUtils.h"
static void usage(char **argv)
{
printf("usage: %s op [options]\n", argv[0]);
printf("op:\n");
printf(" d -- display ACL\n");
printf(" a -- add ACL\n");
printf(" l -- lookup, dump label; no ACL operation\n");
printf(" m -- modify data (only allowed for password items; must specify -p)\n");
printf("Options:\n");
printf(" -k keychain\n");
printf(" -t itemType : k=privateKey, b=publicKey s=sessionKey, p=password; default is sessionKey\n");
printf(" -l label_or_printName\n");
printf(" -p new_password_data\n");
printf(" -d -- dump data\n");
printf(" -e -- edit ACL entries\n");
printf(" -s -- simulate StickyRecord ACL\n");
exit(1);
}
static OSStatus printItemLabelAndData(
SecKeychainItemRef itemRef,
SecItemAttr labelAttr,
bool dumpData)
{
SecKeychainAttributeList attrList;
SecKeychainAttribute attr;
UInt32 length = 0;
void *outData = NULL;
attr.tag = labelAttr;
attr.length = 0;
attr.data = NULL;
attrList.count = 1;
attrList.attr = &attr;
OSStatus ortn = SecKeychainItemCopyContent(itemRef,
NULL, &attrList, dumpData ? &length : 0,
dumpData ? &outData : NULL);
if(ortn) {
cssmPerror("SecKeychainItemCopyContent", ortn);
printf("***Error fetching label %s\n", dumpData ? "and data" : "");
return ortn;
}
if(attr.data == NULL) {
printf("**No label attribute found\n");
}
else {
printf("Label: ");
print_buffer(stdout, attr.length, attr.data);
printf("\n");
}
if(dumpData) {
if(outData == NULL) {
printf("***Asked for data but none found\n");
}
else {
printf("Data : ");
print_buffer(stdout, length, outData);
printf("\n");
}
}
SecKeychainItemFreeContent(&attrList, outData);
return noErr;
}
static OSStatus dumpAcls(
SecKeychainRef kcRef,
SecItemClass itemClass,
SecItemAttr labelAttr, const char *label,
bool dumpData,
bool dumpAcl,
bool editAcl,
bool simulateStickyRecord,
const unsigned char *newData, unsigned newDataLen)
{
OSStatus ortn;
SecKeychainSearchRef srchRef;
SecKeychainAttributeList attrList;
SecKeychainAttributeList *attrListP = NULL;
SecKeychainAttribute attr;
unsigned numFound = 0;
if(label) {
attr.tag = labelAttr;
attr.length = strlen(label);
attr.data = (void *)label;
attrList.count = 1;
attrList.attr = &attr;
attrListP = &attrList;
}
ortn = SecKeychainSearchCreateFromAttributes(kcRef,
itemClass,
attrListP,
&srchRef);
if(ortn) {
cssmPerror("SecKeychainSearchCreateFromAttributes", ortn);
return ortn;
}
for(;;) {
SecKeychainItemRef itemRef;
ortn = SecKeychainSearchCopyNext(srchRef, &itemRef);
if(ortn) {
if(ortn == errSecItemNotFound) {
ortn = noErr;
}
else {
cssmPerror("SecKeychainSearchCopyNext", ortn);
}
break;
}
printf("Item %u:\n", numFound++);
printItemLabelAndData(itemRef, labelAttr, dumpData);
if(newData) {
ortn = SecKeychainItemModifyAttributesAndData(itemRef,
NULL, newDataLen,
newData);
if(ortn) {
cssmPerror("SecKeychainItemModifyAttributesAndData", ortn);
printf("***Cannot modify data of this item***\n");
goto endOfLoop;
}
}
if(dumpAcl) {
SecAccessRef accessRef = nil;
ortn = SecKeychainItemCopyAccess(itemRef, &accessRef);
if(ortn) {
cssmPerror("SecKeychainItemCopyAccess", ortn);
printf("***No SecAccessRef found***\n");
goto endOfLoop;
}
print_access(stdout, accessRef, editAcl);
if(simulateStickyRecord) {
ortn = stickyRecordUpdateAcl(accessRef);
if(ortn) {
goto endOfLoop;
}
}
if(editAcl || simulateStickyRecord) {
ortn = SecKeychainItemSetAccess(itemRef, accessRef);
if(ortn) {
cssmPerror("SecKeychainItemSetAccess", ortn);
}
}
}
endOfLoop:
CFRelease(itemRef);
if(ortn) {
break;
}
}
CFRelease(srchRef);
printf("...%u items found\n", numFound);
return ortn;
}
typedef enum {
AO_Dump,
AO_Add,
AO_Lookup,
AO_ModifyPassword
} AclOp;
int main(int argc, char **argv)
{
const char *kcName = NULL;
const char *labelOrName = NULL; AclOp op = AO_Dump;
SecItemClass itemClass = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
SecItemAttr labelAttr = kSecLabelItemAttr;
bool dumpData = false;
bool editAcl = false;
bool dumpAcl = true;
bool simulateStickyRecord = false;
const char *newPassword = NULL;
unsigned newPasswordLen = 0;
SecKeychainRef kcRef = nil;
OSStatus ortn;
if(argc < 2) {
usage(argv);
}
switch(argv[1][0]) {
case 'd':
op = AO_Dump;
break;
case 'a':
op = AO_Add;
break;
case 'l':
op = AO_Lookup;
dumpAcl = false;
break;
case 'm':
op = AO_ModifyPassword;
dumpAcl = false;
break;
default:
usage(argv);
}
extern char *optarg;
int arg;
extern int optind;
optind = 2;
while ((arg = getopt(argc, argv, "k:t:l:dep:sh")) != -1) {
switch (arg) {
case 'k':
kcName = optarg;
break;
case 't':
switch(optarg[0]) {
case 'k':
itemClass = CSSM_DL_DB_RECORD_PRIVATE_KEY;
break;
case 's':
itemClass = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
break;
case 'b':
itemClass = CSSM_DL_DB_RECORD_PUBLIC_KEY;
break;
case 'p':
itemClass = kSecGenericPasswordItemClass;
labelAttr = kSecLabelItemAttr;
break;
default:
usage(argv);
}
break;
case 'l':
labelOrName = optarg;
break;
case 'd':
dumpData = true;
break;
case 'e':
editAcl = true;
break;
case 'p':
newPassword = optarg;
newPasswordLen = strlen(newPassword);
break;
case 's':
simulateStickyRecord = true;
break;
case 'h':
usage(argv);
}
}
if(optind != argc) {
usage(argv);
}
if(op == AO_ModifyPassword) {
if(itemClass != kSecGenericPasswordItemClass) {
printf("***You can only modify data on a password item.\n");
exit(1);
}
if(newPassword == NULL) {
printf("***You must supply new password data for this operation.\n");
exit(1);
}
}
if(kcName) {
ortn = SecKeychainOpen(kcName, &kcRef);
if(ortn) {
cssmPerror("SecKeychainOpen", ortn);
printf("***Error opening keychain %s. Aborting.\n", kcName);
exit(1);
}
}
switch(op) {
case AO_Dump:
case AO_Lookup:
case AO_ModifyPassword:
ortn = dumpAcls(kcRef, itemClass, labelAttr, labelOrName, dumpData, dumpAcl, editAcl,
simulateStickyRecord, (unsigned char *)newPassword, newPasswordLen);
break;
case AO_Add:
printf("Add ACL op to be implemented real soon now\n");
ortn = -1;
break;
}
if(kcRef) {
CFRelease(kcRef);
}
return (int)ortn;
}