How to Get The UId of The Other End of a Unix Socket Connection

Is there a way to get the uid of the other end of a unix socket connection

The easiest way to check peer credentials is with SO_PEERCRED.
To do this for socket sock:

int len;
struct ucred ucred;

len = sizeof(struct ucred);
if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
// check errno

printf("Credentials from SO_PEERCRED: pid=%ld, euid=%ld, egid=%ld\n",
(long) ucred.pid, (long) ucred.uid, (long) ucred.gid);
SO_PEERCRED
Return the credentials of the foreign process connected to
this socket. This is possible only for connected AF_UNIX
stream sockets and AF_UNIX stream and datagram socket pairs
created using socketpair(2); see unix(7). The returned
credentials are those that were in effect at the time of the
call to connect(2) or socketpair(2). The argument is a ucred
structure; define the _GNU_SOURCE feature test macro to obtain
the definition of that structure from <sys/socket.h>. This
socket option is read-only.

From a tlpi example. PostgreSQL has a few variants for other unices.

Is it possible to find which user is at the other end of a localhost TCP connection?

On Linux, /proc/net/tcp contains information on the open TCP sockets on the system. For a connected socket, the entries look like this (the header is part of the file, other lines removed):

  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                     

11: 0100007F:C9CB 0100007F:0016 01 00000000:00000000 00:00000000 00000000 1000 0 978132 ...

The second and third columns have the endpoints of the socket, and the uid column has the effective UID of the process what created the socket.
/proc/net/tcp6 is similar for IPv6. (The IP address there is 127.0.0.1, so the octets seem to be in reverse order.)

If you wanted to track the actual process(es) holding the socket, you'd need to go through all /proc/$PID/fd/$N entries, and compare the inode numbers in the socket symlinks to the inode number mentioned in the tcp socket table. But you can only see the file descriptors of your own processes, unless you're the superuser.

Identify program that connects to a Unix Domain Socket

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 */
};

How to get caller pid in zmq (local socket)

Forget most of the low-level socket designs and worries. Think higher in the sky. ZeroMQ is a pretty higher-level messaging concept. So you will have zero-worries about most of the socket-io problems.

For more on these ZMQ principles, read Pieter Hintjens' design maxims and his resources-rich book "Code Connected, Vol.1".

That said, the solution is fully in your control.

Solution

Create a problem-specific multi-zmq-socket / multi-zmq-pattern (multiple zmq-primitives used and orchestrated by your application level logic) as a problem-specific formal communication handshaking.

Ensure the <sender> adds it's own PID into message.

Re/authorise via another register/auth-socket-pattern with the pre-registered sender from the receiver side, so as to avoid a spoofed attack under a fake/stolen PID-identity.

Adapt your access-control policy according to your ProblemDOMAIN, use and implement any level of crypto-security formal handshaking protocols for identity-validation or key-exchange, to raise your access-control policy security to adequate strengths ( including MIL-STD grades ).

Peer credentials through unix domain socket ipc mechanism

See http://www.thomasstover.com/uds.html for good overview.

If the server is Linux, the main problem is missing _GNU_SOURCE. Full patch below, it has a few minor changes just to get rid of gcc -Wall -Werror -pedantic -std=c99 errors and warnings.

--- server.c.orig   2014-12-06 13:23:09.138472871 +0200
+++ server.c 2014-12-06 13:21:31.962475754 +0200
@@ -1,3 +1,4 @@
+#define _GNU_SOURCE
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -5,7 +6,6 @@
#include <unistd.h>
#include <string.h>
//#include<ucred.h>
-#define SCM_CREDENTIALS
# define UNIX_PATH_MAX 100

int getpeereid(int connection_fd,uid_t euid,gid_t gid)
@@ -20,8 +20,8 @@
//int passcred=1;
//setsockopt(connection_fd,SOL_SOCKET,SO_PASSCRED,(void *)&passcred,sizeof(passcred));

-printf("effective user id", euid);
-printf("effective group id",gid);
+printf("effective user id %d", euid);
+printf("effective group id %d",gid);
return 0;
}

@@ -40,7 +40,7 @@
printf("MESSAGE FROM CLIENT: %s\n", buffer);
printf("enter the message");
scanf("%s",msg);
-nbytes = snprintf(buffer, 256,msg);
+nbytes = snprintf(buffer, 256, "%s", msg);
write(connection_fd, buffer, nbytes);
//}
close(connection_fd);
@@ -54,8 +54,6 @@
int socket_fd, connection_fd,res;
socklen_t address_length;
pid_t child;
-uid_t eid;
-gid_t gid;

socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if(socket_fd < 0)


Related Topics



Leave a reply



Submit