#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <TargetConditionals.h>
#include <CoreFoundation/CFString.h>
#include <CoreFoundation/CFNumber.h>
#include "symbol_scope.h"
#include "EAPLog.h"
#include "EAPSecurity.h"
#include "EAPKeychainUtil.h"
#include "EAPKeychainUtilInternal.h"
#include "myCFUtil.h"
#if TARGET_OS_EMBEDDED
OSStatus
EAPSecKeychainPasswordItemRemove(SecKeychainRef keychain,
CFStringRef unique_id_str)
{
const void * keys[] = {
kSecClass,
kSecAttrService
};
CFDictionaryRef query;
OSStatus status;
const void * values[] = {
kSecClassGenericPassword,
unique_id_str
};
query = CFDictionaryCreate(NULL, keys, values,
sizeof(keys) / sizeof(*keys),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
status = SecItemDelete(query);
CFRelease(query);
if (status != noErr) {
EAPLOG_FL(LOG_NOTICE, "SecItemDelete failed: %s (%d)",
EAPSecurityErrorString(status), (int)status);
}
return (status);
}
OSStatus
EAPSecKeychainPasswordItemCopy(SecKeychainRef keychain,
CFStringRef unique_id_str,
CFDataRef * ret_password)
{
const void * keys[] = {
kSecClass,
kSecAttrService,
kSecReturnData
};
CFDictionaryRef query;
CFTypeRef results;
OSStatus status;
const void * values[] = {
kSecClassGenericPassword,
unique_id_str,
kCFBooleanTrue
};
query = CFDictionaryCreate(NULL, keys, values,
sizeof(keys) / sizeof(*keys),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
status = SecItemCopyMatching(query, &results);
CFRelease(query);
if (status == noErr) {
*ret_password = results;
}
else {
*ret_password = NULL;
}
return (status);
}
OSStatus
EAPSecKeychainPasswordItemCreateWithAccess(SecKeychainRef keychain,
SecAccessRef access,
CFStringRef unique_id_str,
CFDataRef label,
CFDataRef description,
CFDataRef user,
CFDataRef password)
{
CFMutableDictionaryRef attrs;
OSStatus status;
attrs = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(attrs, kSecClass, kSecClassGenericPassword);
CFDictionarySetValue(attrs, kSecAttrService, unique_id_str);
CFDictionarySetValue(attrs, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock);
if (label != NULL) {
CFDictionarySetValue(attrs, kSecAttrLabel, label);
}
if (description != NULL) {
CFDictionarySetValue(attrs, kSecAttrDescription, description);
}
if (user != NULL) {
CFDictionarySetValue(attrs, kSecAttrAccount, user);
}
CFDictionarySetValue(attrs, kSecValueData, password);
status = SecItemAdd(attrs, NULL);
CFRelease(attrs);
return (status);
}
OSStatus
EAPSecKeychainPasswordItemSet(SecKeychainRef keychain,
CFStringRef unique_id_str,
CFDataRef password)
{
const void * keys[] = {
kSecClass,
kSecAttrService,
kSecReturnData
};
CFTypeRef existing_password = NULL;
CFDictionaryRef query;
CFDictionaryRef pass_dict;
OSStatus status;
const void * values[] = {
kSecClassGenericPassword,
unique_id_str,
kCFBooleanTrue
};
query = CFDictionaryCreate(NULL, keys, values,
sizeof(keys) / sizeof(*keys),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
status = SecItemCopyMatching(query, &existing_password);
CFRelease(query);
if (status != noErr) {
goto done;
}
if (existing_password != NULL
&& CFEqual(password, existing_password)) {
goto done;
}
query = CFDictionaryCreate(NULL, keys, values,
(sizeof(keys) / sizeof(*keys)) - 1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
pass_dict = CFDictionaryCreate(NULL,
(const void * *)&kSecValueData,
(const void * *)&password,
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
status = SecItemUpdate(query, pass_dict);
CFRelease(query);
CFRelease(pass_dict);
done:
my_CFRelease(&existing_password);
return (status);
}
#else
#include <Security/SecAccess.h>
#include <Security/SecACL.h>
#include <Security/SecTrustedApplication.h>
#include <Security/SecTrustedApplicationPriv.h>
#include <Security/AuthorizationTags.h>
const CFStringRef kEAPSecKeychainPropPassword = CFSTR("Password");
const CFStringRef kEAPSecKeychainPropLabel = CFSTR("Label");
const CFStringRef kEAPSecKeychainPropDescription = CFSTR("Description");
const CFStringRef kEAPSecKeychainPropAccount = CFSTR("Account");
const CFStringRef kEAPSecKeychainPropTrustedApplications = CFSTR("TrustedApplications");
const CFStringRef kEAPSecKeychainPropAllowRootAccess = CFSTR("AllowRootAccess");
#include <Security/cssmtype.h>
#include <Security/cssmapple.h>
#include <Security/SecKeychain.h>
#include <Security/SecKeychainItem.h>
#define MY_KEYCHAIN_ATTR_MAX 6
typedef struct {
SecKeychainAttributeInfo info;
UInt32 tag[MY_KEYCHAIN_ATTR_MAX];
UInt32 format[MY_KEYCHAIN_ATTR_MAX];
} mySecKeychainAttributeInfo;
typedef struct {
SecKeychainAttributeList list;
SecKeychainAttribute attr[MY_KEYCHAIN_ATTR_MAX];
} mySecKeychainAttributeList;
typedef struct CFStringSecItemTag {
const CFStringRef * key;
UInt32 tag;
} CFStringSecItemTag;
STATIC const CFStringSecItemTag prop_tag_tbl[] = {
{ &kEAPSecKeychainPropAccount, kSecAccountItemAttr },
{ &kEAPSecKeychainPropLabel, kSecLabelItemAttr },
{ &kEAPSecKeychainPropDescription, kSecDescriptionItemAttr },
};
STATIC const int prop_tag_tbl_size = (sizeof(prop_tag_tbl)
/ sizeof(prop_tag_tbl[0]));
STATIC void
mySecKeychainAttributeInfoInit(mySecKeychainAttributeInfo * attr_info)
{
attr_info->info.count = 0;
attr_info->info.tag = attr_info->tag;
attr_info->info.format = attr_info->format;
return;
}
STATIC Boolean
mySecKeychainAttributeInfoAdd(mySecKeychainAttributeInfo * attr_info,
UInt32 tag)
{
int count = attr_info->info.count;
if (count >= MY_KEYCHAIN_ATTR_MAX) {
EAPLOG_FL(LOG_NOTICE, "Trying to add attribute %d but list is full",
(int)tag);
return (FALSE);
}
attr_info->format[count] = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
attr_info->tag[count] = tag;
attr_info->info.count++;
return (TRUE);
}
STATIC void
mySecKeychainAttributeListInit(mySecKeychainAttributeList * attr_list)
{
attr_list->list.count = 0;
attr_list->list.attr = attr_list->attr;
return;
}
STATIC Boolean
mySecKeychainAttributeListAdd(mySecKeychainAttributeList * attr_list,
UInt32 attr_tag, CFDataRef attr_data)
{
SecKeychainAttribute * attr;
int count = attr_list->list.count;
if (count >= MY_KEYCHAIN_ATTR_MAX) {
EAPLOG_FL(LOG_NOTICE, "Trying to add attribute %d but list is full",
(int)attr_tag);
return (FALSE);
}
attr = attr_list->attr + count;
attr->tag = attr_tag;
attr->length = CFDataGetLength(attr_data);
attr->data = (void *)CFDataGetBytePtr(attr_data);
attr_list->list.count++;
return (TRUE);
}
STATIC Boolean
mySecKeychainAttributeListAddFromDict(mySecKeychainAttributeList * attr_list,
CFDictionaryRef attrs)
{
int i;
Boolean ret = TRUE;
const CFStringSecItemTag * tbl;
for (i = 0, tbl = prop_tag_tbl; i < prop_tag_tbl_size; i++, tbl++) {
CFDataRef val = CFDictionaryGetValue(attrs, *tbl->key);
if (val != NULL) {
ret = mySecKeychainAttributeListAdd(attr_list, tbl->tag, val);
if (ret == FALSE) {
EAPLOG_FL(LOG_NOTICE, "mySecKeychainAttributeListAddFromDict() "
"failed to add %d", (int)tbl->tag);
break;
}
}
}
return (ret);
}
PRIVATE_EXTERN OSStatus
EAPSecAccessCreateWithTrustedApplications(CFArrayRef trusted_apps,
CFDataRef label_data,
SecAccessRef * ret_access)
{
CFStringRef label = NULL;
OSStatus status;
if (label_data != NULL) {
label = my_CFStringCreateWithData(label_data);
}
else {
label = CFSTR("--unspecified--");
CFRetain(label);
}
status = SecAccessCreate(label, trusted_apps, ret_access);
my_CFRelease(&label);
return (status);
}
PRIVATE_EXTERN OSStatus
EAPSecKeychainItemSetAccessForTrustedApplications(SecKeychainItemRef item,
CFArrayRef trusted_apps)
{
CFArrayRef app_list = NULL;
CFMutableArrayRef app_list_data = NULL;
SecACLRef acl;
CFArrayRef acl_list = NULL;
SecAccessRef access = NULL;
CFStringRef prompt_description = NULL;
SecKeychainPromptSelector prompt_selector;
OSStatus status;
status = SecKeychainItemCopyAccess(item, &access);
if (status != noErr) {
status = SecAccessCreate(CFSTR("--unspecified--"),
trusted_apps, &access);
if (status != noErr) {
goto done;
}
}
else {
acl_list
= SecAccessCopyMatchingACLList(access, kSecACLAuthorizationDecrypt);
if (acl_list == NULL) {
status = errSecAllocate;
goto done;
}
acl = (SecACLRef)CFArrayGetValueAtIndex(acl_list, 0);
status = SecACLCopyContents(acl, &app_list, &prompt_description,
&prompt_selector);
if (status == noErr && app_list != NULL) {
int count;
int i;
CFRange r;
CFMutableArrayRef new_list = NULL;
r.location = 0;
r.length = CFArrayGetCount(app_list);
app_list_data = CFArrayCreateMutable(NULL, r.length,
&kCFTypeArrayCallBacks);
for (i = 0; i < r.length; i++) {
SecTrustedApplicationRef app;
CFDataRef data = NULL;
app = (SecTrustedApplicationRef)
CFArrayGetValueAtIndex(app_list, i);
(void)SecTrustedApplicationCopyExternalRepresentation(app,
&data);
if (data != NULL) {
CFArrayAppendValue(app_list_data, data);
CFRelease(data);
}
}
r.length = CFArrayGetCount(app_list_data);
count = CFArrayGetCount(trusted_apps);
for (i = 0; i < count; i++) {
bool already_there;
SecTrustedApplicationRef app;
CFDataRef data = NULL;
app = (SecTrustedApplicationRef)
CFArrayGetValueAtIndex(trusted_apps, i);
(void)SecTrustedApplicationCopyExternalRepresentation(app,
&data);
if (data == NULL) {
continue;
}
already_there = CFArrayContainsValue(app_list_data, r, data);
CFRelease(data);
if (already_there) {
continue;
}
if (new_list == NULL) {
new_list = CFArrayCreateMutableCopy(NULL, 0, app_list);
}
CFArrayAppendValue(new_list, app);
}
if (new_list == NULL) {
goto done;
}
status = SecACLSetContents(acl, new_list, prompt_description,
prompt_selector);
CFRelease(new_list);
if (status != noErr) {
goto done;
}
}
else {
status = SecACLSetContents(acl, trusted_apps,
prompt_description,
prompt_selector);
if (status != noErr) {
goto done;
}
}
}
status = SecKeychainItemSetAccess(item, access);
done:
my_CFRelease(&access);
my_CFRelease(&app_list);
my_CFRelease(&app_list_data);
my_CFRelease(&prompt_description);
my_CFRelease(&acl_list);
return (status);
}
STATIC OSStatus
KeychainPasswordItemCopy(SecKeychainRef keychain,
CFStringRef unique_id_str,
SecKeychainItemRef * ret_item)
{
SecKeychainItemRef item;
OSStatus status;
CFDataRef unique_id;
unique_id = CFStringCreateExternalRepresentation(NULL,
unique_id_str,
kCFStringEncodingUTF8,
0);
status
= SecKeychainFindGenericPassword(keychain,
CFDataGetLength(unique_id),
(const char *)CFDataGetBytePtr(unique_id),
0,
NULL,
NULL,
NULL,
&item);
CFRelease(unique_id);
*ret_item = NULL;
if (status != noErr) {
#if TEST_EAPKEYCHAINUTIL
fprintf(stderr, "SecKeychainFindGenericPassword failed: %s (%d)\n",
EAPSecurityErrorString(status), (int)status);
#endif
}
else {
*ret_item = item;
}
return (status);
}
STATIC CFStringRef
SecKeychainAttrTypeGetCFString(SecKeychainAttrType type)
{
int i;
const CFStringSecItemTag * tbl;
for (i = 0, tbl = prop_tag_tbl; i < prop_tag_tbl_size; i++, tbl++) {
if (tbl->tag == type) {
return (*tbl->key);
}
}
return (NULL);
}
STATIC OSStatus
KeychainItemCopyInfo(SecKeychainItemRef item,
CFArrayRef keys,
CFDictionaryRef * ret_attrs)
{
CFMutableDictionaryRef attrs = NULL;
int i;
void * password_data = NULL;
UInt32 password_length = 0;
void * * password_data_p;
UInt32 * password_length_p;
CFRange range = CFRangeMake(0, CFArrayGetCount(keys));
mySecKeychainAttributeInfo req_attr_info;
SecKeychainAttributeInfo * req_attr_info_p;
SecKeychainAttributeList * ret_attr_list = NULL;
SecKeychainAttributeList * *ret_attr_list_p;
OSStatus status;
mySecKeychainAttributeInfoInit(&req_attr_info);
if (CFArrayContainsValue(keys, range, kEAPSecKeychainPropAccount)) {
mySecKeychainAttributeInfoAdd(&req_attr_info,
kSecAccountItemAttr);
}
if (CFArrayContainsValue(keys, range, kEAPSecKeychainPropLabel)) {
mySecKeychainAttributeInfoAdd(&req_attr_info,
kSecLabelItemAttr);
}
if (CFArrayContainsValue(keys, range, kEAPSecKeychainPropDescription)) {
mySecKeychainAttributeInfoAdd(&req_attr_info,
kSecDescriptionItemAttr);
}
if (CFArrayContainsValue(keys, range, kEAPSecKeychainPropPassword)) {
password_data_p = &password_data;
password_length_p = &password_length;
}
else {
password_data_p = NULL;
password_length_p = NULL;
}
if (req_attr_info.info.count != 0) {
req_attr_info_p = &req_attr_info.info;
ret_attr_list_p = &ret_attr_list;
}
else {
req_attr_info_p = NULL;
ret_attr_list_p = NULL;
}
status = SecKeychainItemCopyAttributesAndData(item,
req_attr_info_p,
NULL,
ret_attr_list_p,
password_length_p,
password_data_p);
if (status != noErr) {
goto done;
}
attrs = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (password_data != NULL && password_length != 0) {
CFDataRef password;
password = CFDataCreate(NULL, password_data, password_length);
CFDictionarySetValue(attrs, kEAPSecKeychainPropPassword, password);
CFRelease(password);
}
if (ret_attr_list != NULL) {
SecKeychainAttribute * attr = ret_attr_list->attr;
for (i = 0; i < ret_attr_list->count; i++, attr++) {
CFStringRef key;
CFDataRef val;
if (attr->data == NULL || attr->length == 0) {
continue;
}
key = SecKeychainAttrTypeGetCFString(attr->tag);
if (key == NULL) {
continue;
}
val = CFDataCreate(NULL, attr->data, attr->length);
CFDictionarySetValue(attrs, key, val);
CFRelease(val);
}
}
SecKeychainItemFreeAttributesAndData(ret_attr_list, password_data);
done:
*ret_attrs = attrs;
return (status);
}
OSStatus
EAPSecKeychainPasswordItemRemove(SecKeychainRef keychain,
CFStringRef unique_id_str)
{
SecKeychainItemRef item;
OSStatus status;
status = KeychainPasswordItemCopy(keychain, unique_id_str, &item);
if (status != noErr) {
goto done;
}
status = SecKeychainItemDelete(item);
CFRelease(item);
if (status != noErr) {
EAPLOG_FL(LOG_NOTICE, "SecKeychainItemDelete() failed: %s (%d)",
EAPSecurityErrorString(status), (int)status);
}
done:
return (status);
}
OSStatus
EAPSecKeychainPasswordItemCopy2(SecKeychainRef keychain,
CFStringRef unique_id_str,
CFArrayRef keys,
CFDictionaryRef * ret_values)
{
SecKeychainItemRef item = NULL;
OSStatus status;
*ret_values = NULL;
status = KeychainPasswordItemCopy(keychain, unique_id_str, &item);
if (status == noErr) {
status = KeychainItemCopyInfo(item, keys, ret_values);
}
if (item != NULL) {
CFRelease(item);
}
return (status);
}
OSStatus
EAPSecKeychainPasswordItemCopy(SecKeychainRef keychain,
CFStringRef unique_id_str,
CFDataRef * ret_password)
{
CFDataRef password;
CFDictionaryRef props;
CFArrayRef req_props;
OSStatus status;
*ret_password = NULL;
req_props = CFArrayCreate(NULL,
(const void * *)&kEAPSecKeychainPropPassword, 1,
&kCFTypeArrayCallBacks);
status = EAPSecKeychainPasswordItemCopy2(keychain,
unique_id_str,
req_props,
&props);
CFRelease(req_props);
if (status != noErr) {
return (status);
}
password = CFDictionaryGetValue(props, kEAPSecKeychainPropPassword);
if (password == NULL) {
status = errSecItemNotFound;
}
else {
*ret_password = CFRetain(password);
}
CFRelease(props);
return (status);
}
OSStatus
EAPSecKeychainPasswordItemCreateWithAccess(SecKeychainRef keychain,
SecAccessRef access,
CFStringRef unique_id_str,
CFDataRef label,
CFDataRef description,
CFDataRef user,
CFDataRef password)
{
mySecKeychainAttributeList attr_list;
OSStatus status;
CFDataRef unique_id;
unique_id = CFStringCreateExternalRepresentation(NULL,
unique_id_str,
kCFStringEncodingUTF8,
0);
mySecKeychainAttributeListInit(&attr_list);
mySecKeychainAttributeListAdd(&attr_list, kSecServiceItemAttr, unique_id);
if (label != NULL) {
mySecKeychainAttributeListAdd(&attr_list, kSecLabelItemAttr, label);
}
if (description != NULL) {
mySecKeychainAttributeListAdd(&attr_list, kSecDescriptionItemAttr,
description);
}
if (user != NULL) {
mySecKeychainAttributeListAdd(&attr_list, kSecAccountItemAttr, user);
}
status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass,
&attr_list.list,
CFDataGetLength(password),
CFDataGetBytePtr(password),
keychain,
access,
NULL);
CFRelease(unique_id);
return (status);
}
OSStatus
EAPSecKeychainPasswordItemCreate(SecKeychainRef keychain,
CFStringRef unique_id_str,
CFDictionaryRef attrs)
{
CFBooleanRef allow_root;
SecAccessRef access = NULL;
mySecKeychainAttributeList attr_list;
CFDataRef password;
void * password_data;
UInt32 password_length;
OSStatus status;
CFArrayRef trusted_apps;
CFDataRef unique_id = NULL;
password = CFDictionaryGetValue(attrs, kEAPSecKeychainPropPassword);
if (password != NULL) {
password_length = CFDataGetLength(password);
password_data = (void *)CFDataGetBytePtr(password);
}
else {
password_length = 0;
password_data = NULL;
}
trusted_apps = CFDictionaryGetValue(attrs,
kEAPSecKeychainPropTrustedApplications);
allow_root = CFDictionaryGetValue(attrs,
kEAPSecKeychainPropAllowRootAccess);
if (trusted_apps != NULL) {
CFDataRef label_data;
label_data = CFDictionaryGetValue(attrs,
kEAPSecKeychainPropLabel);
status = EAPSecAccessCreateWithTrustedApplications(trusted_apps,
label_data,
&access);
if (status != noErr) {
EAPLOG_FL(LOG_NOTICE,
"failed to get SecAccess for Trusted Apps, %d",
(int)status);
goto done;
}
}
else if (allow_root != NULL && CFBooleanGetValue(allow_root)) {
CFErrorRef error;
access = SecAccessCreateWithOwnerAndACL(0, 0, kSecUseOnlyUID,
NULL, &error);
if (access == NULL) {
status = errSecAllocate;
if (error != NULL) {
EAPLOG_FL(LOG_NOTICE,
"SecAccessCreateWithOwnerAndACL() failed %d",
(int)CFErrorGetCode(error));
CFRelease(error);
}
goto done;
}
}
mySecKeychainAttributeListInit(&attr_list);
unique_id = CFStringCreateExternalRepresentation(NULL,
unique_id_str,
kCFStringEncodingUTF8,
0);
mySecKeychainAttributeListAdd(&attr_list, kSecServiceItemAttr, unique_id);
if (mySecKeychainAttributeListAddFromDict(&attr_list, attrs) == FALSE) {
status = errSecBufferTooSmall;
}
else {
status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass,
&attr_list.list,
password_length,
password_data,
keychain,
access,
NULL);
}
done:
my_CFRelease(&unique_id);
my_CFRelease(&access);
return (status);
}
OSStatus
EAPSecKeychainPasswordItemCreateUnique(SecKeychainRef keychain,
CFDictionaryRef attrs,
CFStringRef * ret_unique_id)
{
OSStatus status;
CFStringRef unique_id_str;
unique_id_str = my_CFUUIDStringCreate(NULL);
status = EAPSecKeychainPasswordItemCreate(keychain,
unique_id_str,
attrs);
if (status == noErr && ret_unique_id != NULL) {
*ret_unique_id = unique_id_str;
}
else {
if (ret_unique_id != NULL) {
*ret_unique_id = NULL;
}
CFRelease(unique_id_str);
}
return (status);
}
OSStatus
EAPSecKeychainPasswordItemSet(SecKeychainRef keychain,
CFStringRef unique_id_str,
CFDataRef password)
{
SecKeychainItemRef item;
OSStatus status;
status = KeychainPasswordItemCopy(keychain, unique_id_str, &item);
if (status != noErr) {
return (status);
}
status = SecKeychainItemModifyAttributesAndData(item,
NULL,
CFDataGetLength(password),
CFDataGetBytePtr(password));
CFRelease(item);
return (status);
}
OSStatus
EAPSecKeychainPasswordItemSet2(SecKeychainRef keychain,
CFStringRef unique_id_str,
CFDictionaryRef attrs)
{
mySecKeychainAttributeList attr_list;
SecKeychainItemRef item;
CFDataRef password;
void * password_data;
UInt32 password_length;
OSStatus status;
status = KeychainPasswordItemCopy(keychain, unique_id_str, &item);
if (status != noErr) {
return (status);
}
mySecKeychainAttributeListInit(&attr_list);
if (mySecKeychainAttributeListAddFromDict(&attr_list, attrs) == FALSE) {
status = errSecBufferTooSmall;
goto done;
}
password = CFDictionaryGetValue(attrs, kEAPSecKeychainPropPassword);
if (password != NULL) {
password_length = CFDataGetLength(password);
password_data = (void *)CFDataGetBytePtr(password);
}
else {
password_length = 0;
password_data = NULL;
}
status = SecKeychainItemModifyAttributesAndData(item,
&attr_list.list,
password_length,
password_data);
done:
CFRelease(item);
return (status);
}
#endif
OSStatus
EAPSecKeychainPasswordItemCreateUniqueWithAccess(SecKeychainRef keychain,
SecAccessRef access,
CFDataRef label,
CFDataRef description,
CFDataRef user,
CFDataRef password,
CFStringRef * ret_unique_id)
{
OSStatus status;
CFStringRef unique_id_str;
unique_id_str = my_CFUUIDStringCreate(NULL);
status = EAPSecKeychainPasswordItemCreateWithAccess(keychain,
access,
unique_id_str,
label,
description,
user,
password);
if (status == noErr && ret_unique_id != NULL) {
*ret_unique_id = unique_id_str;
}
else {
if (ret_unique_id != NULL) {
*ret_unique_id = NULL;
}
CFRelease(unique_id_str);
}
return (status);
}
#ifdef TEST_EAPKEYCHAINUTIL
#if ! TARGET_OS_EMBEDDED
static OSStatus
SecKeychainCopySystemKeychain(SecKeychainRef * ret_keychain)
{
SecKeychainRef keychain = NULL;
OSStatus status;
status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem,
&keychain);
if (status != noErr && keychain != NULL) {
CFRelease(keychain);
keychain = NULL;
}
*ret_keychain = keychain;
return (status);
}
#endif
#if TARGET_OS_EMBEDDED
#define SYS_OPT " "
#else
#define SYS_OPT " [system] "
#define HAS_KEYCHAINS
#endif
static void
usage(const char * progname)
{
fprintf(stderr, "%s" SYS_OPT
"create <label> <description> <username> <password>\n",
progname);
fprintf(stderr,
"%s" SYS_OPT "set <unique_id> <username> <password>\n",
progname);
fprintf(stderr, "%s" SYS_OPT "remove <unique_id>\n", progname);
fprintf(stderr, "%s" SYS_OPT "get <unique_id>\n", progname);
exit(1);
}
typedef enum {
kCommandUnknown,
kCommandCreate,
kCommandRemove,
kCommandSet,
kCommandGet
} Command;
#define keapolclientPath "/System/Library/SystemConfiguration/EAPOLController.bundle/Contents/Resources/eapolclient"
#define kAirPortApplicationGroup "AirPort"
#define kSystemUIServerPath "/System/Library/CoreServices/SystemUIServer.app"
STATIC CFArrayRef
copy_trusted_applications(void)
{
CFMutableArrayRef array;
SecTrustedApplicationRef trusted_app;
OSStatus status;
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
status = SecTrustedApplicationCreateFromPath(NULL, &trusted_app);
if (status != noErr) {
fprintf(stderr,
"SecTrustedApplicationCreateFromPath(NULL) failed, %d\n",
status);
}
else {
CFArrayAppendValue(array, trusted_app);
CFRelease(trusted_app);
}
status = SecTrustedApplicationCreateFromPath(keapolclientPath,
&trusted_app);
if (status != noErr) {
fprintf(stderr,
"SecTrustedApplicationCreateFromPath(%s) failed, %d\n",
keapolclientPath,
status);
}
else {
CFArrayAppendValue(array, trusted_app);
CFRelease(trusted_app);
}
status = SecTrustedApplicationCreateFromPath(kSystemUIServerPath,
&trusted_app);
if (status != noErr) {
fprintf(stderr,
"SecTrustedApplicationCreateFromPath(%s) failed, %d\n",
kSystemUIServerPath,
status);
}
else {
CFArrayAppendValue(array, trusted_app);
CFRelease(trusted_app);
}
status
= SecTrustedApplicationCreateApplicationGroup(kAirPortApplicationGroup,
NULL, &trusted_app);
if (status != noErr) {
fprintf(stderr,
"SecTrustedApplicationCreateApplicationGroup("
kAirPortApplicationGroup ") failed, %d\n",
status);
}
else {
CFArrayAppendValue(array, trusted_app);
CFRelease(trusted_app);
}
if (CFArrayGetCount(array) == 0) {
my_CFRelease(&array);
}
return (array);
}
int
main(int argc, const char *argv[])
{
Command cmd = kCommandUnknown;
SecKeychainRef keychain = NULL;
const char * progname = argv[0];
OSStatus status;
#ifdef HAS_KEYCHAINS
bool use_system = FALSE;
#endif
if (argc < 2) {
usage(progname);
}
#ifdef HAS_KEYCHAINS
if (strcmp(argv[1], "system") == 0) {
if (argc < 3) {
usage(progname);
}
use_system = TRUE;
status = SecKeychainCopySystemKeychain(&keychain);
if (status != noErr) {
fprintf(stderr, "SecKeychainCopySystemKeychain failed, %s (%d)\n",
EAPSecurityErrorString(status), (int)status);
exit(1);
}
argc--;
argv++;
}
#endif
if (strcmp(argv[1], "create") == 0) {
if (argc < 6) {
usage(progname);
}
cmd = kCommandCreate;
}
else if (strcmp(argv[1], "set") == 0) {
if (argc < 5) {
usage(progname);
}
cmd = kCommandSet;
}
else if (strcmp(argv[1], "get") == 0) {
if (argc < 3) {
usage(progname);
}
cmd = kCommandGet;
}
else if (strcmp(argv[1], "remove") == 0) {
if (argc < 3) {
usage(progname);
}
cmd = kCommandRemove;
}
else {
usage(progname);
}
switch (cmd) {
case kCommandSet: {
CFMutableDictionaryRef attrs = NULL;
CFDataRef password;
CFArrayRef trusted_apps;
CFStringRef unique_id_str;
CFDataRef username;
unique_id_str
= CFStringCreateWithCStringNoCopy(NULL,
argv[2],
kCFStringEncodingUTF8,
kCFAllocatorNull);
username
= CFDataCreateWithBytesNoCopy(NULL,
(const UInt8 *)argv[3],
strlen(argv[3]),
kCFAllocatorNull);
password
= CFDataCreateWithBytesNoCopy(NULL,
(const UInt8 *)argv[4],
strlen(argv[4]),
kCFAllocatorNull);
attrs = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(attrs, kEAPSecKeychainPropAccount,
username);
CFDictionarySetValue(attrs, kEAPSecKeychainPropPassword,
password);
trusted_apps = copy_trusted_applications();
CFDictionarySetValue(attrs, kEAPSecKeychainPropTrustedApplications,
trusted_apps);
CFRelease(trusted_apps);
status = EAPSecKeychainPasswordItemSet2(keychain,
unique_id_str,
attrs);
if (status != noErr) {
fprintf(stderr, "EAPSecKeychainItemSet2 failed %s (%d)\n",
EAPSecurityErrorString(status), (int)status);
exit(2);
}
my_CFRelease(&password);
break;
}
case kCommandCreate: {
SecAccessRef access = NULL;
CFMutableDictionaryRef attrs = NULL;
CFDataRef data;
CFArrayRef trusted_apps;
CFDataRef unique_id;
CFStringRef unique_id_str = NULL;
#ifdef HAS_KEYCHAINS
if (use_system) {
CFErrorRef error;
access = SecAccessCreateWithOwnerAndACL(0, 0, kSecUseOnlyUID,
NULL, &error);
if (access == NULL) {
if (error != NULL) {
fprintf(stderr,
"SecAccessCreateWithOwnerAndACL() failed %d\n",
(int)CFErrorGetCode(error));
}
exit(2);
}
}
else {
status = SecAccessCreate(CFSTR("keychain"), NULL, &access);
if (status != noErr) {
fprintf(stderr, "SecAccessCreate failed, %s (%d)\n",
EAPSecurityErrorString(status), (int)status);
exit(2);
}
}
#endif
attrs = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
data = CFDataCreateWithBytesNoCopy(NULL,
(const UInt8 *)argv[2],
strlen(argv[2]),
kCFAllocatorNull);
CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, data);
CFRelease(data);
data = CFDataCreateWithBytesNoCopy(NULL,
(const UInt8 *)argv[3],
strlen(argv[3]),
kCFAllocatorNull);
CFDictionarySetValue(attrs, kEAPSecKeychainPropDescription,
data);
CFRelease(data);
data = CFDataCreateWithBytesNoCopy(NULL,
(const UInt8 *)argv[4],
strlen(argv[4]),
kCFAllocatorNull);
CFDictionarySetValue(attrs, kEAPSecKeychainPropAccount,
data);
CFRelease(data);
data = CFDataCreateWithBytesNoCopy(NULL,
(const UInt8 *)argv[5],
strlen(argv[5]),
kCFAllocatorNull);
CFDictionarySetValue(attrs, kEAPSecKeychainPropPassword,
data);
CFRelease(data);
trusted_apps = copy_trusted_applications();
CFDictionarySetValue(attrs, kEAPSecKeychainPropTrustedApplications,
trusted_apps);
CFRelease(trusted_apps);
if (argc > 6) {
unique_id_str
= CFStringCreateWithCStringNoCopy(NULL,
argv[6],
kCFStringEncodingUTF8,
kCFAllocatorNull);
status
= EAPSecKeychainPasswordItemCreate(keychain,
unique_id_str,
attrs);
if (status != noErr) {
fprintf(stderr, "EAPSecKeychainItemCreate failed,"
" %s (%d)\n",
EAPSecurityErrorString(status), (int)status);
exit(1);
}
}
else {
status
= EAPSecKeychainPasswordItemCreateUnique(keychain,
attrs,
&unique_id_str);
if (status != noErr) {
fprintf(stderr,
"EAPSecKeychainItemCreateUniqueWithAccessfailed,"
" %s (%d)\n",
EAPSecurityErrorString(status), (int)status);
exit(1);
}
}
unique_id
= CFStringCreateExternalRepresentation(NULL,
unique_id_str,
kCFStringEncodingUTF8,
0);
fwrite(CFDataGetBytePtr(unique_id),
CFDataGetLength(unique_id), 1, stdout);
printf("\n");
CFRelease(attrs);
break;
}
case kCommandGet:
case kCommandRemove: {
CFStringRef unique_id_str;
unique_id_str
= CFStringCreateWithCStringNoCopy(NULL,
argv[2],
kCFStringEncodingUTF8,
kCFAllocatorNull);
if (cmd == kCommandRemove) {
status
= EAPSecKeychainPasswordItemRemove(keychain, unique_id_str);
if (status != noErr) {
fprintf(stderr,
"EAPSecKeychainItemRemove failed, %s (%d)\n",
EAPSecurityErrorString(status), (int)status);
exit(2);
}
}
else {
CFDictionaryRef attrs;
const void * keys[] = {
kEAPSecKeychainPropPassword,
kEAPSecKeychainPropAccount,
kEAPSecKeychainPropLabel,
kEAPSecKeychainPropDescription
};
int keys_count = sizeof(keys) / sizeof(keys[0]);
CFDataRef password = NULL;
CFArrayRef req_props;
OSStatus status;
CFDataRef username = NULL;
req_props = CFArrayCreate(NULL,
keys, keys_count,
&kCFTypeArrayCallBacks);
status = EAPSecKeychainPasswordItemCopy2(keychain,
unique_id_str,
req_props,
&attrs);
CFRelease(req_props);
if (status != noErr) {
fprintf(stderr,
"EAPSecKeychainPasswordItemCopy2 failed, %s (%d)\n",
EAPSecurityErrorString(status), (int)status);
exit(2);
}
CFShow(attrs);
password = CFDictionaryGetValue(attrs,
kEAPSecKeychainPropPassword);
username = CFDictionaryGetValue(attrs,
kEAPSecKeychainPropAccount);
if (password != NULL) {
printf("Password = '");
fwrite(CFDataGetBytePtr(password),
CFDataGetLength(password), 1, stdout);
printf("'\n");
}
if (username != NULL) {
printf("Name = '");
fwrite(CFDataGetBytePtr(username),
CFDataGetLength(username), 1, stdout);
printf("'\n");
}
CFRelease(attrs);
}
CFRelease(unique_id_str);
}
default:
break;
}
if (keychain != NULL) {
CFRelease(keychain);
}
exit(0);
return (0);
}
#endif