Home | History | Annotate | Line # | Download | only in unfdpass
unfdpass.c revision 1.3
      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 
     59 int	main __P((int, char *[]));
     60 void	child __P((void));
     61 void	catch_sigchld __P((int));
     62 
     63 struct fdcmessage {
     64 	struct cmsghdr cm;
     65 	int files[2];
     66 };
     67 
     68 struct crcmessage {
     69 	struct cmsghdr cm;
     70 	char creds[SOCKCREDSIZE(NGROUPS)];
     71 };
     72 
     73 /* ARGSUSED */
     74 int
     75 main(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 
    238 void
    239 catch_sigchld(sig)
    240 	int sig;
    241 {
    242 	int status;
    243 
    244 	(void) wait(&status);
    245 }
    246 
    247 void
    248 child()
    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