1 /* $NetBSD: unfdpass.c,v 1.4 1999/01/21 09:54:23 mycroft Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Test passing of file descriptors and credentials over Unix domain sockets. 42 */ 43 44 #include <sys/param.h> 45 #include <sys/socket.h> 46 #include <sys/time.h> 47 #include <sys/wait.h> 48 #include <sys/un.h> 49 #include <sys/uio.h> 50 51 #include <err.h> 52 #include <errno.h> 53 #include <fcntl.h> 54 #include <signal.h> 55 #include <stdio.h> 56 #include <string.h> 57 #include <unistd.h> 58 59 #define SOCK_NAME "test-sock" 60 61 int main __P((int, char *[])); 62 void child __P((void)); 63 void catch_sigchld __P((int)); 64 65 #define FILE_SIZE 128 66 #define MSG_SIZE -1 67 #define NFILES 24 68 69 struct fdcmessage { 70 struct cmsghdr cm; 71 int files[NFILES]; 72 }; 73 74 struct crcmessage { 75 struct cmsghdr cm; 76 char creds[SOCKCREDSIZE(NGROUPS)]; 77 }; 78 79 /* ARGSUSED */ 80 int 81 main(argc, argv) 82 int argc; 83 char *argv[]; 84 { 85 #if MSG_SIZE >= 0 86 struct iovec iov; 87 #endif 88 struct msghdr msg; 89 int listensock, sock, fd, i, status; 90 char fname[16], buf[FILE_SIZE]; 91 struct cmsghdr *cmp; 92 struct { 93 struct fdcmessage fdcm; 94 struct crcmessage crcm; 95 } message; 96 int *files = NULL; 97 struct sockcred *sc = NULL; 98 struct sockaddr_un sun, csun; 99 int csunlen; 100 fd_set oob; 101 pid_t pid; 102 103 /* 104 * Create the test files. 105 */ 106 for (i = 0; i < NFILES; i++) { 107 (void) sprintf(fname, "file%d", i + 1); 108 if ((fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) 109 err(1, "open %s", fname); 110 (void) sprintf(buf, "This is file %d.\n", i + 1); 111 if (write(fd, buf, strlen(buf)) != strlen(buf)) 112 err(1, "write %s", fname); 113 (void) close(fd); 114 } 115 116 /* 117 * Create the listen socket. 118 */ 119 if ((listensock = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) 120 err(1, "socket"); 121 122 (void) unlink(SOCK_NAME); 123 (void) memset(&sun, 0, sizeof(sun)); 124 sun.sun_family = AF_LOCAL; 125 (void) strcpy(sun.sun_path, SOCK_NAME); 126 sun.sun_len = SUN_LEN(&sun); 127 128 i = 1; 129 if (setsockopt(listensock, 0, LOCAL_CREDS, &i, sizeof(i)) == -1) 130 err(1, "setsockopt"); 131 132 if (bind(listensock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 133 err(1, "bind"); 134 135 if (listen(listensock, 1) == -1) 136 err(1, "listen"); 137 138 /* 139 * Create the sender. 140 */ 141 (void) signal(SIGCHLD, catch_sigchld); 142 pid = fork(); 143 switch (pid) { 144 case -1: 145 err(1, "fork"); 146 /* NOTREACHED */ 147 148 case 0: 149 child(); 150 /* NOTREACHED */ 151 } 152 153 /* 154 * Wait for the sender to connect. 155 */ 156 if ((sock = accept(listensock, (struct sockaddr *)&csun, 157 &csunlen)) == -1) 158 err(1, "accept"); 159 160 /* 161 * Give sender a chance to run. We will get going again 162 * once the SIGCHLD arrives. 163 */ 164 (void) sleep(10); 165 166 /* 167 * Grab the descriptors and credentials passed to us. 168 */ 169 170 (void) memset(&msg, 0, sizeof(msg)); 171 msg.msg_control = (caddr_t) &message; 172 msg.msg_controllen = sizeof(message); 173 #if MSG_SIZE >= 0 174 iov.iov_base = buf; 175 iov.iov_len = MSG_SIZE; 176 msg.msg_iov = &iov; 177 msg.msg_iovlen = 1; 178 #endif 179 180 if (recvmsg(sock, &msg, 0) == -1) 181 err(1, "recvmsg"); 182 183 (void) close(sock); 184 185 if (msg.msg_controllen == 0) 186 errx(1, "no control messages received"); 187 188 if (msg.msg_flags & MSG_CTRUNC) 189 errx(1, "lost control message data"); 190 191 cmp = CMSG_FIRSTHDR(&msg); 192 for (cmp = CMSG_FIRSTHDR(&msg); cmp != NULL; 193 cmp = CMSG_NXTHDR(&msg, cmp)) { 194 if (cmp->cmsg_level != SOL_SOCKET) 195 errx(1, "bad control message level %d", 196 cmp->cmsg_level); 197 198 switch (cmp->cmsg_type) { 199 case SCM_RIGHTS: 200 if (cmp->cmsg_len != sizeof(message.fdcm)) 201 errx(1, "bad fd control message length"); 202 203 files = (int *)CMSG_DATA(cmp); 204 break; 205 206 case SCM_CREDS: 207 if (cmp->cmsg_len < sizeof(struct sockcred)) 208 errx(1, "bad cred control message length"); 209 210 sc = (struct sockcred *)CMSG_DATA(cmp); 211 break; 212 213 default: 214 errx(1, "unexpected control message"); 215 /* NOTREACHED */ 216 } 217 } 218 219 /* 220 * Read the files and print their contents. 221 */ 222 if (files == NULL) 223 warnx("didn't get fd control message"); 224 else { 225 for (i = 0; i < NFILES; i++) { 226 (void) memset(buf, 0, sizeof(buf)); 227 if (read(files[i], buf, sizeof(buf)) <= 0) 228 err(1, "read file %d", i + 1); 229 printf("%s", buf); 230 } 231 } 232 233 /* 234 * Double-check credentials. 235 */ 236 if (sc == NULL) 237 warnx("didn't get cred control message"); 238 else { 239 if (sc->sc_uid == getuid() && 240 sc->sc_euid == geteuid() && 241 sc->sc_gid == getgid() && 242 sc->sc_egid == getegid()) 243 printf("Credentials match.\n"); 244 else 245 printf("Credentials do NOT match.\n"); 246 } 247 248 /* 249 * All done! 250 */ 251 exit(0); 252 } 253 254 void 255 catch_sigchld(sig) 256 int sig; 257 { 258 int status; 259 260 (void) wait(&status); 261 } 262 263 void 264 child() 265 { 266 #if MSG_SIZE >= 0 267 struct iovec iov; 268 #endif 269 struct msghdr msg; 270 char fname[16], buf[FILE_SIZE]; 271 struct cmsghdr *cmp; 272 struct fdcmessage fdcm; 273 int i, fd, sock; 274 struct sockaddr_un sun; 275 276 /* 277 * Create socket and connect to the receiver. 278 */ 279 if ((sock = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) 280 errx(1, "child socket"); 281 282 (void) memset(&sun, 0, sizeof(sun)); 283 sun.sun_family = AF_LOCAL; 284 (void) strcpy(sun.sun_path, SOCK_NAME); 285 sun.sun_len = SUN_LEN(&sun); 286 287 if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 288 err(1, "child connect"); 289 290 /* 291 * Open the files again, and pass them to the child over the socket. 292 */ 293 for (i = 0; i < NFILES; i++) { 294 (void) sprintf(fname, "file%d", i + 1); 295 if ((fd = open(fname, O_RDONLY, 0666)) == -1) 296 err(1, "child open %s", fname); 297 fdcm.files[i] = fd; 298 } 299 300 (void) memset(&msg, 0, sizeof(msg)); 301 msg.msg_control = (caddr_t) &fdcm; 302 msg.msg_controllen = sizeof(fdcm); 303 #if MSG_SIZE >= 0 304 iov.iov_base = buf; 305 iov.iov_len = MSG_SIZE; 306 msg.msg_iov = &iov; 307 msg.msg_iovlen = 1; 308 #endif 309 310 cmp = CMSG_FIRSTHDR(&msg); 311 cmp->cmsg_len = sizeof(fdcm); 312 cmp->cmsg_level = SOL_SOCKET; 313 cmp->cmsg_type = SCM_RIGHTS; 314 315 if (sendmsg(sock, &msg, 0) == -1) 316 err(1, "child sendmsg"); 317 318 /* 319 * All done! 320 */ 321 exit(0); 322 } 323