Pregunta

I am building a mac application, that at a certain time, needs to switch the currently logged in user to a different, preset one. Essentially a modified login window.

Is there a way to do this using cocoa?

-- Ari

Edit: Is there a way to not require the user to input their password?

¿Fue útil?

Solución

Before I say my solution, I want to say that @jrodatus's answer is excellent, it just is for a slightly different use case.

I came up with this little applescript:

set theUser to "user"
set theUser to do shell script "/usr/bin/id -u " & theUser
set password to "pswd"
do shell script "/System/Library/CoreServices/Menu\\ Extras/User.menu/Contents/Resources/CGSession -switchToUserID " & theUser
repeat
    try
        tell application "System Events"
            repeat until visible of process "SecurityAgent" is false
                set visible of process "SecurityAgent" to false
            end repeat
            keystroke password
            keystroke return
        end tell
        exit repeat
    on error
        tell application "System Events"
        end tell
    end try
end repeat

This simply triggers the login screen, with -switchToUserID set to the username's user id. Then when at least one window of SecurityAgent (The login screen) is visible, simulate the keystroke of the password, then enter the result is when run the login window opens, with the password typed in. Also, this has no delays.

Otros consejos

As explained in answer to a similar question here, there is a command-line tool called "CGSession" hidden in the System folder that should do what you need. To run a command-line tool inside a Cocoa application, look into NSTask.

To switch users directly, find out the unix user ID of your preset user by running "id -u theUserName" and then use the output as the argument for executing:

/System/Library/CoreServices/Menu\ Extras/User.menu/Contents/Resources/CGSession -switchToUserID theUserIDNumber

Or to simply get to the login window (without logging out), run:

/System/Library/CoreServices/Menu\ Extras/User.menu/Contents/Resources/CGSession -suspend

Here is a quick Obj-C category for NSWorkspace.

NSWorkspace-SwitchUser.h:

#import <Cocoa/Cocoa.h>

@interface NSWorkspace (SwitchUser)
-(BOOL)switchToUser:(NSString *)userName;
@end

NSWorkspace-SwitchUser.m:

#import "NSWorkspace-SwitchUser.h"
#import <sys/types.h>
#import <pwd.h>
#import <stdlib.h>
#import <unistd.h>
#import <stdio.h>

@implementation NSWorkspace (SwitchUser)

-(BOOL)switchToUser:(NSString *)userName {
    struct passwd *pwd = malloc(sizeof(struct passwd));
    if (!pwd) {
        NSLog(@"Couldn't allocate struct passwd for getpwnam_r.");
        return FALSE;
    }

    size_t buf_len = sysconf(_SC_GETPW_R_SIZE_MAX) * sizeof(char);
    char *buffer = malloc(buf_len);
    if (!buffer) {
        NSLog(@"Couldn't allocate buffer for getpwnam_r.");
        return FALSE;
    }

    getpwnam_r([userName UTF8String], pwd, buffer, buf_len, &pwd);
    if (!pwd) {
        NSLog(@"getpwnam_r failed to find the requested user.");
        return FALSE;
    }

    uid_t userID = pwd->pw_uid;

    free(pwd);
    free(buffer);

    // Run CGSession with the -switchToUserID argument
    NSTask *cgsTask = [NSTask launchedTaskWithLaunchPath:@"/System/Library/CoreServices/Menu Extras/User.menu/Contents/Resources/CGSession" 
                                               arguments:[NSArray arrayWithObjects:@"-switchToUserID",[NSString stringWithFormat:@"%u",userID],nil]];

    // Wait till the task completes.
    // Should be able to use -[NSTask waitUntilExit] instead, but it wasn't working for me :-P
    while ([cgsTask isRunning]) {
        usleep(100000);
    }

    return ([cgsTask terminationStatus] == 0);
}

@end

Edit: If you need to switch users without requiring the user to enter their password, there doesn't seem to be any way to do that without AppleScript, which IMO is unsafe in every sense of the word. But you might glean what you need here and here.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top