Hi Eskimo, thank you for your help.
An example file would be /System/Library/Frameworks/CoreMediaIO.framework/Versions/A/Resources/VDC.plugin/Contents/MacOS/VDC
.
Following is my client code. I get the user's choice to block/unblock a file via xpc-connection from the frontend:
static NSArray *files = @[
@"/System/Library/Frameworks/CoreMediaIO.framework/Versions/A/Resources/VDC.plugin/Contents/MacOS/VDC",
...
];
static dispatch_queue_t g_event_queue = NULL;
static void
init_dispatch_queue(void)
{
dispatch_queue_attr_t queue_attrs = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_USER_INITIATED, 0);
g_event_queue = dispatch_queue_create("open_event_queue", queue_attrs);
}
#pragma mark Endpoint Security Event handlers
static void
handle_open_worker(es_client_t *client, const es_message_t *msg) {
NSString *openFilePath = [NSString stringWithFormat: @"%s", msg->event.open.file->path.data];
if ([files containsObject: openFilePath]) {
//Block if blocking state is disbaled at Host application
[[IPCConnectionService sharedService] getBlockingStateWithApplicationPath:[NSString stringWithUTF8String:msg->process->executable->path.data] completionHandler: ^(BOOL blockingState, NSString *source) {
es_respond_result_t es_result;
if (blockingState) {
// Don't allow any operations on path...
es_result = es_respond_flags_result(client, msg, 0, false);
// Deny writing to path...
// es_respond_flags_result(client, msg, 0xffffffff & ~FWRITE, true);
// Deny reading of path...
// es_respond_flags_result(client, msg, 0xffffffff & ~FREAD, true);
} else {
// Allow everything else...
es_result = es_respond_flags_result(client, msg, 0xffffffff, false);
}
// Print result
if (es_result != ES_RESPOND_RESULT_SUCCESS) {
switch(es_result) {
case ES_RESPOND_RESULT_ERR_INVALID_ARGUMENT:
// "One or more invalid arguments were provided"
break;
case ES_RESPOND_RESULT_ERR_INTERNAL:
// "Communication with the ES subsystem failed"
break;
case ES_RESPOND_RESULT_NOT_FOUND:
// "The message being responded to could not be found"
break;
case ES_RESPOND_RESULT_ERR_DUPLICATE_RESPONSE:
// "The provided message has been responded to more than once"
break;
case ES_RESPOND_RESULT_ERR_EVENT_TYPE:
// "Either an inappropriate response API was used for the event type (ensure using proper es_respond_auth_result or es_respond_flags_result function) or the event is notification only."
break;
}
}
es_release_message(msg);
}];
} else {
// Allow everything else...
es_respond_flags_result(client, msg, 0xffffffff, true);
es_release_message(msg);
}
}
static void
handle_open(es_client_t *client, const es_message_t *msg)
{
// Retains the given message, extending its lifetime until released.
es_retain_message(msg);
dispatch_async(g_event_queue, ^{
handle_open_worker(client, msg);
// Can't call es_release_message here because in
// handle_open_worker() we are async with an completionHandler
// es_release_message(msg);
});
}
static void
handle_event(es_client_t *client, const es_message_t *msg) {
switch (msg->event_type) {
case ES_EVENT_TYPE_AUTH_OPEN:
handle_open(client, msg);
break;
default:
if (msg->action_type == ES_ACTION_TYPE_AUTH) {
es_respond_auth_result(client, msg, ES_AUTH_RESULT_ALLOW, true);
}
break;
}
}
int main(int argc, char *argv[])
{
[[IPCConnectionService sharedService] startListner];
init_dispatch_queue();
// Create the client
es_client_t* client = NULL;
es_new_client_result_t newClientResult = es_new_client(&client, ^(es_client_t *c, const es_message_t *message) {
handle_event(c, message);
});
if (newClientResult != ES_NEW_CLIENT_RESULT_SUCCESS) {
switch(newClientResult) {
case ES_NEW_CLIENT_RESULT_ERR_NOT_ENTITLED:
// "Application requires 'com.apple.developer.endpoint-security.client' entitlement"
break;
case ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED:
// "Application lacks Transparency, Consent, and Control (TCC) approval from the user. This can be resolved by granting 'Full Disk Access' from the 'Security & Privacy' tab of System Preferences."
break;
case ES_NEW_CLIENT_RESULT_ERR_NOT_PRIVILEGED:
// "Application needs to be run as root"
break;
default:
// Unknown error
break;
}
es_delete_client(client);
return 1;
}
es_event_type_t events[] = { ES_EVENT_TYPE_AUTH_OPEN };
if (es_subscribe(client, events, sizeof(events) / sizeof(events[0])) != ES_RETURN_SUCCESS) {
es_delete_client(client);
return 1;
}
dispatch_main();
return 0;
}
I appreciate your help!
Thank you,
nm196