Home | History | Annotate | Line # | Download | only in unfdpass
unfdpass.c revision 1.10.44.1
      1  1.10.44.1  pgoyette /*	$NetBSD: unfdpass.c,v 1.10.44.1 2017/03/20 06:57:01 pgoyette Exp $	*/
      2        1.1   thorpej 
      3        1.1   thorpej /*-
      4        1.1   thorpej  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5        1.1   thorpej  * All rights reserved.
      6        1.1   thorpej  *
      7        1.1   thorpej  * This code is derived from software contributed to The NetBSD Foundation
      8        1.1   thorpej  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      9        1.1   thorpej  * NASA Ames Research Center.
     10        1.1   thorpej  *
     11        1.1   thorpej  * Redistribution and use in source and binary forms, with or without
     12        1.1   thorpej  * modification, are permitted provided that the following conditions
     13        1.1   thorpej  * are met:
     14        1.1   thorpej  * 1. Redistributions of source code must retain the above copyright
     15        1.1   thorpej  *    notice, this list of conditions and the following disclaimer.
     16        1.1   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     17        1.1   thorpej  *    notice, this list of conditions and the following disclaimer in the
     18        1.1   thorpej  *    documentation and/or other materials provided with the distribution.
     19        1.1   thorpej  *
     20        1.1   thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21        1.1   thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22        1.1   thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23        1.1   thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24        1.1   thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25        1.1   thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26        1.1   thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27        1.1   thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28        1.1   thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29        1.1   thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30        1.1   thorpej  * POSSIBILITY OF SUCH DAMAGE.
     31        1.1   thorpej  */
     32        1.1   thorpej 
     33        1.1   thorpej /*
     34        1.2   thorpej  * Test passing of file descriptors and credentials over Unix domain sockets.
     35        1.1   thorpej  */
     36        1.1   thorpej 
     37        1.1   thorpej #include <sys/param.h>
     38        1.1   thorpej #include <sys/socket.h>
     39        1.1   thorpej #include <sys/time.h>
     40        1.1   thorpej #include <sys/wait.h>
     41        1.1   thorpej #include <sys/un.h>
     42        1.4   mycroft #include <sys/uio.h>
     43  1.10.44.1  pgoyette #include <sys/stat.h>
     44        1.4   mycroft 
     45        1.1   thorpej #include <err.h>
     46        1.2   thorpej #include <errno.h>
     47        1.1   thorpej #include <fcntl.h>
     48        1.2   thorpej #include <signal.h>
     49        1.1   thorpej #include <stdio.h>
     50        1.1   thorpej #include <string.h>
     51        1.6   thorpej #include <stdlib.h>
     52        1.1   thorpej #include <unistd.h>
     53        1.1   thorpej 
     54        1.2   thorpej #define	SOCK_NAME	"test-sock"
     55        1.1   thorpej 
     56        1.7     perry int	main(int, char *[]);
     57        1.7     perry void	child(void);
     58        1.7     perry void	catch_sigchld(int);
     59        1.7     perry void	usage(char *progname);
     60        1.1   thorpej 
     61        1.4   mycroft #define	FILE_SIZE	128
     62        1.4   mycroft #define	MSG_SIZE	-1
     63        1.4   mycroft #define	NFILES		24
     64        1.4   mycroft 
     65        1.6   thorpej #define	FDCM_DATASIZE	(sizeof(int) * NFILES)
     66        1.6   thorpej #define	CRCM_DATASIZE	(SOCKCREDSIZE(NGROUPS))
     67        1.6   thorpej 
     68        1.6   thorpej #define	MESSAGE_SIZE	(CMSG_SPACE(FDCM_DATASIZE) +			\
     69        1.6   thorpej 			 CMSG_SPACE(CRCM_DATASIZE))
     70        1.2   thorpej 
     71        1.5  sommerfe int chroot_rcvr = 0;
     72        1.5  sommerfe int pass_dir = 0;
     73        1.5  sommerfe int pass_root_dir = 0;
     74        1.5  sommerfe int exit_early = 0;
     75        1.5  sommerfe int exit_later = 0;
     76        1.5  sommerfe int pass_sock = 0;
     77        1.5  sommerfe int make_pretzel = 0;
     78        1.5  sommerfe 
     79        1.1   thorpej /* ARGSUSED */
     80        1.1   thorpej int
     81        1.1   thorpej main(argc, argv)
     82        1.1   thorpej 	int argc;
     83        1.1   thorpej 	char *argv[];
     84        1.1   thorpej {
     85        1.4   mycroft #if MSG_SIZE >= 0
     86        1.4   mycroft 	struct iovec iov;
     87        1.4   mycroft #endif
     88        1.5  sommerfe 	char *progname=argv[0];
     89        1.1   thorpej 	struct msghdr msg;
     90        1.6   thorpej 	int listensock, sock, fd, i;
     91        1.4   mycroft 	char fname[16], buf[FILE_SIZE];
     92        1.2   thorpej 	struct cmsghdr *cmp;
     93        1.6   thorpej 	void *message;
     94        1.2   thorpej 	int *files = NULL;
     95        1.2   thorpej 	struct sockcred *sc = NULL;
     96        1.2   thorpej 	struct sockaddr_un sun, csun;
     97        1.8       mrg 	socklen_t csunlen;
     98        1.1   thorpej 	pid_t pid;
     99        1.5  sommerfe 	int ch;
    100        1.6   thorpej 
    101        1.6   thorpej 	message = malloc(CMSG_SPACE(MESSAGE_SIZE));
    102        1.6   thorpej 	if (message == NULL)
    103        1.6   thorpej 		err(1, "unable to malloc message buffer");
    104        1.6   thorpej 	memset(message, 0, CMSG_SPACE(MESSAGE_SIZE));
    105        1.5  sommerfe 
    106        1.5  sommerfe 	while ((ch = getopt(argc, argv, "DESdepr")) != -1) {
    107        1.5  sommerfe 		switch(ch) {
    108        1.5  sommerfe 
    109        1.5  sommerfe 		case 'e':
    110        1.5  sommerfe 			exit_early++; /* test early GC */
    111        1.5  sommerfe 			break;
    112        1.5  sommerfe 
    113        1.5  sommerfe 		case 'E':
    114        1.5  sommerfe 			exit_later++; /* test later GC */
    115        1.5  sommerfe 			break;
    116        1.5  sommerfe 
    117        1.5  sommerfe 		case 'd':
    118        1.5  sommerfe 			pass_dir++;
    119        1.5  sommerfe 			break;
    120        1.5  sommerfe 
    121        1.5  sommerfe 		case 'D':
    122        1.5  sommerfe 			pass_dir++;
    123        1.5  sommerfe 			pass_root_dir++;
    124        1.5  sommerfe 			break;
    125        1.5  sommerfe 
    126        1.5  sommerfe 		case 'S':
    127        1.5  sommerfe 			pass_sock++;
    128        1.5  sommerfe 			break;
    129        1.5  sommerfe 
    130        1.5  sommerfe 		case 'r':
    131        1.5  sommerfe 			chroot_rcvr++;
    132        1.5  sommerfe 			break;
    133        1.5  sommerfe 
    134        1.5  sommerfe 		case 'p':
    135        1.5  sommerfe 			make_pretzel++;
    136        1.5  sommerfe 			break;
    137        1.5  sommerfe 
    138        1.5  sommerfe 		case '?':
    139        1.5  sommerfe 		default:
    140        1.5  sommerfe 			usage(progname);
    141        1.5  sommerfe 		}
    142        1.5  sommerfe 	}
    143        1.5  sommerfe 
    144        1.1   thorpej 
    145        1.1   thorpej 	/*
    146        1.1   thorpej 	 * Create the test files.
    147        1.1   thorpej 	 */
    148        1.4   mycroft 	for (i = 0; i < NFILES; i++) {
    149        1.1   thorpej 		(void) sprintf(fname, "file%d", i + 1);
    150        1.1   thorpej 		if ((fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1)
    151        1.1   thorpej 			err(1, "open %s", fname);
    152        1.1   thorpej 		(void) sprintf(buf, "This is file %d.\n", i + 1);
    153        1.1   thorpej 		if (write(fd, buf, strlen(buf)) != strlen(buf))
    154        1.1   thorpej 			err(1, "write %s", fname);
    155        1.1   thorpej 		(void) close(fd);
    156        1.1   thorpej 	}
    157        1.1   thorpej 
    158        1.1   thorpej 	/*
    159        1.2   thorpej 	 * Create the listen socket.
    160        1.1   thorpej 	 */
    161        1.3   thorpej 	if ((listensock = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1)
    162        1.2   thorpej 		err(1, "socket");
    163        1.2   thorpej 
    164        1.2   thorpej 	(void) unlink(SOCK_NAME);
    165        1.2   thorpej 	(void) memset(&sun, 0, sizeof(sun));
    166        1.2   thorpej 	sun.sun_family = AF_LOCAL;
    167        1.2   thorpej 	(void) strcpy(sun.sun_path, SOCK_NAME);
    168        1.2   thorpej 	sun.sun_len = SUN_LEN(&sun);
    169        1.2   thorpej 
    170        1.2   thorpej 	i = 1;
    171        1.2   thorpej 	if (setsockopt(listensock, 0, LOCAL_CREDS, &i, sizeof(i)) == -1)
    172        1.2   thorpej 		err(1, "setsockopt");
    173        1.2   thorpej 
    174        1.2   thorpej 	if (bind(listensock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
    175        1.2   thorpej 		err(1, "bind");
    176        1.2   thorpej 
    177        1.2   thorpej 	if (listen(listensock, 1) == -1)
    178        1.2   thorpej 		err(1, "listen");
    179        1.1   thorpej 
    180        1.2   thorpej 	/*
    181        1.2   thorpej 	 * Create the sender.
    182        1.2   thorpej 	 */
    183        1.2   thorpej 	(void) signal(SIGCHLD, catch_sigchld);
    184        1.1   thorpej 	pid = fork();
    185        1.1   thorpej 	switch (pid) {
    186        1.1   thorpej 	case -1:
    187        1.1   thorpej 		err(1, "fork");
    188        1.1   thorpej 		/* NOTREACHED */
    189        1.1   thorpej 
    190        1.1   thorpej 	case 0:
    191        1.1   thorpej 		child();
    192        1.1   thorpej 		/* NOTREACHED */
    193        1.1   thorpej 	}
    194        1.1   thorpej 
    195        1.5  sommerfe 	if (exit_early)
    196        1.5  sommerfe 		exit(0);
    197        1.5  sommerfe 
    198        1.5  sommerfe 	if (chroot_rcvr &&
    199        1.5  sommerfe 	    ((chroot(".") < 0)))
    200        1.5  sommerfe 		err(1, "chroot");
    201        1.5  sommerfe 
    202        1.2   thorpej 	/*
    203        1.2   thorpej 	 * Wait for the sender to connect.
    204        1.2   thorpej 	 */
    205        1.9        ad 	csunlen = sizeof(csun);
    206        1.2   thorpej 	if ((sock = accept(listensock, (struct sockaddr *)&csun,
    207        1.2   thorpej 	    &csunlen)) == -1)
    208        1.2   thorpej 		err(1, "accept");
    209        1.1   thorpej 
    210        1.1   thorpej 	/*
    211        1.2   thorpej 	 * Give sender a chance to run.  We will get going again
    212        1.2   thorpej 	 * once the SIGCHLD arrives.
    213        1.1   thorpej 	 */
    214        1.2   thorpej 	(void) sleep(10);
    215        1.1   thorpej 
    216        1.5  sommerfe 	if (exit_later)
    217        1.5  sommerfe 		exit(0);
    218        1.5  sommerfe 
    219        1.2   thorpej 	/*
    220        1.2   thorpej 	 * Grab the descriptors and credentials passed to us.
    221        1.2   thorpej 	 */
    222        1.4   mycroft 
    223        1.6   thorpej 	/* Expect 2 messages; descriptors and creds. */
    224        1.5  sommerfe 	do {
    225        1.5  sommerfe 		(void) memset(&msg, 0, sizeof(msg));
    226        1.6   thorpej 		msg.msg_control = message;
    227        1.6   thorpej 		msg.msg_controllen = MESSAGE_SIZE;
    228        1.4   mycroft #if MSG_SIZE >= 0
    229        1.5  sommerfe 		iov.iov_base = buf;
    230        1.5  sommerfe 		iov.iov_len = MSG_SIZE;
    231        1.5  sommerfe 		msg.msg_iov = &iov;
    232        1.5  sommerfe 		msg.msg_iovlen = 1;
    233        1.4   mycroft #endif
    234        1.2   thorpej 
    235        1.5  sommerfe 		if (recvmsg(sock, &msg, 0) == -1)
    236        1.5  sommerfe 			err(1, "recvmsg");
    237        1.5  sommerfe 
    238        1.5  sommerfe 		(void) close(sock);
    239        1.5  sommerfe 		sock = -1;
    240        1.2   thorpej 
    241        1.5  sommerfe 		if (msg.msg_controllen == 0)
    242        1.5  sommerfe 			errx(1, "no control messages received");
    243        1.2   thorpej 
    244        1.5  sommerfe 		if (msg.msg_flags & MSG_CTRUNC)
    245        1.5  sommerfe 			errx(1, "lost control message data");
    246        1.2   thorpej 
    247        1.5  sommerfe 		for (cmp = CMSG_FIRSTHDR(&msg); cmp != NULL;
    248        1.5  sommerfe 		     cmp = CMSG_NXTHDR(&msg, cmp)) {
    249        1.5  sommerfe 			if (cmp->cmsg_level != SOL_SOCKET)
    250        1.5  sommerfe 				errx(1, "bad control message level %d",
    251        1.5  sommerfe 				    cmp->cmsg_level);
    252        1.1   thorpej 
    253        1.5  sommerfe 			switch (cmp->cmsg_type) {
    254        1.5  sommerfe 			case SCM_RIGHTS:
    255        1.6   thorpej 				if (cmp->cmsg_len != CMSG_LEN(FDCM_DATASIZE))
    256        1.6   thorpej 					errx(1, "bad fd control message "
    257        1.6   thorpej 					    "length %d", cmp->cmsg_len);
    258        1.2   thorpej 
    259        1.5  sommerfe 				files = (int *)CMSG_DATA(cmp);
    260        1.5  sommerfe 				break;
    261        1.2   thorpej 
    262        1.5  sommerfe 			case SCM_CREDS:
    263        1.6   thorpej 				if (cmp->cmsg_len < CMSG_LEN(SOCKCREDSIZE(1)))
    264        1.6   thorpej 					errx(1, "bad cred control message "
    265        1.6   thorpej 					    "length %d", cmp->cmsg_len);
    266        1.2   thorpej 
    267        1.5  sommerfe 				sc = (struct sockcred *)CMSG_DATA(cmp);
    268        1.5  sommerfe 				break;
    269        1.2   thorpej 
    270        1.5  sommerfe 			default:
    271        1.5  sommerfe 				errx(1, "unexpected control message");
    272        1.5  sommerfe 				/* NOTREACHED */
    273        1.5  sommerfe 			}
    274        1.2   thorpej 		}
    275        1.1   thorpej 
    276        1.5  sommerfe 		/*
    277        1.5  sommerfe 		 * Read the files and print their contents.
    278        1.5  sommerfe 		 */
    279        1.5  sommerfe 		if (files == NULL)
    280        1.5  sommerfe 			warnx("didn't get fd control message");
    281        1.5  sommerfe 		else {
    282        1.5  sommerfe 			for (i = 0; i < NFILES; i++) {
    283        1.5  sommerfe 				struct stat st;
    284        1.5  sommerfe 				(void) memset(buf, 0, sizeof(buf));
    285        1.5  sommerfe 				fstat(files[i], &st);
    286        1.5  sommerfe 				if (S_ISDIR(st.st_mode)) {
    287        1.5  sommerfe 					printf("file %d is a directory\n", i+1);
    288        1.5  sommerfe 				} else if (S_ISSOCK(st.st_mode)) {
    289        1.5  sommerfe 					printf("file %d is a socket\n", i+1);
    290        1.5  sommerfe 					sock = files[i];
    291        1.5  sommerfe 				} else {
    292        1.5  sommerfe 					int c;
    293        1.5  sommerfe 					c = read (files[i], buf, sizeof(buf));
    294        1.5  sommerfe 					if (c < 0)
    295        1.5  sommerfe 						err(1, "read file %d", i + 1);
    296        1.5  sommerfe 					else if (c == 0)
    297        1.5  sommerfe 						printf("[eof on %d]\n", i + 1);
    298        1.5  sommerfe 					else
    299        1.5  sommerfe 						printf("%s", buf);
    300        1.5  sommerfe 				}
    301        1.5  sommerfe 			}
    302        1.5  sommerfe 		}
    303        1.5  sommerfe 		/*
    304        1.5  sommerfe 		 * Double-check credentials.
    305        1.5  sommerfe 		 */
    306        1.5  sommerfe 		if (sc == NULL)
    307        1.5  sommerfe 			warnx("didn't get cred control message");
    308        1.5  sommerfe 		else {
    309        1.5  sommerfe 			if (sc->sc_uid == getuid() &&
    310        1.5  sommerfe 			    sc->sc_euid == geteuid() &&
    311        1.5  sommerfe 			    sc->sc_gid == getgid() &&
    312        1.5  sommerfe 			    sc->sc_egid == getegid())
    313        1.5  sommerfe 				printf("Credentials match.\n");
    314        1.5  sommerfe 			else
    315        1.5  sommerfe 				printf("Credentials do NOT match.\n");
    316        1.2   thorpej 		}
    317        1.5  sommerfe 	} while (sock != -1);
    318        1.1   thorpej 
    319        1.2   thorpej 	/*
    320        1.2   thorpej 	 * All done!
    321        1.2   thorpej 	 */
    322        1.1   thorpej 	exit(0);
    323        1.1   thorpej }
    324        1.1   thorpej 
    325        1.1   thorpej void
    326        1.5  sommerfe usage(progname)
    327        1.5  sommerfe 	char *progname;
    328        1.5  sommerfe {
    329        1.5  sommerfe 	fprintf(stderr, "usage: %s [-derDES]\n", progname);
    330        1.5  sommerfe 	exit(1);
    331        1.5  sommerfe }
    332        1.5  sommerfe 
    333        1.5  sommerfe void
    334        1.2   thorpej catch_sigchld(sig)
    335        1.2   thorpej 	int sig;
    336        1.2   thorpej {
    337        1.2   thorpej 	int status;
    338        1.2   thorpej 
    339        1.2   thorpej 	(void) wait(&status);
    340        1.2   thorpej }
    341        1.2   thorpej 
    342        1.2   thorpej void
    343        1.1   thorpej child()
    344        1.1   thorpej {
    345        1.4   mycroft #if MSG_SIZE >= 0
    346        1.4   mycroft 	struct iovec iov;
    347        1.4   mycroft #endif
    348        1.1   thorpej 	struct msghdr msg;
    349        1.6   thorpej 	char fname[16];
    350        1.1   thorpej 	struct cmsghdr *cmp;
    351        1.6   thorpej 	void *fdcm;
    352        1.6   thorpej 	int i, fd, sock, nfd, *files;
    353        1.2   thorpej 	struct sockaddr_un sun;
    354        1.5  sommerfe 	int spair[2];
    355        1.6   thorpej 
    356        1.6   thorpej 	fdcm = malloc(CMSG_SPACE(FDCM_DATASIZE));
    357        1.6   thorpej 	if (fdcm == NULL)
    358        1.6   thorpej 		err(1, "unable to malloc fd control message");
    359        1.6   thorpej 	memset(fdcm, 0, CMSG_SPACE(FDCM_DATASIZE));
    360        1.6   thorpej 
    361        1.6   thorpej 	cmp = fdcm;
    362        1.6   thorpej 	files = (int *)CMSG_DATA(fdcm);
    363        1.6   thorpej 
    364        1.1   thorpej 	/*
    365        1.2   thorpej 	 * Create socket and connect to the receiver.
    366        1.1   thorpej 	 */
    367        1.3   thorpej 	if ((sock = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1)
    368        1.2   thorpej 		errx(1, "child socket");
    369        1.2   thorpej 
    370        1.2   thorpej 	(void) memset(&sun, 0, sizeof(sun));
    371        1.2   thorpej 	sun.sun_family = AF_LOCAL;
    372        1.2   thorpej 	(void) strcpy(sun.sun_path, SOCK_NAME);
    373        1.2   thorpej 	sun.sun_len = SUN_LEN(&sun);
    374        1.2   thorpej 
    375        1.2   thorpej 	if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
    376        1.2   thorpej 		err(1, "child connect");
    377        1.1   thorpej 
    378        1.5  sommerfe 	nfd = NFILES;
    379        1.5  sommerfe 	i = 0;
    380        1.5  sommerfe 
    381        1.5  sommerfe 	if (pass_sock) {
    382        1.6   thorpej 		files[i++] = sock;
    383        1.5  sommerfe 	}
    384        1.5  sommerfe 
    385        1.5  sommerfe 	if (pass_dir)
    386        1.5  sommerfe 		nfd--;
    387        1.5  sommerfe 
    388        1.1   thorpej 	/*
    389        1.5  sommerfe 	 * Open the files again, and pass them to the child
    390        1.5  sommerfe 	 * over the socket.
    391        1.1   thorpej 	 */
    392        1.5  sommerfe 
    393        1.5  sommerfe 	for (; i < nfd; i++) {
    394        1.2   thorpej 		(void) sprintf(fname, "file%d", i + 1);
    395        1.2   thorpej 		if ((fd = open(fname, O_RDONLY, 0666)) == -1)
    396        1.2   thorpej 			err(1, "child open %s", fname);
    397        1.6   thorpej 		files[i] = fd;
    398        1.2   thorpej 	}
    399        1.5  sommerfe 
    400        1.5  sommerfe 	if (pass_dir) {
    401        1.5  sommerfe 		char *dirname = pass_root_dir ? "/" : ".";
    402        1.5  sommerfe 
    403        1.5  sommerfe 
    404        1.5  sommerfe 		if ((fd = open(dirname, O_RDONLY, 0)) == -1) {
    405        1.5  sommerfe 			err(1, "child open directory %s", dirname);
    406        1.5  sommerfe 		}
    407        1.6   thorpej 		files[i] = fd;
    408        1.5  sommerfe 	}
    409        1.5  sommerfe 
    410        1.1   thorpej 	(void) memset(&msg, 0, sizeof(msg));
    411        1.6   thorpej 	msg.msg_control = fdcm;
    412        1.6   thorpej 	msg.msg_controllen = CMSG_LEN(FDCM_DATASIZE);
    413        1.4   mycroft #if MSG_SIZE >= 0
    414        1.4   mycroft 	iov.iov_base = buf;
    415        1.4   mycroft 	iov.iov_len = MSG_SIZE;
    416        1.4   mycroft 	msg.msg_iov = &iov;
    417        1.4   mycroft 	msg.msg_iovlen = 1;
    418        1.4   mycroft #endif
    419        1.1   thorpej 
    420        1.1   thorpej 	cmp = CMSG_FIRSTHDR(&msg);
    421        1.6   thorpej 	cmp->cmsg_len = CMSG_LEN(FDCM_DATASIZE);
    422        1.2   thorpej 	cmp->cmsg_level = SOL_SOCKET;
    423        1.2   thorpej 	cmp->cmsg_type = SCM_RIGHTS;
    424        1.5  sommerfe 
    425        1.5  sommerfe 	while (make_pretzel > 0) {
    426        1.5  sommerfe 		if (socketpair(PF_LOCAL, SOCK_STREAM, 0, spair) < 0)
    427        1.5  sommerfe 			err(1, "socketpair");
    428        1.5  sommerfe 
    429        1.5  sommerfe 		printf("send pretzel\n");
    430        1.5  sommerfe 		if (sendmsg(spair[0], &msg, 0) < 0)
    431        1.5  sommerfe 			err(1, "child prezel sendmsg");
    432        1.5  sommerfe 
    433        1.6   thorpej 		close(files[0]);
    434        1.6   thorpej 		close(files[1]);
    435        1.6   thorpej 		files[0] = spair[0];
    436        1.6   thorpej 		files[1] = spair[1];
    437        1.5  sommerfe 		make_pretzel--;
    438        1.5  sommerfe 	}
    439        1.1   thorpej 
    440        1.4   mycroft 	if (sendmsg(sock, &msg, 0) == -1)
    441        1.2   thorpej 		err(1, "child sendmsg");
    442        1.1   thorpej 
    443        1.1   thorpej 	/*
    444        1.1   thorpej 	 * All done!
    445        1.1   thorpej 	 */
    446        1.1   thorpej 	exit(0);
    447        1.1   thorpej }
    448