SecKeychainAddCallback and command-line program

I was trying to figure out how to monitor keychain events, and wrote:

        dispatch_async(dispatch_get_main_queue(), ^{
            OSStatus kr = SecKeychainAddCallback(MyKeychainEventCallback, kSecEveryEventMask, NULL);
            printf("Got result %d\n", kr);
        });
        dispatch_main();

However, the callback never gets called.

I put the same code into a simple GUI app (invoked from the didFinishLaunching method), and it does work. So presumably this is something run-loop related. But I can't seem to figure it out -- so what am I doing wrong?

Given the age of this API it’s likely to be run loop based, so you’ll need to park the main thread is NSRunLoop rather than ‘parking’ [1] it in dispatch_main.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] dispatch_main actually terminates the main thread, which is kinda neat. The kernel will then start a worker thread in your process to service any Dispatch sources.

siiiiiiiiiiigh. The rest of the daemon I'd like to put this in is, of course, dispatch-based. I assume I can mix them both in, but I'll have to create a run loop just for this?

It's been a long time since I've had to do run loop stuff.

Looking at the code I believe that SecKeychainAddCallback schedules its run loop source on the current thead’s run loop rather than the main thread’s run loop. If I’m right, you should be able to start a thread to run this run loop source. So something like:

Thread {
    let err = SecKeychainAddCallback(…)
    … do something with err …
    RunLoop.current.run()
}

The rest of the daemon

Why are you registering this callback in a daemon? Most of the events it delivers aren’t relevant in that context.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

As usual, I probably WAY overthought it, and did:

        dispatch_async(dispatch_get_main_queue(), ^{
            NSRunLoop *myLoop = NSRunLoop.currentRunLoop;
            OSStatus kr = SecKeychainAddCallback(MyKeychainEventCallback, kSecEveryEventMask, NULL);
            while (1) {
                // Keep running, restarting every 10 minutes. We could make
                // this a lot longer, though.
                [myLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:600]];
            }
        });
SecKeychainAddCallback and command-line program
 
 
Q