Home | History | Annotate | Line # | Download | only in unfdpass
unfdpass.c revision 1.4
      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