porting CCAPI to UNIX

Ken Raeburn raeburn at MIT.EDU
Wed May 2 17:56:27 EDT 2007


I've been looking at porting the CCAPI code that's used on the Mac  
for managing credentials caches over to UNIX.

Basically, this code works by having a running process for the user  
(CCacheServer) that can be contacted via IPC.  The protocol defines a  
set of remote procedure calls for fetching or storing credentials,  
selecting from among multiple credentials caches, etc.

The RPC portion and the main server code are pretty well isolated  
from the system-specific bits.  So the interesting part for porting  
to UNIX is how the IPC should be performed, including how the client  
should contact the server.

Some of the issues are:
  * credentials segregated per login session or visible to all of  
users' sessions?
  * minimal or no resource use (no server process) for users not  
using Kerberos
  * one monolithic server process for the system, or one per user or  
session?

For portable solutions, I think we come down to sockets, shared  
memory, and message queues.  None of these portably let you look at  
the uid of the process on the other side, so I think we're stuck with  
access control to some rendezvous point.  Shared memory and message  
queues may have some interesting capabilities, but so far, I don't  
think we get a lot that we don't get with file system access, and I  
understand there are often severe limitations on (e.g.) the number of  
shared memory segments available.  With UNIX-domain sockets, it's not  
too hard.  While some systems don't implement checks of the  
permissions on the socket object itself, a mode-700 directory  
containing the socket and owned by the user is quite effective.

Another issue is how to get the server process started.  If we launch  
a subprocess, we have to deal with SIGCHLD being delivered to the  
application process for a child it doesn't know about (which arguably  
the process should handle, if it could have been started via exec  
from a process with children, but that may not always be the case);  
if the application is calling wait() or friends in another thread, it  
may catch the exit status of the ccapi launcher subprocess..   
Handlers registered with pthread_atfork will get invoked.  If we  
launch a subprocess and exec a server program, we need to close all  
previously open file descriptors except for the ccapi communications  
channel.

Well, what do we have that works well for spawning server processes  
without messy interaction with the process wanting to talk to the  
server?  There's inetd...

So, here's a strawman proposal; comments would be greatly appreciated:

We pick a port number, and if the sysadmin wants to use ccacheserver  
on unix, he configures inetd to launch it.  Maybe the port number can  
be configured in krb5.conf.

The server process either uses a configured directory given by the  
administrator (via command line or krb5.conf), or creates a randomly- 
generated name in /tmp (iterating until finding one not in use;  
strong PRNG not required).  This directory is owned by root, mode 755  
or 711.

Application connects to server, sends over its uid.  On the server  
side, a subdirectory of the server's work directory is created, mode  
700, and the uid is changed to the specified uid.  A UNIX-domain  
socket is created in the directory, and the server listens on it.   
The server sends the pathname of the socket back to the client.  The  
client closes down the initial connection and connects to the UNIX- 
domain socket, thereby proving it's really using that uid.

If the server has to pick a directory name, either we have to find  
some place to record it, or some process (presumably the master  
server process) needs to stay around as long as it's in use, so all  
clients, regardless of uid, can be pointed to the same tree.  If a  
fixed directory name (or a computable one like /var/per-user-temp- 
space/${uid}) is used, the server process launched from inetd could  
instead just see if the per-uid process is running, spawn it if  
necessary, send the client the pathname, and exit.

The server process can time out; if it has no credentials and hasn't  
heard from anyone in some amount of time, it cleans up and goes away.

Any connections coming in from non-loopback addresses would be  
immediately discarded.

----

Tom and I talked over some other possibilities that would get rid of  
the mode-700 directory, including writing to a mode-600 file  
appropriately chown'ed, but the schemes kept coming down to using a  
strong PRNG to generate some kind of authentication data.

We also looked at the subprocess approach a bit.  We keep coming back  
to either schemes that are easy for a third party to disrupt, because  
they involve predictable names in world-writable places, or they  
require a setuid server program launched from under user control, and  
all the hassle that that implies.  Or having a server program that  
has to be launched by an administrator, listening on a well-known  
UNIX-domain socket.  Or setup and teardown done by the login program  
(or sshd or whatever).

Maybe we've just overlooked something simple....

Ken



More information about the krbdev mailing list