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

时间:2015-07-24 20:42:51

标签: c linux sockets file-permissions unix-socket

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

事实证明,该服务没有足够的权限来写入为其提供的地址I(或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到特定地址,这是一个更难发现的问题,因为底层操作系统将隐式为用户生成此套接字 - 但它仍然存在且仍然将有相同的访问问题。

那么,我的问题就是最后一步。有没有办法允许操作系统隐式生成我的端点的套接字(即服务将响应的地址),但是请求给它一定的权限?

解释

此问题成为问题的原因是由于要求程序的其他部分以root身份执行。因此,当我作为root用户尝试connect / send到后台服务时,操作系统将隐式创建一个回复将被定向到的地址。但是,这会导致我的套接字文件无论是隐式的还是使用bind创建的,都具有srw- --- ---等权限,因此另一个端点只有在它们自身提升时才会回复。< / p>

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

2 个答案:

答案 0 :(得分:3)

  

有没有办法允许操作系统隐式生成我的端点的套接字(即服务将响应的地址),但是请求给它一定的权限?

我使用两次umask()调用解决了这个问题。

伪代码:

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

答案 1 :(得分:-1)

[编辑]我的第一个猜测是改为使用fifo,它允许你先创建文件并设置其权限。此外,如果两个用户要通过fifo进行通信,最好使用组级读/写并将它们放在同一组中。

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