识别连接到Unix域套接字的程序

17

我有一个程序在监听Unix域套接字。

当客户端连接到套接字时,我想找出是哪个程序连接的,然后根据用户/组设置决定是否允许连接。

在Linux下是否可能实现这一点,如果可以,如何实现?

3个回答

18

在Linux下是可以实现这个的,但是这种方法不太具有可移植性。它是通过使用"ancillary data"以及sendmsg / recvmsg实现的。

  • 使用setsockoptSO_PASSCRED
  • 使用SCM_CREDENTIALSstruct ucred结构体

这个结构体在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 */
};

请注意,您需要在msghdr.control中填写这些内容,内核将检查它们是否正确。

主要的可移植性障碍是该结构在其他Unix系统上不同 - 例如,在FreeBSD上是这样的:

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

1
非常感谢。正是我想要的。可移植性不是问题。因为代码只会在 Android 上作为本地代码运行。 - Nils Pipenbrinck
嗨,我是socket的新手。我想知道如何获取发送进程的PID。谢谢。 - Kevin Yue

15

我搜索了很多,所以我会向您展示如何在套接字sock上使用SO_PEERCRED来获取套接字的对等方的pid/uid/gid:

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);

1
我也搜索了很多,很幸运找到了这个答案!大多数其他来源坚称你需要使用sendmsgrecvmsg,但这是不正确的。我要补充的是,在给出的示例中,sock参数将是您想要标识的客户端进程的文件描述符,而且我发现我需要从客户端进行至少一次数据读取,否则在ucred结构中我会得到未定义的值。 - Username Obfuscation
自glibc 2.8.0 (2009) 起,需要定义“_GNU_SOURCE”。临时源代码:https://github.com/apple/cups/issues/2860 - i336_

2

也许 getpeername 或者 getsockname 可以帮助你。我认为你的 unix socket 的权限是有用的(不太确定)。如果你的 accept 的 socket 是 12,你可以读取 /proc/self/fd/12 中的链接。

编辑

cnicutar所建议的那样,使用辅助数据获取凭证和 sendmsg 更好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接