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] [-s]\n", cmd); 104 exit(1); 105 } 106 107 int 108 main(int argc, char *argv[]) 109 { 110 int s[2], fd, status, n, discard, skipfd; 111 int opt; 112 off_t ofs; 113 114 discard = 0; 115 skipfd = 0; 116 while ((opt = getopt(argc, argv, "ds")) != -1) { 117 switch (opt) { 118 case 'd': 119 discard = 1; 120 break; 121 122 case 's': 123 skipfd = 1; 124 break; 125 126 default: 127 usage(argv[0]); 128 } 129 } 130 131 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, s) < 0) 132 err(1, "socketpair(LOCAL, STREAM) failed"); 133 134 if (fork() == 0) { 135 close(s[0]); 136 if (!discard && !skipfd) { 137 test_recv_desc(s[1]); 138 } else if (skipfd) { 139 int buf; 140 141 fprintf(stderr, "skipfd\n"); 142 n = read(s[1], &buf, sizeof(buf)); 143 if (n < 0) 144 err(1, "read failed"); 145 } else { 146 fprintf(stderr, "discard msg\n"); 147 sleep(5); 148 } 149 exit(0); 150 } 151 close(s[1]); 152 153 fd = open(TEST_FILENAME, O_RDWR | O_TRUNC | O_CREAT, 154 S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); 155 if (fd < 0) 156 err(1, "open " TEST_FILENAME " failed"); 157 158 n = write(fd, TEST_FILENAME, strlen(TEST_FILENAME)); 159 if (n < 0) 160 err(1, "write failed"); 161 else if (n != strlen(TEST_FILENAME)) 162 errx(1, "write %d", n); 163 164 ofs = lseek(fd, 0, SEEK_SET); 165 if (ofs < 0) 166 err(1, "lseek failed"); 167 else if (ofs != 0) 168 errx(1, "lseek offset %jd", (intmax_t)ofs); 169 170 test_send_desc(s[0], fd); 171 172 wait(&status); 173 exit(0); 174 } 175