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