Search code examples
macoscocoalaunch-daemon

Daemon to know when a user logs into the MAC


I have a daemon (written in Obj C) running, and I would like to perform some action when some user logs in. Is it possible for a Daemon to know when a particular user logs in or out in OSX? Are there any Notifications thrown when a log in occurs? I would like to avoid the use of Log in Item or Launch Agent. And also i would like to avoid polling on a timer to check the logged in user.


Solution

  • Use SCDynamicStoreCopyConsoleUser to get the console user name.

    CFStringRef  consoleUserName = nil;
    uid_t        uid;
    gid_t        gid;
    consoleUserName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid);
    

    Store consoleUserName in some member variable. Now creates a session to interact with the dynamic store maintained by the System Configuration server using SCDynamicStoreCreate

         SCDynamicStoreRef   store;
         CFStringRef         key;
         CFArrayRef          keys;
         CFRunLoopSourceRef  rls;
         store = SCDynamicStoreCreate(
                                         NULL, 
                                         CFSTR("com.apple.dts.ConsoleUser"), 
                                         callBackFunction, 
                                         NULL
                                         );
    
        // Set it up to notify us when the console user value changes.
    
        key = SCDynamicStoreKeyCreateConsoleUser(NULL);
        assert(key != NULL);
    
        keys = CFArrayCreate(NULL, (const void **) &key, 1, &kCFTypeArrayCallBacks);
        //assert(keys != NULL);
    
        success = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
        //assert(success);
    
        // Add it to the runloop.
    
        rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
       // assert(rls != NULL);
    
        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
    
    
        mConsoleUserName = CopyCurrentConsoleUsername(store);
        CFRunLoopRun();
    
        CFRunLoopSourceInvalidate(rls);
        CFRelease(rls);
        CFRelease(keys);
        CFRelease(key);
        CFRelease(store);   
    

    Implement callBackFunction function. You will get callback when the console user value changes.

    static void callBackFunction(
                                   SCDynamicStoreRef    store,
                                   CFArrayRef          changedKeys,
                                   void *              info
                                   )
    {
        CFStringRef         currentConsoleUser;
        Boolean             didChange;
    
        // Get the current console user.
    
        currentConsoleUser = CopyCurrentConsoleUsername(store);
    
        if (currentConsoleUser == NULL)
        {
            return;
        }
        didChange = ! CFEqual(storedvalue, currentConsoleUser);
        if (![currentConsoleUser isEqualToString:@"loginwindow"])
        {
          // pass this value to some method
        }
    }