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