How is Unix socket credential passing accomplished in Python?
2 Answers
Internet searches on this topic came up with surprisingly few results. I figured I'd post the question and answer here for others interested in this topic.
The following client and server applications demonstrate how to accomplish this on Linux with the standard python interpreter. No extensions are required but, due to the use of embedded constants, the code is Linux-specific.
Server:
#!/usr/bin/env python
import struct
from socket import socket, AF_UNIX, SOCK_STREAM, SOL_SOCKET
SO_PEERCRED = 17 # Pulled from /usr/include/asm-generic/socket.h
s = socket(AF_UNIX, SOCK_STREAM)
s.bind('/tmp/pass_cred')
s.listen(1)
conn, addr = s.accept()
creds = conn.getsockopt(SOL_SOCKET, SO_PEERCRED, struct.calcsize('3i'))
pid, uid, gid = struct.unpack('3i',creds)
print 'pid: %d, uid: %d, gid %d' % (pid, uid, gid)
Client:
#!/usr/bin/env python
from socket import socket, AF_UNIX, SOCK_STREAM, SOL_SOCKET
SO_PASSCRED = 16 # Pulled from /usr/include/asm-generic/socket.h
s = socket(AF_UNIX, SOCK_STREAM)
s.setsockopt(SOL_SOCKET, SO_PASSCRED, 1)
s.connect('/tmp/pass_cred')
s.close()
Unfortunately, the SO_PEERCRED and SO_PASSCRED constants are not exported by python's socket module so they must be entered by hand. Although these value are unlikely to change it is possible. This should be considered by any applications using this approach.

- 7,779
- 24
- 25
-
I don't think they can ever change. In this case, all existing applications would have to be recompiled... But they might be different amongst several OSes or several platforms. – glglgl Nov 02 '11 at 16:17
-
3I'd +1 you but for one thing, this isn't actually credential passing. `SO_PASSCRED` allows receiving (not sending) of credentials, but those are sent using `sendmsg` and an ancillarry `SCM_CREDENTIALS` message. you are reading `SO_PEERCRED` which does not depend on this, only that the socket is a unix domain socket or was created by `socketpair`. and only gets the current credentials (root can send credential messages matching other users) – Hasturkun Nov 02 '11 at 16:24
-
5I think SO_PEERCRED and SO_PASSCRED are in the socket module right now (at least in 3.3). Didn't found when they were added. I did remember they were not there when I first find this post one year ago... – yuyichao Sep 04 '13 at 04:18
Here is a Python 3 version of Rakis' server.py that does not use hardcoded IDs and also displays user and group names of the client:
#!/usr/bin/env python
import os
import atexit
import grp
import pwd
import struct
from socket import socket, AF_UNIX, SOCK_STREAM, SOL_SOCKET, SO_PEERCRED
def remove_sock():
try:
os.unlink('/tmp/pass_cred')
except FileNotFoundError:
pass
remove_sock()
atexit.register(remove_sock)
s = socket(AF_UNIX, SOCK_STREAM)
s.bind('/tmp/pass_cred')
s.listen(1)
conn, addr = s.accept()
creds = conn.getsockopt(SOL_SOCKET, SO_PEERCRED, struct.calcsize('3i'))
pid, uid, gid = struct.unpack('3i',creds)
user_name = pwd.getpwuid(uid)[0]
group_name = grp.getgrgid(gid)[0]
print(f'pid={pid}, uid={uid}({user_name}), gid={gid}({group_name})')
Also updated to make reusable (you cannot bind the socket to a filename that already exists, so we clean the socket both before bind and after normal process exit)

- 129,958
- 22
- 279
- 321