Welcome, guest | Sign In | My Account | Store | Cart

Return a nested tuple of (uid, (gids)) for a UNIX domain socket, on FreeBSD. This is useful for access control on local servers, which can limit access based on the ID of the connecting user.

Python, 26 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import struct

def getpeerid(sock):
    """ Get peer credentials on a UNIX domain socket.

        Returns a nested tuple: (uid, (gids)) """

    LOCAL_PEERCRED = 0x001
    NGROUPS = 16

#struct xucred {
#        u_int   cr_version;             /* structure layout version */
#        uid_t   cr_uid;                 /* effective user id */
#        short   cr_ngroups;             /* number of groups */
#        gid_t   cr_groups[NGROUPS];     /* groups */
#        void    *_cr_unused1;           /* compatibility with old ucred */
#};

    xucred_fmt = '2ih16iP'
    res = tuple(struct.unpack(xucred_fmt, sock.getsockopt(0, LOCAL_PEERCRED, struct.calcsize(xucred_fmt))))
    
    # Check this is the above version of the structure
    if res[0] != 0:
        raise OSError

    return (res[1], res[3:3+res[2]])

UNIX domain sockets are great for communication with local servers because they are fast, and support credential passing: one end of the socket can identify the user ID and group IDs of the other party. This is useful for services that need to limit privileged access to certain users or groups.

Python does not provide an interface to this OS feature. The usual method for credential passing is to use the sendmsg/recvmsg system calls, but these are not exported by the socket module. However at least on some UNIX systems (FreeBSD, Linux, ...) there is an alternate interface using socket options. Unfortunately the interfaces are OS-specific. This is the FreeBSD interface; it would not be difficult for someone to add Linux support.