I have a program that is listening to a Unix Domain Socket.
When a client connects to the socket I'd like to find out which program connected and then decide if I allow the connection or not (based on the user/group settings).
Is this possible under Linux, and if so, how?
Yes, this is possible on Linux, but it won't be very portable. It's achieved using what is called "ancillary data" with sendmsg
/ recvmsg
.
- Use
SO_PASSCRED
with setsockopt
- Use
SCM_CREDENTIALS
and the struct ucred
structure
This structure is defined in Linux:
struct ucred {
pid_t pid; /* process ID of the sending process */
uid_t uid; /* user ID of the sending process */
gid_t gid; /* group ID of the sending process */
};
Note you have to fill these in your msghdr.control
, and the kernel will check if they're correct.
The main portability hindrance is that this structure differs on other Unixes - for example on FreeBSD it's:
struct cmsgcred {
pid_t cmcred_pid; /* PID of sending process */
uid_t cmcred_uid; /* real UID of sending process */
uid_t cmcred_euid; /* effective UID of sending process */
gid_t cmcred_gid; /* real GID of sending process */
short cmcred_ngroups; /* number or groups */
gid_t cmcred_groups[CMGROUP_MAX]; /* groups */
};
I searched for this quite a bit, so I will show you this example on how to use SO_PEERCRED
on a socket sock
to get the pid/uid/gid of the peer of a socket:
int len;
struct ucred ucred;
len = sizeof(struct ucred);
if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) {
//getsockopt failed
}
printf("Credentials from SO_PEERCRED: pid=%ld, euid=%ld, egid=%ld\n",
(long) ucred.pid, (long) ucred.uid, (long) ucred.gid);
Perhaps getpeername or getsockname could help. and I think that the permission of your unix socket are useful (not sure of that). And you might read the link inside /proc/self/fd/12
if your accept
-ed socket is 12.
EDIT
using ancillary data for credentials and sendmsg
is much better, as suggested by cnicutar below.