views:

728

answers:

2

Is it possible to replace the Mac OS X login window, /System/Library/CoreServices/loginwindow.app, with a custom login window application? (See my rational for doing so.)

I'm afraid my Cocoa programming skills are rudimentary. I do find it interesting that, when I run probe CGSession (which is a undocumented utility that performs fast user switching) to see what functions it uses, by doing

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

that one of the linked function is:

(undefined [lazy bound]) external _CGSCreateLoginSession (from ApplicationServices)

I haven't found documentation on the ApplicationServices framework. I suspect I'm getting deep into Service Provider Interfaces instead of Application Programmer Interfaces.

I did find this really interesting snippet: (google cache) (direct link to down page; it appears the site is undergoing re-organization) from an application that claims to switch to the login window even if fast user switching is disabled.

#include "CGSInternal.h"

int main (int argc, const char * argv[]) {
    // switch to the login window
    CGSCreateLoginSession(NULL);

    return 0;
}

I take CG to mean CoreGraphics, and don't understand what that has to do with logging in (except with perhaps putting a login dialog up over the current user's work).

Even if it is not possible to achieve a replacement for the login window, I'd be interested to know what can be done along these lines (by people who don't work for Apple).

+6  A: 

The login window application is defined as part of the launchd configuration in /System/Library/LaunchDaemons/com.apple.loginwindow.plist.

In theory you can replace the login window with your own but I don't know what you have to do in the new app - I think the login window does a bit more then authentication and setting up the user session -> amongst others, it looks like its doing some launchd related chores.

I've compiled an application that calls CGSCreateLoginSession and once you run it it transitions to the login window via the rotating cube. I imagine this is why it requires CoreGraphics - it's just a graphics function that calls logout at the end.

You could try an InputManager and see it the login window loads the code -> if it does, you could then alter the loginwindow NIB (LoginWindowUI.nib) and add some buttons to display a new window with the user browser. Once the student chooses a picture of him/herself you could autofill the username and password fields in the loginwindow.

Node this is all theory, and it looks very fragile and unsafe.

Good luck.

Later edit

Please note this is very unsafe so use with care - I did hose my system a couple of times when trying out this stuff

Here's a proof-of-concept implementation that injects code in the loginwindow.

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <strings.h>
#include <syslog.h>

#import <Cocoa/Cocoa.h>

#include <execinfo.h>

@interface LLApp:NSApplication
@end
@implementation LLApp
- (void)run
{
    syslog(LOG_ERR, "LLApp being run");
    [super run];
}
@end

void my_openlog(const char *ident, int logopt, int facility);

typedef struct interpose_s 
{
        void * new_func;
        void * orig_func;
} interpose_t;

int MyNSApplicationMain(int argc,  const char ** argv);


static const interpose_t interposers[] __attribute__ ((section("__DATA, __interpose")))     = {
{ (void *) my_openlog, (void *) openlog },
};

void my_openlog(const char *ident, int logopt, int facility)
{
        openlog(ident, logopt, facility);

    if(!strcmp(ident, "/System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow"))
    {

     [LLApp poseAsClass:[NSApplication class]];
    }
    else
    {
     syslog(LOG_ERR, "Ignoring unknown indent: >%s<", ident);
    }
    return;
}

The code compiles with:

gcc -Wall -dynamiclib -undefined dynamic_lookup -o ~/Desktop/libinterposers.dylib testin.m -framework Cocoa

Code loading is based on interposing so the launchd definition of loginwindow has to contain an additional entry (to enable interposing in the dynamic linker), i.e.:

<key>EnvironmentVariables</key>
<dict>    
    <key>DYLD_INSERT_LIBRARIES</key>
    <string>path_to/Desktop/libinterposers.dylib</string>
</dict>
diciu
Wow. I'd gladly upvote you a second time. That's incredible and crazy at the same time. As it is fairly advanced, let me be sure I understand correctly what this sample does: it replaces the call to "openlog" with a "my_openlog" which makes your class LLApp pretend to be the NSApplication class, so that any calls to its functions can be modified, and it proves this by modifying the run function to output something to the system log.
Clinton Blackmore
Function replacement is made possible by interposing - google for "interposing mac os x" and you'll find a chapter of Amit Singh's book on OS X that describes how it works. Class posing is used to replace all instances of class X with class Y - note it's not supported on 64 bit.As for replacing -[NSApplication run] you probably don't want that - you need to replace something inside the loginwindow app such as some method from the custom view class (you can find the name of the custom view class by opening the bundle in Interface builder).
diciu
It looks like I wont be able to allocate time to this in the near future, but I'm definitely giving you the correct answer rep for all the hard work you put in; I really think that the task can be accomplished with this guidance. Thanks.
Clinton Blackmore
+2  A: 

yes, you can use the SFAuthorizationPluginView

here the reference link at ADC

kent
Thanks for the info. Looks like it is Leopard only (I would like to support Tiger, too). Apple has a "NameAndPassword" sample, and there are a couple related questions on SO, which are using a tag or "SFAuthorizationPluginView" (http://stackoverflow.com/questions/tagged/sfauthorizationpluginview)
Clinton Blackmore
I'm not sure you can easily use SFAuthorizationPluginView to change anything in the login window. I've compiled and installed the NameAndPassword code sample that illustrates SFAuthorizationPluginView and it looks to me like it allows you to build a custom right (see /etc/authorization for definitions of existing rights -> login is not in there).The plugin comes into play when an application then asks the OS to authorize the user for that newly created right.
diciu
Thank you, diciu. It wasn't clear to me how you would (or if you could) make this appear on the login screen. [I'd compiled it, but didn't want to test (and break!) authorization on my own computer.]
Clinton Blackmore
I thought perhaps I could add something to /etc/authorization under the system.login.console to trigger the plugin at login time, but I have no clear idea what to add there.
Clinton Blackmore
For what it's worth, I've completely broken my login window by messing up com.apple.loginwindow.plist referred in my answer but I was able to login via SSH. And I have a bootable external drive (I use SuperDuper!) that allows me to mess up my system knowing I can always boot via Firewire and undo destructive system changes.
diciu