-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscm_rights.c
More file actions
103 lines (86 loc) · 2.52 KB
/
Copy pathscm_rights.c
File metadata and controls
103 lines (86 loc) · 2.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#define _GNU_SOURCE
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void send_fd(int sock, int fd)
{
char buf[1] = {0};
struct iovec iov = { .iov_base = buf, .iov_len = 1 };
union {
struct cmsghdr cm;
char ctrl[CMSG_SPACE(sizeof(int))];
} cmsg_buf;
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = cmsg_buf.ctrl,
.msg_controllen = sizeof(cmsg_buf.ctrl),
};
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
if (sendmsg(sock, &msg, 0) < 0) { perror("sendmsg"); exit(1); }
}
static int recv_fd(int sock)
{
char buf[1];
struct iovec iov = { .iov_base = buf, .iov_len = 1 };
union {
struct cmsghdr cm;
char ctrl[CMSG_SPACE(sizeof(int))];
} cmsg_buf;
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = cmsg_buf.ctrl,
.msg_controllen = sizeof(cmsg_buf.ctrl),
};
if (recvmsg(sock, &msg, 0) < 0) { perror("recvmsg"); exit(1); }
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
if (!cmsg || cmsg->cmsg_type != SCM_RIGHTS) {
fprintf(stderr, "no fd received\n"); exit(1);
}
int fd;
memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
return fd;
}
int main(void)
{
int sv[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
perror("socketpair"); return 1;
}
int orig = open("/etc/hostname", O_RDONLY);
if (orig < 0) { perror("open"); return 1; }
pid_t pid = fork();
if (pid < 0) { perror("fork"); return 1; }
if (pid == 0) {
/* child: receive the fd and read from it, no knowledge of path */
close(sv[0]);
close(orig);
int fd = recv_fd(sv[1]);
printf("[child] received fd %d\n", fd);
char rbuf[128] = {0};
ssize_t n = read(fd, rbuf, sizeof(rbuf) - 1);
if (n > 0) printf("[child] content: %s", rbuf);
close(fd);
close(sv[1]);
return 0;
}
/* parent: send the fd then close its own copy */
close(sv[1]);
send_fd(sv[0], orig);
printf("[parent] sent fd %d (/etc/hostname)\n", orig);
close(orig);
close(sv[0]);
int status;
waitpid(pid, &status, 0);
return 0;
}