1 #include <sys/types.h> 2 #include <sys/socket.h> 3 #include <sys/stat.h> 4 #include <sys/un.h> 5 #include <sys/wait.h> 6 7 #include <err.h> 8 #include <stdint.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <unistd.h> 13 14 #define TEST_FILENAME "/tmp/passdesc" 15 16 static void 17 test_send_desc(int s, int fd) 18 { 19 struct msghdr msg; 20 struct iovec iov; 21 union { 22 struct cmsghdr cm; 23 uint8_t data[CMSG_SPACE(sizeof(int))]; 24 } ctrl; 25 struct cmsghdr *cm; 26 int n; 27 28 iov.iov_base = &fd; 29 iov.iov_len = sizeof(fd); 30 31 memset(&msg, 0, sizeof(msg)); 32 msg.msg_iov = &iov; 33 msg.msg_iovlen = 1; 34 msg.msg_control = ctrl.data; 35 msg.msg_controllen = sizeof(ctrl.data); 36 37 memset(&ctrl, 0, sizeof(ctrl)); 38 cm = CMSG_FIRSTHDR(&msg); 39 cm->cmsg_len = CMSG_LEN(sizeof(int)); 40 cm->cmsg_level = SOL_SOCKET; 41 cm->cmsg_type = SCM_RIGHTS; 42 *((int *)CMSG_DATA(cm)) = fd; 43 44 n = sendmsg(s, &msg, 0); 45 if (n < 0) 46 err(1, "sendmsg failed"); 47 else if (n != sizeof(fd)) 48 errx(1, "sendmsg sent %d", n); 49 close(fd); 50 } 51 52 static void 53 test_recv_desc(int s) 54 { 55 struct msghdr msg; 56 struct iovec iov; 57 union { 58 struct cmsghdr cm; 59 uint8_t data[CMSG_SPACE(sizeof(int))]; 60 } ctrl; 61 struct cmsghdr *cm; 62 int buf, n, fd; 63 char data[16]; 64 65 iov.iov_base = &buf; 66 iov.iov_len = sizeof(buf); 67 68 memset(&msg, 0, sizeof(msg)); 69 msg.msg_iov = &iov; 70 msg.msg_iovlen = 1; 71 msg.msg_control = ctrl.data; 72 msg.msg_controllen = sizeof(ctrl.data); 73 74 n = recvmsg(s, &msg, 0); 75 if (n < 0) 76 err(1, "recvmsg failed"); 77 else if (n != sizeof(buf)) 78 errx(1, "recvmsg received %d", n); 79 80 cm = CMSG_FIRSTHDR(&msg); 81 if (cm == NULL) 82 errx(1, "no cmsg"); 83 if (cm->cmsg_len != CMSG_LEN(sizeof(int))) 84 errx(1, "cmsg len mismatch"); 85 if (cm->cmsg_level != SOL_SOCKET) 86 errx(1, "cmsg level mismatch"); 87 if (cm->cmsg_type != SCM_RIGHTS) 88 errx(1, "cmsg type mismatch"); 89 90 fd = *((int *)CMSG_DATA(cm)); 91 92 n = read(fd, data, sizeof(data) - 1); 93 if (n < 0) 94 err(1, "read failed"); 95 data[n] = '\0'; 96 97 fprintf(stderr, "fd content: %s\n", data); 98 } 99 100 static void 101 usage(const char *cmd) 102 { 103 fprintf(stderr, "%s [-d]\n", cmd); 104 exit(1); 105 } 106 107 int 108 main(int argc, char *argv[]) 109 { 110 int s[2], fd, status, n, discard; 111 int opt; 112 off_t ofs; 113 114 discard = 0; 115 while ((opt = getopt(argc, argv, "d")) != -1) { 116 switch (opt) { 117 case 'd': 118 discard = 1; 119 break; 120 121 default: 122 usage(argv[0]); 123 } 124 } 125 126 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, s) < 0) 127 err(1, "socketpair(LOCAL, STREAM) failed"); 128 129 if (fork() == 0) { 130 close(s[0]); 131 if (!discard) 132 test_recv_desc(s[1]); 133 else 134 sleep(5); 135 exit(0); 136 } 137 close(s[1]); 138 139 fd = open(TEST_FILENAME, O_RDWR | O_TRUNC | O_CREAT, 140 S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); 141 if (fd < 0) 142 err(1, "open " TEST_FILENAME " failed"); 143 144 n = write(fd, TEST_FILENAME, strlen(TEST_FILENAME)); 145 if (n < 0) 146 err(1, "write failed"); 147 else if (n != strlen(TEST_FILENAME)) 148 errx(1, "write %d", n); 149 150 ofs = lseek(fd, 0, SEEK_SET); 151 if (ofs < 0) 152 err(1, "lseek failed"); 153 else if (ofs != 0) 154 errx(1, "lseek offset %jd", (intmax_t)ofs); 155 156 test_send_desc(s[0], fd); 157 158 wait(&status); 159 exit(0); 160 } 161