Created
February 20, 2019 19:45
-
-
Save knightsc/9b3fba827317cbf980ad8e99d8a17c7f to your computer and use it in GitHub Desktop.
Example of how the Security.framework calls into `syspolicyd` for Gatekeeper functionality
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#import <Security/Security.h> | |
#import <xpc/xpc.h> | |
#include <CoreFoundation/CoreFoundation.h> | |
#include <stdint.h> | |
typedef uint64_t SecAssessmentFlags; | |
enum { | |
kSecAssessmentDefaultFlags = 0, // default behavior | |
kSecAssessmentFlagDirect = 1 << 30, // in-process evaluation | |
kSecAssessmentFlagAsynchronous = 1 << 29, // request asynchronous operation | |
kSecAssessmentFlagIgnoreCache = 1 << 28, // do not search cache | |
kSecAssessmentFlagNoCache = 1 << 27, // do not populate cache | |
kSecAssessmentFlagEnforce = 1 << 26, // force on (disable bypass switches) | |
kSecAssessmentFlagAllowWeak = 1 << 25, // allow weak signatures | |
kSecAssessmentFlagIgnoreWhitelist = 1 << 24, // do not search weak signature whitelist | |
kSecAssessmentFlagDequarantine = 1 << 23, | |
// 1 << 23 removed (was kSecAssessmentFlagDequarantine) | |
kSecAssessmentFlagIgnoreActiveAssessments = 1 << 22, // permit parallel re-assessment of the same target | |
kSecAssessmentFlagLowPriority = 1 << 21, // run the assessment in low priority | |
}; | |
static const char serviceName[] = "com.apple.security.syspolicy"; | |
//static dispatch_once_t dispatchInit; // one-time init marker | |
static xpc_connection_t service; // connection to spd | |
static dispatch_queue_t queue; // dispatch queue for service | |
static void doProgress(xpc_object_t msg) | |
{ | |
uint64_t current = xpc_dictionary_get_uint64(msg, "current"); | |
uint64_t total = xpc_dictionary_get_uint64(msg, "total"); | |
uint64_t ref = xpc_dictionary_get_uint64(msg, "ref"); | |
const char *token = xpc_dictionary_get_string(msg, "token"); | |
// Skip handling cancellations for now. | |
// | |
// SecAssessmentFeedback feedback = SecAssessmentFeedback(ref); | |
// CFTemp<CFDictionaryRef> info("{current=%d,total=%d}", current, total); | |
// Boolean proceed = feedback(kSecAssessmentFeedbackProgress, info); | |
// if (!proceed) { | |
// xpc_connection_t connection = xpc_dictionary_get_remote_connection(msg); | |
// xpc_object_t cancelRequest = xpc_dictionary_create(NULL, NULL, 0); | |
// xpc_dictionary_set_string(cancelRequest, "function", "cancel"); | |
// xpc_dictionary_set_string(cancelRequest, "token", token); | |
// xpc_connection_send_message(connection, cancelRequest); | |
// xpc_release(cancelRequest); | |
// } | |
} | |
int main(int argc, const char * argv[]) { | |
@autoreleasepool { | |
const char *name = serviceName; | |
queue = dispatch_queue_create("spd-client", 0); | |
service = xpc_connection_create_mach_service(name, queue, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED); | |
xpc_connection_set_event_handler(service, ^(xpc_object_t msg) { | |
if (xpc_get_type(msg) == XPC_TYPE_DICTIONARY) { | |
const char *function = xpc_dictionary_get_string(msg, "function"); | |
if (!strcmp(function, "progress")) { | |
doProgress(msg); | |
} | |
} | |
}); | |
xpc_connection_resume(service); | |
xpc_object_t obj; | |
obj = xpc_dictionary_create(NULL, NULL, 0); | |
xpc_dictionary_set_string(obj, "function", "assess"); | |
xpc_dictionary_set_string(obj, "path", [@"/bin/ls" UTF8String]); | |
xpc_dictionary_set_uint64(obj, "flags", 0); | |
// Leaving off context causes syspolicyd to crash | |
CFMutableDictionaryRef ctx = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
// Set some values | |
CFDataRef contextData = CFPropertyListCreateData(NULL, ctx, kCFPropertyListXMLFormat_v1_0, 0, NULL); | |
xpc_dictionary_set_data(obj, "context", CFDataGetBytePtr(contextData), CFDataGetLength(contextData)); | |
xpc_object_t reply = xpc_connection_send_message_with_reply_sync(service, obj); | |
obj = NULL; | |
xpc_type_t type = xpc_get_type(reply); | |
if (type == XPC_TYPE_DICTIONARY) { | |
obj = reply; | |
int64_t error = xpc_dictionary_get_int64(obj, "error"); | |
if (error) { | |
printf("Error\n"); | |
} | |
else { | |
size_t resultLength; | |
const void *resultData = xpc_dictionary_get_data(obj, "result", &resultLength); | |
CFDataRef tempData = CFDataCreate(NULL, (const UInt8 *)resultData, resultLength); | |
CFPropertyListRef plist = CFPropertyListCreateFromXMLData(NULL, tempData, kCFPropertyListImmutable, NULL); | |
} | |
} else if (type == XPC_TYPE_ERROR) { | |
const char *s = xpc_copy_description(reply); | |
printf("Error returned: %s\n", s); | |
printf("code signing internal problem: unexpected error from xpc: %s", s); | |
free((char*)s); | |
} else { | |
const char *s = xpc_copy_description(reply); | |
printf("Unexpected type of return object: %s\n", s); | |
free((char*)s); | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment