如何创建具有特定访问权限的 Unix 域套接字

How to create a Unix-domain socket with specific access permissions

我有一种情况,我打算通过文件系统上的 UNIX 域套接字提供的命令接口与服务通信。我能够成功地向它发送命令,但有一段时间我很困惑为什么我无法收到对我的查询的任何响应。

事实证明,该服务没有足够的权限写入我为其提供的地址(或 OS)。但是,我意识到,如果我明确 bind 到文件系统上的地址,那么我可以通过利用 chmod 来调整文件权限。

类似于:

int mySocket;
struct sockaddr_un local_addr; 

mySocket = socket(AF_UNIX, SOCK_DGRAM, 0);
local_addr.sun_family = AF_UNIX;
snprintf(local_addr.sun_path, 108  "/path/to/mySocket");

bind(mySocket, (struct sockaddr *) &local_addr, sizeof(struct sockaddr_un));
chmod("/path/to/mySocket", 777);

也就是说,如果没有最后的 chmod 步骤,服务将无法写入 mySocket,因为它没有适当的写入权限。显然,如果没有显式 bind 到特定地址,这是一个更难发现的问题,因为底层 OS 将为用户隐式生成此套接字 - 但它仍然存在并且 仍然会有同样的访问问题。

那么,我的问题是关于这最后一步的。有没有办法允许 OS 为我的端点隐式生成套接字(即服务将响应的 地址 )但请求它被赋予某些权限?


解释

这个问题成为问题的原因是程序的其他部分需要以 root 身份执行。因此,当我以 root 身份尝试 connect/send 到后台服务时,OS 将隐式创建一个地址,回复将定向到该地址。然而,这导致了我的套接字文件的问题,无论是隐式的还是使用 bind 创建的,都将具有像 srw- --- --- 这样的权限,因此另一个端点只有在它们也提升自己时才能回复。

因此,如果我先 bind 然后 chmod 如上所示的权限,问题就会消失。

[已编辑] 我的第一个猜测是改用 fifo,它可以让您先创建文件并设置其权限。此外,如果两个用户要通过 fifo 进行通信,最好使用组级别 read/write 并将他们放在同一组中。

$ mkfifo -m 660 fifo_name

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *path, mode_t mode);

正如 sherrellbc 所提到的,这与 unix 套接字无关。如果您被迫使用套接字,为什么不在创建之前放弃权限呢?这似乎是 运行 suid 时的重要一步。

struct sockaddr_un to_addr;
memset(&to_addr, 0, sizeof(struct sockaddr_un));
strncpy(to_addr.sun_path, "/path/to/socket", sizeof(to_addr.sun_path) - 1);
to_addr.sun_family = AF_UNIX;

/* ------------ change user ------------ */
if(setgid(new_gid) || setuid(new_uid))
    goto error;

handle_conn(&to_addr, sizeof(struct sockaddr_un));

int handle_conn(struct sockaddr *to_addr, socklen_t addrlen) {
    int to_sock;
    int ret;
    pid_t pid;
    if( (to_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
            goto error;
    }
    if(connect(to_sock, to_addr, addrlen)) {
            close(to_sock);
            goto error;
    }

    ...                               

    close(to_sock);
}

Is there a way to allow the OS to implicitly generate the socket for my endpoint (i.e. the address to which the service will respond) but request that it be given certain permissions?

我通过两次调用 umask().

解决了这个问题

伪代码:

current_mask = umask(umask_to_be_used_on_afunix_socket_file_system_entry_creation);
bind afunix socket here
umask(current_umask);