unfdpass.c revision 1.1
1/* $NetBSD: unfdpass.c,v 1.3 1998/06/24 23:51:30 thorpej 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 <err.h> 50#include <errno.h> 51#include <fcntl.h> 52#include <signal.h> 53#include <stdio.h> 54#include <string.h> 55#include <unistd.h> 56 57#define SOCK_NAME "test-sock" 58 59int main __P((int, char *[])); 60void child __P((void)); 61void catch_sigchld __P((int)); 62 63struct fdcmessage { 64 struct cmsghdr cm; 65 int files[2]; 66}; 67 68struct crcmessage { 69 struct cmsghdr cm; 70 char creds[SOCKCREDSIZE(NGROUPS)]; 71}; 72 73/* ARGSUSED */ 74int 75main(argc, argv) 76 int argc; 77 char *argv[]; 78{ 79 struct msghdr msg; 80 int listensock, sock, fd, i, status; 81 char fname[16], buf[64]; 82 struct cmsghdr *cmp; 83 struct { 84 struct fdcmessage fdcm; 85 struct crcmessage crcm; 86 } message; 87 int *files = NULL; 88 struct sockcred *sc = NULL; 89 struct sockaddr_un sun, csun; 90 int csunlen; 91 fd_set oob; 92 pid_t pid; 93 94 /* 95 * Create the test files. 96 */ 97 for (i = 0; i < 2; i++) { 98 (void) sprintf(fname, "file%d", i + 1); 99 if ((fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) 100 err(1, "open %s", fname); 101 (void) sprintf(buf, "This is file %d.\n", i + 1); 102 if (write(fd, buf, strlen(buf)) != strlen(buf)) 103 err(1, "write %s", fname); 104 (void) close(fd); 105 } 106 107 /* 108 * Create the listen socket. 109 */ 110 if ((listensock = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) 111 err(1, "socket"); 112 113 (void) unlink(SOCK_NAME); 114 (void) memset(&sun, 0, sizeof(sun)); 115 sun.sun_family = AF_LOCAL; 116 (void) strcpy(sun.sun_path, SOCK_NAME); 117 sun.sun_len = SUN_LEN(&sun); 118 119 i = 1; 120 if (setsockopt(listensock, 0, LOCAL_CREDS, &i, sizeof(i)) == -1) 121 err(1, "setsockopt"); 122 123 if (bind(listensock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 124 err(1, "bind"); 125 126 if (listen(listensock, 1) == -1) 127 err(1, "listen"); 128 129 /* 130 * Create the sender. 131 */ 132 (void) signal(SIGCHLD, catch_sigchld); 133 pid = fork(); 134 switch (pid) { 135 case -1: 136 err(1, "fork"); 137 /* NOTREACHED */ 138 139 case 0: 140 child(); 141 /* NOTREACHED */ 142 } 143 144 /* 145 * Wait for the sender to connect. 146 */ 147 if ((sock = accept(listensock, (struct sockaddr *)&csun, 148 &csunlen)) == -1) 149 err(1, "accept"); 150 151 /* 152 * Give sender a chance to run. We will get going again 153 * once the SIGCHLD arrives. 154 */ 155 (void) sleep(10); 156 157 /* 158 * Grab the descriptors and credentials passed to us. 159 */ 160 (void) memset(&msg, 0, sizeof(msg)); 161 msg.msg_control = (caddr_t) &message; 162 msg.msg_controllen = sizeof(message); 163 164 if (recvmsg(sock, &msg, 0) < 0) 165 err(1, "recvmsg"); 166 167 (void) close(sock); 168 169 if (msg.msg_controllen == 0) 170 errx(1, "no control messages received"); 171 172 if (msg.msg_flags & MSG_CTRUNC) 173 errx(1, "lost control message data"); 174 175 cmp = CMSG_FIRSTHDR(&msg); 176 for (cmp = CMSG_FIRSTHDR(&msg); cmp != NULL; 177 cmp = CMSG_NXTHDR(&msg, cmp)) { 178 if (cmp->cmsg_level != SOL_SOCKET) 179 errx(1, "bad control message level %d", 180 cmp->cmsg_level); 181 182 switch (cmp->cmsg_type) { 183 case SCM_RIGHTS: 184 if (cmp->cmsg_len != sizeof(message.fdcm)) 185 errx(1, "bad fd control message length"); 186 187 files = (int *)CMSG_DATA(cmp); 188 break; 189 190 case SCM_CREDS: 191 if (cmp->cmsg_len < sizeof(struct sockcred)) 192 errx(1, "bad cred control message length"); 193 194 sc = (struct sockcred *)CMSG_DATA(cmp); 195 break; 196 197 default: 198 errx(1, "unexpected control message"); 199 /* NOTREACHED */ 200 } 201 } 202 203 /* 204 * Read the files and print their contents. 205 */ 206 if (files == NULL) 207 warnx("didn't get fd control message"); 208 else { 209 for (i = 0; i < 2; i++) { 210 (void) memset(buf, 0, sizeof(buf)); 211 if (read(files[i], buf, sizeof(buf)) <= 0) 212 err(1, "read file %d", i + 1); 213 printf("%s", buf); 214 } 215 } 216 217 /* 218 * Double-check credentials. 219 */ 220 if (sc == NULL) 221 warnx("didn't get cred control message"); 222 else { 223 if (sc->sc_uid == getuid() && 224 sc->sc_euid == geteuid() && 225 sc->sc_gid == getgid() && 226 sc->sc_egid == getegid()) 227 printf("Credentials match.\n"); 228 else 229 printf("Credentials do NOT match.\n"); 230 } 231 232 /* 233 * All done! 234 */ 235 exit(0); 236} 237 238void 239catch_sigchld(sig) 240 int sig; 241{ 242 int status; 243 244 (void) wait(&status); 245} 246 247void 248child() 249{ 250 struct msghdr msg; 251 char fname[16], buf[64]; 252 struct cmsghdr *cmp; 253 struct fdcmessage fdcm; 254 int i, fd, sock; 255 struct sockaddr_un sun; 256 257 /* 258 * Create socket and connect to the receiver. 259 */ 260 if ((sock = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) 261 errx(1, "child socket"); 262 263 (void) memset(&sun, 0, sizeof(sun)); 264 sun.sun_family = AF_LOCAL; 265 (void) strcpy(sun.sun_path, SOCK_NAME); 266 sun.sun_len = SUN_LEN(&sun); 267 268 if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 269 err(1, "child connect"); 270 271 /* 272 * Open the files again, and pass them to the child over the socket. 273 */ 274 for (i = 0; i < 2; i++) { 275 (void) sprintf(fname, "file%d", i + 1); 276 if ((fd = open(fname, O_RDONLY, 0666)) == -1) 277 err(1, "child open %s", fname); 278 fdcm.files[i] = fd; 279 } 280 281 (void) memset(&msg, 0, sizeof(msg)); 282 msg.msg_control = (caddr_t) &fdcm; 283 msg.msg_controllen = sizeof(fdcm); 284 285 cmp = CMSG_FIRSTHDR(&msg); 286 cmp->cmsg_len = sizeof(fdcm); 287 cmp->cmsg_level = SOL_SOCKET; 288 cmp->cmsg_type = SCM_RIGHTS; 289 290 if (sendmsg(sock, &msg, 0)) 291 err(1, "child sendmsg"); 292 293 /* 294 * All done! 295 */ 296 exit(0); 297} 298