#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFRuntime.h>
#include <CoreFoundation/CFXPCBridge.h>
#include <xpc/xpc.h>
#include "common.h"
#define HEIMCRED_CONST(_t,_c) \
const _t _c = (_t)CFSTR(#_c); \
const char *_c##xpc = #_c
#include "heimcred-const.h"
HEIMCRED_CONST(CFTypeRef, kHEIMTargetName);
#undef HEIMCRED_CONST
HeimCredContext HeimCredCTX;
CFUUIDRef
HeimCredCopyUUID(xpc_object_t object, const char *key)
{
CFUUIDBytes bytes;
const void *data = xpc_dictionary_get_uuid(object, key);
if (data == NULL)
return NULL;
memcpy(&bytes, data, sizeof(bytes));
return CFUUIDCreateFromUUIDBytes(NULL, bytes);
}
CFTypeRef
HeimCredMessageCopyAttributes(xpc_object_t object, const char *key, CFTypeID type)
{
xpc_object_t xpcattrs = xpc_dictionary_get_value(object, key);
CFTypeRef item;
if (xpcattrs == NULL)
return NULL;
item = _CFXPCCreateCFObjectFromXPCObject(xpcattrs);
if (item && CFGetTypeID(item) != type) {
CFRelease(item);
item = NULL;
}
return item;
}
void
HeimCredMessageSetAttributes(xpc_object_t object, const char *key, CFTypeRef attrs)
{
xpc_object_t xpcattrs = _CFXPCCreateXPCObjectFromCFObject(attrs);
if (xpcattrs == NULL)
return;
xpc_dictionary_set_value(object, key, xpcattrs);
xpc_release(xpcattrs);
}
void
HeimCredSetUUID(xpc_object_t object, const char *key, CFUUIDRef uuid)
{
CFUUIDBytes bytes = CFUUIDGetUUIDBytes(uuid);
uuid_t u;
memcpy(&u, &bytes, sizeof(u));
xpc_dictionary_set_uuid(object, key, u);
}
static CFStringRef
HeimCredCopyFormatString(CFTypeRef cf, CFDictionaryRef formatOptions)
{
return CFSTR("format");
}
static CFStringRef
HeimCredCopyDebugName(CFTypeRef cf)
{
HeimCredRef cred = (HeimCredRef)cf;
if (cred->attributes) {
CFTypeRef client = CFDictionaryGetValue(cred->attributes, kHEIMAttrClientName);
CFTypeRef server = CFDictionaryGetValue(cred->attributes, kHEIMAttrServerName);
CFTypeRef parent = CFDictionaryGetValue(cred->attributes, kHEIMAttrParentCredential);
CFTypeRef group = CFDictionaryGetValue(cred->attributes, kHEIMAttrLeadCredential);
CFTypeRef uid = CFDictionaryGetValue(cred->attributes, kHEIMAttrUserID);
int lead = group ? CFBooleanGetValue(group) : false;
CFTypeRef acl = CFDictionaryGetValue(cred->attributes, kHEIMAttrBundleIdentifierACL);
return CFStringCreateWithFormat(NULL, NULL, CFSTR("HeimCred<%@ group: %@ parent: %@ client: %@ server: %@ lead: %s ACL: %@, UID: %@>"),
cred->uuid, group, parent, client, server, lead ? "yes" : "no", acl ? acl : CFSTR(""), uid);
} else {
return CFStringCreateWithFormat(NULL, NULL, CFSTR("HeimCred<%@>"), cred->uuid);
}
}
static void
HeimCredReleaseItem(CFTypeRef item)
{
HeimCredRef cred = (HeimCredRef)item;
CFRELEASE_NULL(cred->uuid);
CFRELEASE_NULL(cred->attributes);
}
void
_HeimCredInitCommon(void)
{
static dispatch_once_t once;
dispatch_once(&once, ^{
static const CFRuntimeClass HeimCredClass = {
0,
"HeimCredential",
NULL,
NULL,
HeimCredReleaseItem,
NULL,
NULL,
HeimCredCopyFormatString,
HeimCredCopyDebugName
};
HeimCredCTX.haid = _CFRuntimeRegisterClass(&HeimCredClass);
HeimCredCTX.queue = dispatch_queue_create("HeimCred", NULL);
#if HEIMCRED_SERVER
HeimCredCTX.sessions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
#else
HeimCredCTX.items = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
#endif
});
}
CFTypeID
HeimCredGetTypeID(void)
{
_HeimCredInitCommon();
return HeimCredCTX.haid;
}
HeimCredRef
HeimCredCreateItem(CFUUIDRef uuid)
{
HeimCredRef cred = (HeimCredRef)_CFRuntimeCreateInstance(NULL, HeimCredCTX.haid, sizeof(struct HeimCred_s) - sizeof(CFRuntimeBase), NULL);
if (cred == NULL)
return NULL;
CFRetain(uuid);
cred->uuid = uuid;
return cred;
}