1

I am learning to write EndpointSecurity Client for macOS. The client is running and observes all the notifications from all the paths from "/" (root), as it runs as root. I have muted all the system-paths.

What I need is to observe path for /Users/anoopvaidya for any file changes. But this never happens, what am I missing?

What I learn is if there are several notifications it may get skipped in the Queue.

So is there a way to mute-all but targeted ones?

Any leads/guidance is much appreciated.

Here is the full code:

static void handleEvent(es_client_t *client, const es_message_t *msg)
{
    char const *filePath = msg->process->executable->path.data;
    NSString *filePathString = [[NSString alloc] initWithFormat:@"%s", filePath];
    
    // TODO: need to check the user who logged in, is this possible?
    NSString *path = [NSString stringWithFormat:@"/Users/%@/Documents", @"anoopvaidya"];

    os_log(OS_LOG_DEFAULT, "filePathString = %@, path = %@", filePathString, path);
    
    // check if the events are from path
    if ([filePathString hasPrefix:path]) {
        os_log(OS_LOG_DEFAULT, "Compare - filePathString = %@, path = %@", filePathString, path);
        os_log(OS_LOG_DEFAULT, "proceeding...");
    }
    else {
        return;
    }
    
    switch (msg->event_type) {
        case ES_EVENT_TYPE_NOTIFY_EXEC:
            os_log(OS_LOG_DEFAULT, "%{public}s (pid: %d) | EXEC: New image: %{public}s",
                msg->process->executable->path.data,
                audit_token_to_pid(msg->process->audit_token),
                msg->event.exec.target->executable->path.data);
            break;

        case ES_EVENT_TYPE_NOTIFY_FORK:
            os_log(OS_LOG_DEFAULT, "%{public}s (pid: %d) | FORK: Child pid: %d",
                msg->process->executable->path.data,
                audit_token_to_pid(msg->process->audit_token),
                audit_token_to_pid(msg->event.fork.child->audit_token));
            break;

        case ES_EVENT_TYPE_NOTIFY_EXIT:
            os_log(OS_LOG_DEFAULT, "%{public}s (pid: %d) | EXIT: status: %d",
                msg->process->executable->path.data,
                audit_token_to_pid(msg->process->audit_token),
                msg->event.exit.stat);
            break;

        case   ES_EVENT_TYPE_NOTIFY_OPEN:
            os_log(OS_LOG_DEFAULT, "Open event");
            break;
        case ES_EVENT_TYPE_NOTIFY_CLOSE:
            os_log(OS_LOG_DEFAULT, "Close event");

            break;
            
        default:
            os_log_error(OS_LOG_DEFAULT, "Unexpected event type encountered: %d\n", msg->event_type);
            break;
    }
}

void mutePath(es_client_t *client) {
    NSArray<NSString *> *paths = @[
        @"/bin/", @"/private/", @"/Applications/",
        @"/var/", @"/cores/", @"/dev/", @"/opt/", @"/private/", @"/System/", @"/Library/",
        @"/sbin/", @"/usr/"
    ];
    for (NSString *e in paths) {
        es_mute_path_prefix(client, [e UTF8String]);
    }
}

int main(int argc, char *argv[])
{
    // 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) {
        handleEvent(client, message);
    });

    if (newClientResult != ES_NEW_CLIENT_RESULT_SUCCESS) {
        return 1;
    }
    
    mutePath(client);
    
    es_event_type_t events[] = {
        ES_EVENT_TYPE_NOTIFY_CREATE, //create file
        ES_EVENT_TYPE_NOTIFY_OPEN, // open file
        ES_EVENT_TYPE_NOTIFY_RENAME, // rename file
        ES_EVENT_TYPE_NOTIFY_CLOSE, // close file
        ES_EVENT_TYPE_NOTIFY_WRITE, // write to file
        ES_EVENT_TYPE_NOTIFY_UNLINK, // delete
        ES_EVENT_TYPE_NOTIFY_EXIT };

    if (es_subscribe(client, events, sizeof(events) / sizeof(events[0])) != ES_RETURN_SUCCESS) {
        os_log(OS_LOG_DEFAULT, "Failed to subscribe to events");
        es_delete_client(client);
        return 1;
    }

    dispatch_main();
}
Anoop Vaidya
  • 46,283
  • 15
  • 111
  • 140

1 Answers1

0

There is a way to do this, with the es_invert_muting() function (available in MacOS 13.0 and later).

You can do something like this:

es_unmute_all_target_paths(client)
es_invert_muting(client, ES_MUTE_INVERSION_TYPE_TARGET_PATH)
es_mute_path(client, path, ES_MUTE_PATH_TYPE_TARGET_PREFIX)

This removes the default mute list, "inverts" the mute logic, so only muted paths are selected, then selects one path p[refix to monitor.

Note that there is a difference between ES_MUTE_PATH_TYPE_PREFIX and ES_MUTE_PATH_TYPE_TARGET_PREFIX. The former refers to the path of the executable that triggered the event, and the latter is the path of the file that was accessed.

Mark Bessey
  • 19,598
  • 4
  • 47
  • 69