So awhile ago I started working on a way to move our Open Directory database off of Mac and onto a Linux box running OpenLDAP. But I wanted to find a way to do it without losing any functionality. So far it’s going pretty good. I have another post I’m working on that details all the steps to accomplish this. I’m kind of waiting until I make the move to post everything. One big hiccup I ran into is that without Apple’s PasswordServer most applications only support cleartext passwords, which is kind of a pain. Especially since some Apple applications (such as iChat) complain if you are using cleartext passwords, even if it is over an SSL link. So I wanted to find a way to provide the advanced password services that Apple provides.
Thus was born the Linux Password Server (or lpws). What I discovered is that Apple’s PasswordServer is simply a bridge between a client computer that wants to do SASL authentication and a centralized server that has access to the cleartext passwords. The protocol itself is simple text with the SASL data encoded in hex strings. While I don’t have everything working yet, all the authentication seems to work just fine. I have been able to generate an RSA private/public key pair which it uses to verify the authenticity of the host the client is talking to. I can store that public key in the authAuthority record of a user and add the server to the Password Server list in the LDAP database. From then on any requests to authenticate the user will work just as if you were still using Apple’s own services. All the authentication schemes seem to work just fine.
Since the password server just uses SASL to perform the actual authentication there was actually very little code to write for the server itself. I had to write the usual “client tracking” code and socket code you would need to provide basic TCP services and then implement a command processor to deal with the different commands that can be sent by the client. After that it was just pass along the data sent from the client into the SASL library. There were two big hurdles I ran into to get to the point I’m at now.
The first was the WEBDAV-DIGEST mechanism. This mechanism doesn’t exist on Linux, or anywhere else that I could find. After some time deciphering a bit of the protocol I found that it was basically just the DIGEST-MD5 mechanism with a slight twist. Instead of the authentication server generating the nonce and all that stuff, the “intermediate” server (i.e. iChat, Address Book, mail, etc.) generates the nonce and gives it to the authentication server. I suppose there is a slight security consideration with doing that as it is kind of close to a replay attack, but from my understanding of DIGEST-MD5 there are still enough security measures in place. So basically I had to duplicate a modify a few lines of code in the DIGEST-MD5 mechanism and rename it to WEBDAV-DIGEST.
The second hurdle was DHX. Nearly everything uses DIGEST-MD5 or WEBDAV-DIGEST to authenticate the user. I found only two cases where DHX is used. The first is when logging into a network account at the login window. Oddly enough, if DHX failed then it would fall back to DIGEST-MD5. This caused a significant delay in the login process so it was unacceptable to me. The second place was when changing a password via the “Connect to server” window (and possibly via System Preferences, I didn’t try that yet). When changing a password the client first authenticates you via DHX and then issues a CHANGEPASS command to set the new password. Why they chose to use a different mechanism just to authenticate you before changing your password I don’t know. But again, there did not exist an SASL DHX mechanism that I could use. So I had to write one. That took awhile to figure out but I finally managed to get it working after a few days of pouring over various resources online.
So what works now? Well you can authenticate users via the Linux Password Server. The services uses SASL so as long as SASL works on the server then it can authenticate. For my use, I wrote a tiny auxprop plugin that loads the cleartext password from LDAP and gives it to SASL to authenticate the user with. This all assumes you are using OpenLDAP and storing cleartext passwords (in as safe a way as possible). In theory the passwords could be stored somewhere else like Apple does, but this would require some customization to OpenLDAP so that when a user tries to do basic authentication they will be authenticated via the password server instead of the userPassword property. I didn’t really care for that option.
What doesn’t work? The CHANGEPASS command I mentioned above is not yet implemented but I don’t expect it to be any harder than the DHX was. I would expect it to be a fair amount easier actually. The only other command I have seen so far in all my testing is a GETPOLICY command during loginwindow logins. Apple returns a space separated list of abilities that the user has (for example, isAdmin=1/0). So this should be pretty easy to simulate by just returning a blank list or something. Right now it gives back an error response and the login proceeds normally. I think normally the loginwindow would check to see if the policy allows local logins, needs to change password, etc. There are also about 30+ more commands buried in Apple’s implementation that I haven’t even seen used yet. But those may not actually ever be used in the setup I will be running so we’ll have to wait and see.
If you are interested in taking a look at whats going on head over to Google Code and take a look at the project: http://code.google.com/p/lpws/
If you would like to help out just drop a note to me over there in the project. I’d be happy to have any extra help, especially with some of the documentation. Otherwise feel free to download the code and take it for a spin.
You might, by the way, be wondering why I would ever want to do this anyway. The answer is simple. Apple’s tools work great if you play by their rules. If you don’t want to customize anything or do anything a little different you are all good. As soon as you start making custom changes (like installing your own SSL certificate so it’s actually valid instead of a self-signed one) or modifying the way the Mail service filters spam; that is when you run into trouble. I don’t play by their rules 100% of the time. I can’t. They work great if you are a company with maybe a dozen employees but I have to deal with over 60 user accounts and about 150 client machines.
The other reason I want to do this is redundancy. I want to put all this authentication stuff on a VM, but I can’t do that with Apple. In order to virtualize I have to run it on Apple hardware. Only problem with that is they got rid of their server hardware. The Mac Mini is great as a client device but a joke as server. One ethernet? One power supply? Yea right. The Mac Pro is not much better. I gain a secondary ethernet port but still have a single power supply. But even if I did go with a Mac Pro, to get proper redundancy I would need at-least 2 Mac Pros in the rack (yea there goes 12U of space) and to buy a separate copy of VMWare Essentials Plus (at another $1,500 thank you). So now I’m sitting at $7,500 just to run a single server? no thanks. I’d rather do it on Linux where it’s free and works with everything I’ve already got installed. Does that mean I will still continue down this path if I can’t get the Mac clients to integrate nicely with Linux server? nope. That is still #1 priority, I need to have easy management. Time will tell.