README: fdcred module for Python -------------------------------- Release 1 - 26/11/2004 Martin C. Atkins (martin@parvat.com) OVERVIEW -------- This module provides 5 functions, in two groups: sendfd and recvfd - send and receive an open fd down a Unix domain socket sendcred, recvcred, allowrecvcred - send and receive process credentials (IDs) WHY IS THIS USEFUL? ------------------- 1) A meta-server can accept network connections, say, and then pass them to an application server. Without this module, the meta-server would have had to fork the application server, which might not be possible, since the application server might already be running. 2) A program can run a priviledged utility that opens a connection to a resource, and passes it back to the program. This can remove SUID requirements from the program, and isolate them into the utility. 3) sending credentials allows a server to verify the identity of a client that attaches to it over a Unix-domain socket. This identity is not forgeable (without kernel hacking), and is thus a good thing(tm). 1 and 2 are both common idioms in Plan 9, and are one of the reasons why Plan 9 does not need (or allow) SUID programs. The techniques date back to, I believe, 8th Edition Unix, and allow one to consider file descriptors as "capabilities" for resources. WHY DID I WRITE IT? ------------------- I am working on a proof-of-concept replacement for inetd, working along the lines of 1) above, and wanted to prototype it in Python. EXAMPLE PROGRAM FRAGMENTS ------------------------- Program 1: ... import fdcred ... conn = ... open a Unix-domain socket to program 2 ... ... f = file(....) fdcred.sendfd(conn.fileno(), f.fileno()) Program 2: ... import fdcred ... conn = ... open a Unix-domain socket to program 1 ... ... (succ, fd) = fdcred.recvfd(conn.fileno()) if not succ: ... it all went horribly wrong ... f = os.fdopen(fd, "r") Notes 1) fdcred works with file descriptors, not Python file or socket objects. Use X.fileno() to get the filedescriptors from the objects Use os.fdopen if the received filedescriptor is file-like Use socket.fromfd if the received filedescriptor is a socket (Your programs must agree on which of these is appropriate) Program 3: ... import fdcred ... conn = ... open a Unix-domain socket to program 4 ... ... fdcred.sendcred(conn.fileno(), os.getpid(), os.getuid(), os.getgid()) Program 4: ... import fdcred ... conn = ... open a Unix-domain socket to program 4 ... ... succ = fdcred.allowrecvcred(conn.fileno()) # this only has to be done once if not succ: ... it all went horribly wrong ... ... (succ, pid, uid, gid) = fdcred.recvcred(conn.fileno()) if not succ: ... it all went horribly wrong ... ... pid, uid, gid are those sent by program 3 Notes 2) The pid, uid, gid, etc are checked by the kernel - arbitrary values are rejected 3) However, effective uids, etc, can be given, so long as they are true INSTALLATION ------------ 1) unpack into a new directory: $ tar xvfz fdcred.tgz This creates the directory fdcred in the current directory 2) go into the directory: $ cd fdcred 3) Build the module: $ python setup.py build 4) Install the module (this step must be done as root): $ python setup.py install TESTING THE INSTALLATION ------------------------ Open 2 terminal windows: Win1: $ python fdcred_testsend.py (there should be no output at this stage) Win2: $ python fdcred_testrecv.py Win1:output: sendfd => 0 sendcred=> 0 (NB. no-zero output means a failure to send) Win2:output: root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:100:sync:/bin:/bin/sync pid=17759, uid=1000, gid=1000 (With various differences in pid, uid, etc, depending on your site) LICENSE ------- The code is LGPL. See http://www.gnu.org/copyleft/lesser.html SEE ALSO -------- http://groups.google.com/groups?oi=djq&selm=an_443099042 for example code on using SCM_RIGHTS man 7 unix (SCM_RIGHTS and SCM_CREDENTIALS) man 3 cmsg (see example passing array of FDs) W Richard Stevens' books on Unix Network Programming. TODO ---- 1) Use proper interface macros to cmsg (this might be an aid to portability). See: http://www.uwsg.iu.edu/hypermail/linux/kernel/0009.1/0408.html for an example of this... but then again, the author says this code doesn't work! :-( A much fuller example is at: ftp://ftp.nc.orc.ru/pub/Linux/people/saw/bindd but I've only just discovered this, and haven't had time to look at it much. 2) Make versions for other operating systems that have the ability to pass file descriptors. As I understand it, there are two different interface styles for this functionality, one derived from System V, and one BSD. Linux uses the BSD variant. Systems using STREAMS (System V etc.) use the I_SENDFD variant, instead. (But I've lost my copy of Stevens right now, so I can't check these details right now!) Since I_SENDFD also does some of the functionality of recvcred, maybe this would suggest that a change in the interface from Python would be desirable. DISTRIBUTION ------------ The tar distribution was made by: $ cd $ mkdir fdcred $ cp README fdcredmodule.c setup.py fdcred_testsend.py fdcred_testrecv.py fdcred/. $ tar cfvz fdcred.tgz fdcred $ rm -rf fdcred