xref: /netbsd/regress/sys/kern/unfdpass/unfdpass.c (revision 09fbf839)
1*09fbf839Snia /*	$NetBSD: unfdpass.c,v 1.12 2021/08/08 20:54:48 nia Exp $	*/
21ca58a0fSthorpej 
31ca58a0fSthorpej /*-
41ca58a0fSthorpej  * Copyright (c) 1998 The NetBSD Foundation, Inc.
51ca58a0fSthorpej  * All rights reserved.
61ca58a0fSthorpej  *
71ca58a0fSthorpej  * This code is derived from software contributed to The NetBSD Foundation
81ca58a0fSthorpej  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
91ca58a0fSthorpej  * NASA Ames Research Center.
101ca58a0fSthorpej  *
111ca58a0fSthorpej  * Redistribution and use in source and binary forms, with or without
121ca58a0fSthorpej  * modification, are permitted provided that the following conditions
131ca58a0fSthorpej  * are met:
141ca58a0fSthorpej  * 1. Redistributions of source code must retain the above copyright
151ca58a0fSthorpej  *    notice, this list of conditions and the following disclaimer.
161ca58a0fSthorpej  * 2. Redistributions in binary form must reproduce the above copyright
171ca58a0fSthorpej  *    notice, this list of conditions and the following disclaimer in the
181ca58a0fSthorpej  *    documentation and/or other materials provided with the distribution.
191ca58a0fSthorpej  *
201ca58a0fSthorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
211ca58a0fSthorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
221ca58a0fSthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
231ca58a0fSthorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
241ca58a0fSthorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
251ca58a0fSthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
261ca58a0fSthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
271ca58a0fSthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
281ca58a0fSthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
291ca58a0fSthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
301ca58a0fSthorpej  * POSSIBILITY OF SUCH DAMAGE.
311ca58a0fSthorpej  */
321ca58a0fSthorpej 
331ca58a0fSthorpej /*
3481b7dbe9Sthorpej  * Test passing of file descriptors and credentials over Unix domain sockets.
351ca58a0fSthorpej  */
361ca58a0fSthorpej 
371ca58a0fSthorpej #include <sys/param.h>
381ca58a0fSthorpej #include <sys/socket.h>
391ca58a0fSthorpej #include <sys/time.h>
401ca58a0fSthorpej #include <sys/wait.h>
411ca58a0fSthorpej #include <sys/un.h>
42665d14aaSmycroft #include <sys/uio.h>
43bf689050Schristos #include <sys/stat.h>
44665d14aaSmycroft 
451ca58a0fSthorpej #include <err.h>
4681b7dbe9Sthorpej #include <errno.h>
471ca58a0fSthorpej #include <fcntl.h>
4881b7dbe9Sthorpej #include <signal.h>
491ca58a0fSthorpej #include <stdio.h>
501ca58a0fSthorpej #include <string.h>
51d20c2ec7Sthorpej #include <stdlib.h>
521ca58a0fSthorpej #include <unistd.h>
531ca58a0fSthorpej 
5481b7dbe9Sthorpej #define	SOCK_NAME	"test-sock"
551ca58a0fSthorpej 
56dd334ae5Sperry int	main(int, char *[]);
57dd334ae5Sperry void	child(void);
58dd334ae5Sperry void	catch_sigchld(int);
59dd334ae5Sperry void	usage(char *progname);
601ca58a0fSthorpej 
61665d14aaSmycroft #define	FILE_SIZE	128
62665d14aaSmycroft #define	MSG_SIZE	-1
63665d14aaSmycroft #define	NFILES		24
64665d14aaSmycroft 
65d20c2ec7Sthorpej #define	FDCM_DATASIZE	(sizeof(int) * NFILES)
66d20c2ec7Sthorpej #define	CRCM_DATASIZE	(SOCKCREDSIZE(NGROUPS))
671ca58a0fSthorpej 
68d20c2ec7Sthorpej #define	MESSAGE_SIZE	(CMSG_SPACE(FDCM_DATASIZE) +			\
69d20c2ec7Sthorpej 			 CMSG_SPACE(CRCM_DATASIZE))
7081b7dbe9Sthorpej 
719f81ab06Ssommerfe int chroot_rcvr = 0;
729f81ab06Ssommerfe int pass_dir = 0;
739f81ab06Ssommerfe int pass_root_dir = 0;
749f81ab06Ssommerfe int exit_early = 0;
759f81ab06Ssommerfe int exit_later = 0;
769f81ab06Ssommerfe int pass_sock = 0;
779f81ab06Ssommerfe int make_pretzel = 0;
789f81ab06Ssommerfe 
791ca58a0fSthorpej /* ARGSUSED */
801ca58a0fSthorpej int
main(argc,argv)811ca58a0fSthorpej main(argc, argv)
821ca58a0fSthorpej 	int argc;
831ca58a0fSthorpej 	char *argv[];
841ca58a0fSthorpej {
85665d14aaSmycroft #if MSG_SIZE >= 0
86665d14aaSmycroft 	struct iovec iov;
87665d14aaSmycroft #endif
889f81ab06Ssommerfe 	char *progname=argv[0];
891ca58a0fSthorpej 	struct msghdr msg;
90d20c2ec7Sthorpej 	int listensock, sock, fd, i;
91665d14aaSmycroft 	char fname[16], buf[FILE_SIZE];
921ca58a0fSthorpej 	struct cmsghdr *cmp;
93d20c2ec7Sthorpej 	void *message;
9481b7dbe9Sthorpej 	int *files = NULL;
9581b7dbe9Sthorpej 	struct sockcred *sc = NULL;
9681b7dbe9Sthorpej 	struct sockaddr_un sun, csun;
9737d2b2a6Smrg 	socklen_t csunlen;
9881b7dbe9Sthorpej 	pid_t pid;
999f81ab06Ssommerfe 	int ch;
1009f81ab06Ssommerfe 
101d20c2ec7Sthorpej 	message = malloc(CMSG_SPACE(MESSAGE_SIZE));
102d20c2ec7Sthorpej 	if (message == NULL)
103d20c2ec7Sthorpej 		err(1, "unable to malloc message buffer");
104d20c2ec7Sthorpej 	memset(message, 0, CMSG_SPACE(MESSAGE_SIZE));
1059f81ab06Ssommerfe 
1069f81ab06Ssommerfe 	while ((ch = getopt(argc, argv, "DESdepr")) != -1) {
1079f81ab06Ssommerfe 		switch(ch) {
1089f81ab06Ssommerfe 
1099f81ab06Ssommerfe 		case 'e':
1109f81ab06Ssommerfe 			exit_early++; /* test early GC */
1119f81ab06Ssommerfe 			break;
1129f81ab06Ssommerfe 
1139f81ab06Ssommerfe 		case 'E':
1149f81ab06Ssommerfe 			exit_later++; /* test later GC */
1159f81ab06Ssommerfe 			break;
1169f81ab06Ssommerfe 
1179f81ab06Ssommerfe 		case 'd':
1189f81ab06Ssommerfe 			pass_dir++;
1199f81ab06Ssommerfe 			break;
1209f81ab06Ssommerfe 
1219f81ab06Ssommerfe 		case 'D':
1229f81ab06Ssommerfe 			pass_dir++;
1239f81ab06Ssommerfe 			pass_root_dir++;
1249f81ab06Ssommerfe 			break;
1259f81ab06Ssommerfe 
1269f81ab06Ssommerfe 		case 'S':
1279f81ab06Ssommerfe 			pass_sock++;
1289f81ab06Ssommerfe 			break;
1299f81ab06Ssommerfe 
1309f81ab06Ssommerfe 		case 'r':
1319f81ab06Ssommerfe 			chroot_rcvr++;
1329f81ab06Ssommerfe 			break;
1339f81ab06Ssommerfe 
1349f81ab06Ssommerfe 		case 'p':
1359f81ab06Ssommerfe 			make_pretzel++;
1369f81ab06Ssommerfe 			break;
1379f81ab06Ssommerfe 
1389f81ab06Ssommerfe 		case '?':
1399f81ab06Ssommerfe 		default:
1409f81ab06Ssommerfe 			usage(progname);
1419f81ab06Ssommerfe 		}
1429f81ab06Ssommerfe 	}
1439f81ab06Ssommerfe 
1441ca58a0fSthorpej 
1451ca58a0fSthorpej 	/*
1461ca58a0fSthorpej 	 * Create the test files.
1471ca58a0fSthorpej 	 */
148665d14aaSmycroft 	for (i = 0; i < NFILES; i++) {
1491ca58a0fSthorpej 		(void) sprintf(fname, "file%d", i + 1);
1501ca58a0fSthorpej 		if ((fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1)
1511ca58a0fSthorpej 			err(1, "open %s", fname);
1521ca58a0fSthorpej 		(void) sprintf(buf, "This is file %d.\n", i + 1);
1531ca58a0fSthorpej 		if (write(fd, buf, strlen(buf)) != strlen(buf))
1541ca58a0fSthorpej 			err(1, "write %s", fname);
1551ca58a0fSthorpej 		(void) close(fd);
1561ca58a0fSthorpej 	}
1571ca58a0fSthorpej 
1581ca58a0fSthorpej 	/*
15981b7dbe9Sthorpej 	 * Create the listen socket.
1601ca58a0fSthorpej 	 */
161d7b0b872Sthorpej 	if ((listensock = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1)
16281b7dbe9Sthorpej 		err(1, "socket");
1631ca58a0fSthorpej 
16481b7dbe9Sthorpej 	(void) unlink(SOCK_NAME);
16581b7dbe9Sthorpej 	(void) memset(&sun, 0, sizeof(sun));
16681b7dbe9Sthorpej 	sun.sun_family = AF_LOCAL;
16781b7dbe9Sthorpej 	(void) strcpy(sun.sun_path, SOCK_NAME);
16881b7dbe9Sthorpej 	sun.sun_len = SUN_LEN(&sun);
16981b7dbe9Sthorpej 
17081b7dbe9Sthorpej 	i = 1;
171*09fbf839Snia 	if (setsockopt(listensock, SOL_LOCAL, LOCAL_CREDS, &i, sizeof(i)) == -1)
17281b7dbe9Sthorpej 		err(1, "setsockopt");
17381b7dbe9Sthorpej 
17481b7dbe9Sthorpej 	if (bind(listensock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
17581b7dbe9Sthorpej 		err(1, "bind");
17681b7dbe9Sthorpej 
17781b7dbe9Sthorpej 	if (listen(listensock, 1) == -1)
17881b7dbe9Sthorpej 		err(1, "listen");
17981b7dbe9Sthorpej 
18081b7dbe9Sthorpej 	/*
18181b7dbe9Sthorpej 	 * Create the sender.
18281b7dbe9Sthorpej 	 */
18381b7dbe9Sthorpej 	(void) signal(SIGCHLD, catch_sigchld);
1841ca58a0fSthorpej 	pid = fork();
1851ca58a0fSthorpej 	switch (pid) {
1861ca58a0fSthorpej 	case -1:
1871ca58a0fSthorpej 		err(1, "fork");
1881ca58a0fSthorpej 		/* NOTREACHED */
1891ca58a0fSthorpej 
1901ca58a0fSthorpej 	case 0:
1911ca58a0fSthorpej 		child();
1921ca58a0fSthorpej 		/* NOTREACHED */
1931ca58a0fSthorpej 	}
1941ca58a0fSthorpej 
1959f81ab06Ssommerfe 	if (exit_early)
1969f81ab06Ssommerfe 		exit(0);
1979f81ab06Ssommerfe 
1989f81ab06Ssommerfe 	if (chroot_rcvr &&
1999f81ab06Ssommerfe 	    ((chroot(".") < 0)))
2009f81ab06Ssommerfe 		err(1, "chroot");
2019f81ab06Ssommerfe 
20281b7dbe9Sthorpej 	/*
20381b7dbe9Sthorpej 	 * Wait for the sender to connect.
20481b7dbe9Sthorpej 	 */
205e6ac0b80Sad 	csunlen = sizeof(csun);
20681b7dbe9Sthorpej 	if ((sock = accept(listensock, (struct sockaddr *)&csun,
20781b7dbe9Sthorpej 	    &csunlen)) == -1)
20881b7dbe9Sthorpej 		err(1, "accept");
20981b7dbe9Sthorpej 
21081b7dbe9Sthorpej 	/*
21181b7dbe9Sthorpej 	 * Give sender a chance to run.  We will get going again
21281b7dbe9Sthorpej 	 * once the SIGCHLD arrives.
21381b7dbe9Sthorpej 	 */
21481b7dbe9Sthorpej 	(void) sleep(10);
21581b7dbe9Sthorpej 
2169f81ab06Ssommerfe 	if (exit_later)
2179f81ab06Ssommerfe 		exit(0);
2189f81ab06Ssommerfe 
21981b7dbe9Sthorpej 	/*
22081b7dbe9Sthorpej 	 * Grab the descriptors and credentials passed to us.
22181b7dbe9Sthorpej 	 */
222665d14aaSmycroft 
223d20c2ec7Sthorpej 	/* Expect 2 messages; descriptors and creds. */
2249f81ab06Ssommerfe 	do {
22581b7dbe9Sthorpej 		(void) memset(&msg, 0, sizeof(msg));
226d20c2ec7Sthorpej 		msg.msg_control = message;
227d20c2ec7Sthorpej 		msg.msg_controllen = MESSAGE_SIZE;
228665d14aaSmycroft #if MSG_SIZE >= 0
229665d14aaSmycroft 		iov.iov_base = buf;
230665d14aaSmycroft 		iov.iov_len = MSG_SIZE;
231665d14aaSmycroft 		msg.msg_iov = &iov;
232665d14aaSmycroft 		msg.msg_iovlen = 1;
233665d14aaSmycroft #endif
23481b7dbe9Sthorpej 
235665d14aaSmycroft 		if (recvmsg(sock, &msg, 0) == -1)
23681b7dbe9Sthorpej 			err(1, "recvmsg");
23781b7dbe9Sthorpej 
23881b7dbe9Sthorpej 		(void) close(sock);
2399f81ab06Ssommerfe 		sock = -1;
2409f81ab06Ssommerfe 
24181b7dbe9Sthorpej 		if (msg.msg_controllen == 0)
24281b7dbe9Sthorpej 			errx(1, "no control messages received");
24381b7dbe9Sthorpej 
24481b7dbe9Sthorpej 		if (msg.msg_flags & MSG_CTRUNC)
24581b7dbe9Sthorpej 			errx(1, "lost control message data");
24681b7dbe9Sthorpej 
24781b7dbe9Sthorpej 		for (cmp = CMSG_FIRSTHDR(&msg); cmp != NULL;
24881b7dbe9Sthorpej 		     cmp = CMSG_NXTHDR(&msg, cmp)) {
24981b7dbe9Sthorpej 			if (cmp->cmsg_level != SOL_SOCKET)
25081b7dbe9Sthorpej 				errx(1, "bad control message level %d",
25181b7dbe9Sthorpej 				    cmp->cmsg_level);
25281b7dbe9Sthorpej 
25381b7dbe9Sthorpej 			switch (cmp->cmsg_type) {
25481b7dbe9Sthorpej 			case SCM_RIGHTS:
255d20c2ec7Sthorpej 				if (cmp->cmsg_len != CMSG_LEN(FDCM_DATASIZE))
256d20c2ec7Sthorpej 					errx(1, "bad fd control message "
257d20c2ec7Sthorpej 					    "length %d", cmp->cmsg_len);
25881b7dbe9Sthorpej 
25981b7dbe9Sthorpej 				files = (int *)CMSG_DATA(cmp);
26081b7dbe9Sthorpej 				break;
26181b7dbe9Sthorpej 
26281b7dbe9Sthorpej 			case SCM_CREDS:
263d20c2ec7Sthorpej 				if (cmp->cmsg_len < CMSG_LEN(SOCKCREDSIZE(1)))
264d20c2ec7Sthorpej 					errx(1, "bad cred control message "
265d20c2ec7Sthorpej 					    "length %d", cmp->cmsg_len);
26681b7dbe9Sthorpej 
26781b7dbe9Sthorpej 				sc = (struct sockcred *)CMSG_DATA(cmp);
26881b7dbe9Sthorpej 				break;
26981b7dbe9Sthorpej 
27081b7dbe9Sthorpej 			default:
27181b7dbe9Sthorpej 				errx(1, "unexpected control message");
27281b7dbe9Sthorpej 				/* NOTREACHED */
27381b7dbe9Sthorpej 			}
27481b7dbe9Sthorpej 		}
27581b7dbe9Sthorpej 
27681b7dbe9Sthorpej 		/*
27781b7dbe9Sthorpej 		 * Read the files and print their contents.
27881b7dbe9Sthorpej 		 */
27981b7dbe9Sthorpej 		if (files == NULL)
28081b7dbe9Sthorpej 			warnx("didn't get fd control message");
28181b7dbe9Sthorpej 		else {
282665d14aaSmycroft 			for (i = 0; i < NFILES; i++) {
2839f81ab06Ssommerfe 				struct stat st;
28481b7dbe9Sthorpej 				(void) memset(buf, 0, sizeof(buf));
2859f81ab06Ssommerfe 				fstat(files[i], &st);
2869f81ab06Ssommerfe 				if (S_ISDIR(st.st_mode)) {
2879f81ab06Ssommerfe 					printf("file %d is a directory\n", i+1);
2889f81ab06Ssommerfe 				} else if (S_ISSOCK(st.st_mode)) {
2899f81ab06Ssommerfe 					printf("file %d is a socket\n", i+1);
2909f81ab06Ssommerfe 					sock = files[i];
2919f81ab06Ssommerfe 				} else {
2929f81ab06Ssommerfe 					int c;
2939f81ab06Ssommerfe 					c = read (files[i], buf, sizeof(buf));
2949f81ab06Ssommerfe 					if (c < 0)
29581b7dbe9Sthorpej 						err(1, "read file %d", i + 1);
2969f81ab06Ssommerfe 					else if (c == 0)
2979f81ab06Ssommerfe 						printf("[eof on %d]\n", i + 1);
2989f81ab06Ssommerfe 					else
29981b7dbe9Sthorpej 						printf("%s", buf);
30081b7dbe9Sthorpej 				}
30181b7dbe9Sthorpej 			}
3029f81ab06Ssommerfe 		}
30381b7dbe9Sthorpej 		/*
30481b7dbe9Sthorpej 		 * Double-check credentials.
30581b7dbe9Sthorpej 		 */
30681b7dbe9Sthorpej 		if (sc == NULL)
30781b7dbe9Sthorpej 			warnx("didn't get cred control message");
30881b7dbe9Sthorpej 		else {
30981b7dbe9Sthorpej 			if (sc->sc_uid == getuid() &&
31081b7dbe9Sthorpej 			    sc->sc_euid == geteuid() &&
31181b7dbe9Sthorpej 			    sc->sc_gid == getgid() &&
31281b7dbe9Sthorpej 			    sc->sc_egid == getegid())
31381b7dbe9Sthorpej 				printf("Credentials match.\n");
31481b7dbe9Sthorpej 			else
31581b7dbe9Sthorpej 				printf("Credentials do NOT match.\n");
31681b7dbe9Sthorpej 		}
3179f81ab06Ssommerfe 	} while (sock != -1);
3189f81ab06Ssommerfe 
31981b7dbe9Sthorpej 	/*
32081b7dbe9Sthorpej 	 * All done!
32181b7dbe9Sthorpej 	 */
32281b7dbe9Sthorpej 	exit(0);
32381b7dbe9Sthorpej }
32481b7dbe9Sthorpej 
32581b7dbe9Sthorpej void
usage(progname)3269f81ab06Ssommerfe usage(progname)
3279f81ab06Ssommerfe 	char *progname;
3289f81ab06Ssommerfe {
3299f81ab06Ssommerfe 	fprintf(stderr, "usage: %s [-derDES]\n", progname);
3309f81ab06Ssommerfe 	exit(1);
3319f81ab06Ssommerfe }
3329f81ab06Ssommerfe 
3339f81ab06Ssommerfe void
catch_sigchld(sig)33481b7dbe9Sthorpej catch_sigchld(sig)
33581b7dbe9Sthorpej 	int sig;
33681b7dbe9Sthorpej {
33781b7dbe9Sthorpej 	int status;
33881b7dbe9Sthorpej 
33981b7dbe9Sthorpej 	(void) wait(&status);
34081b7dbe9Sthorpej }
34181b7dbe9Sthorpej 
34281b7dbe9Sthorpej void
child()34381b7dbe9Sthorpej child()
34481b7dbe9Sthorpej {
345665d14aaSmycroft #if MSG_SIZE >= 0
346665d14aaSmycroft 	struct iovec iov;
347665d14aaSmycroft #endif
34881b7dbe9Sthorpej 	struct msghdr msg;
349d20c2ec7Sthorpej 	char fname[16];
35081b7dbe9Sthorpej 	struct cmsghdr *cmp;
351d20c2ec7Sthorpej 	void *fdcm;
352d20c2ec7Sthorpej 	int i, fd, sock, nfd, *files;
35381b7dbe9Sthorpej 	struct sockaddr_un sun;
3549f81ab06Ssommerfe 	int spair[2];
35581b7dbe9Sthorpej 
356d20c2ec7Sthorpej 	fdcm = malloc(CMSG_SPACE(FDCM_DATASIZE));
357d20c2ec7Sthorpej 	if (fdcm == NULL)
358d20c2ec7Sthorpej 		err(1, "unable to malloc fd control message");
359d20c2ec7Sthorpej 	memset(fdcm, 0, CMSG_SPACE(FDCM_DATASIZE));
360d20c2ec7Sthorpej 
361d20c2ec7Sthorpej 	cmp = fdcm;
362d20c2ec7Sthorpej 	files = (int *)CMSG_DATA(fdcm);
363d20c2ec7Sthorpej 
36481b7dbe9Sthorpej 	/*
36581b7dbe9Sthorpej 	 * Create socket and connect to the receiver.
36681b7dbe9Sthorpej 	 */
367d7b0b872Sthorpej 	if ((sock = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1)
36881b7dbe9Sthorpej 		errx(1, "child socket");
36981b7dbe9Sthorpej 
37081b7dbe9Sthorpej 	(void) memset(&sun, 0, sizeof(sun));
37181b7dbe9Sthorpej 	sun.sun_family = AF_LOCAL;
37281b7dbe9Sthorpej 	(void) strcpy(sun.sun_path, SOCK_NAME);
37381b7dbe9Sthorpej 	sun.sun_len = SUN_LEN(&sun);
37481b7dbe9Sthorpej 
37581b7dbe9Sthorpej 	if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
37681b7dbe9Sthorpej 		err(1, "child connect");
3771ca58a0fSthorpej 
3789f81ab06Ssommerfe 	nfd = NFILES;
3799f81ab06Ssommerfe 	i = 0;
3809f81ab06Ssommerfe 
3819f81ab06Ssommerfe 	if (pass_sock) {
382d20c2ec7Sthorpej 		files[i++] = sock;
3839f81ab06Ssommerfe 	}
3849f81ab06Ssommerfe 
3859f81ab06Ssommerfe 	if (pass_dir)
3869f81ab06Ssommerfe 		nfd--;
3879f81ab06Ssommerfe 
3881ca58a0fSthorpej 	/*
3899f81ab06Ssommerfe 	 * Open the files again, and pass them to the child
3909f81ab06Ssommerfe 	 * over the socket.
3911ca58a0fSthorpej 	 */
3929f81ab06Ssommerfe 
3939f81ab06Ssommerfe 	for (; i < nfd; i++) {
3941ca58a0fSthorpej 		(void) sprintf(fname, "file%d", i + 1);
3951ca58a0fSthorpej 		if ((fd = open(fname, O_RDONLY, 0666)) == -1)
39681b7dbe9Sthorpej 			err(1, "child open %s", fname);
397d20c2ec7Sthorpej 		files[i] = fd;
3981ca58a0fSthorpej 	}
3991ca58a0fSthorpej 
4009f81ab06Ssommerfe 	if (pass_dir) {
4019f81ab06Ssommerfe 		char *dirname = pass_root_dir ? "/" : ".";
4029f81ab06Ssommerfe 
4039f81ab06Ssommerfe 
4049f81ab06Ssommerfe 		if ((fd = open(dirname, O_RDONLY, 0)) == -1) {
4059f81ab06Ssommerfe 			err(1, "child open directory %s", dirname);
4069f81ab06Ssommerfe 		}
407d20c2ec7Sthorpej 		files[i] = fd;
4089f81ab06Ssommerfe 	}
4099f81ab06Ssommerfe 
4101ca58a0fSthorpej 	(void) memset(&msg, 0, sizeof(msg));
411d20c2ec7Sthorpej 	msg.msg_control = fdcm;
412d20c2ec7Sthorpej 	msg.msg_controllen = CMSG_LEN(FDCM_DATASIZE);
413665d14aaSmycroft #if MSG_SIZE >= 0
414665d14aaSmycroft 	iov.iov_base = buf;
415665d14aaSmycroft 	iov.iov_len = MSG_SIZE;
416665d14aaSmycroft 	msg.msg_iov = &iov;
417665d14aaSmycroft 	msg.msg_iovlen = 1;
418665d14aaSmycroft #endif
4191ca58a0fSthorpej 
4201ca58a0fSthorpej 	cmp = CMSG_FIRSTHDR(&msg);
421d20c2ec7Sthorpej 	cmp->cmsg_len = CMSG_LEN(FDCM_DATASIZE);
4221ca58a0fSthorpej 	cmp->cmsg_level = SOL_SOCKET;
4231ca58a0fSthorpej 	cmp->cmsg_type = SCM_RIGHTS;
4241ca58a0fSthorpej 
4259f81ab06Ssommerfe 	while (make_pretzel > 0) {
4269f81ab06Ssommerfe 		if (socketpair(PF_LOCAL, SOCK_STREAM, 0, spair) < 0)
4279f81ab06Ssommerfe 			err(1, "socketpair");
4289f81ab06Ssommerfe 
4299f81ab06Ssommerfe 		printf("send pretzel\n");
4309f81ab06Ssommerfe 		if (sendmsg(spair[0], &msg, 0) < 0)
4319f81ab06Ssommerfe 			err(1, "child prezel sendmsg");
4329f81ab06Ssommerfe 
433d20c2ec7Sthorpej 		close(files[0]);
434d20c2ec7Sthorpej 		close(files[1]);
435d20c2ec7Sthorpej 		files[0] = spair[0];
436d20c2ec7Sthorpej 		files[1] = spair[1];
4379f81ab06Ssommerfe 		make_pretzel--;
4389f81ab06Ssommerfe 	}
4399f81ab06Ssommerfe 
440665d14aaSmycroft 	if (sendmsg(sock, &msg, 0) == -1)
44181b7dbe9Sthorpej 		err(1, "child sendmsg");
4421ca58a0fSthorpej 
4431ca58a0fSthorpej 	/*
4441ca58a0fSthorpej 	 * All done!
4451ca58a0fSthorpej 	 */
4461ca58a0fSthorpej 	exit(0);
4471ca58a0fSthorpej }
448