1 /* $NetBSD: unfdpass.c,v 1.9 2008/02/29 16:28:12 ad Exp $ */
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
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.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * Test passing of file descriptors and credentials over Unix domain sockets.
37 #include <sys/param.h>
38 #include <sys/socket.h>
53 #define SOCK_NAME "test-sock"
55 int main(int, char *[]);
57 void catch_sigchld(int);
58 void usage(char *progname
);
64 #define FDCM_DATASIZE (sizeof(int) * NFILES)
65 #define CRCM_DATASIZE (SOCKCREDSIZE(NGROUPS))
67 #define MESSAGE_SIZE (CMSG_SPACE(FDCM_DATASIZE) + \
68 CMSG_SPACE(CRCM_DATASIZE))
72 int pass_root_dir
= 0;
87 char *progname
=argv
[0];
89 int listensock
, sock
, fd
, i
;
90 char fname
[16], buf
[FILE_SIZE
];
94 struct sockcred
*sc
= NULL
;
95 struct sockaddr_un sun
, csun
;
100 message
= malloc(CMSG_SPACE(MESSAGE_SIZE
));
102 err(1, "unable to malloc message buffer");
103 memset(message
, 0, CMSG_SPACE(MESSAGE_SIZE
));
105 while ((ch
= getopt(argc
, argv
, "DESdepr")) != -1) {
109 exit_early
++; /* test early GC */
113 exit_later
++; /* test later GC */
145 * Create the test files.
147 for (i
= 0; i
< NFILES
; i
++) {
148 (void) sprintf(fname
, "file%d", i
+ 1);
149 if ((fd
= open(fname
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666)) == -1)
150 err(1, "open %s", fname
);
151 (void) sprintf(buf
, "This is file %d.\n", i
+ 1);
152 if (write(fd
, buf
, strlen(buf
)) != strlen(buf
))
153 err(1, "write %s", fname
);
158 * Create the listen socket.
160 if ((listensock
= socket(PF_LOCAL
, SOCK_STREAM
, 0)) == -1)
163 (void) unlink(SOCK_NAME
);
164 (void) memset(&sun
, 0, sizeof(sun
));
165 sun
.sun_family
= AF_LOCAL
;
166 (void) strcpy(sun
.sun_path
, SOCK_NAME
);
167 sun
.sun_len
= SUN_LEN(&sun
);
170 if (setsockopt(listensock
, 0, LOCAL_CREDS
, &i
, sizeof(i
)) == -1)
171 err(1, "setsockopt");
173 if (bind(listensock
, (struct sockaddr
*)&sun
, sizeof(sun
)) == -1)
176 if (listen(listensock
, 1) == -1)
182 (void) signal(SIGCHLD
, catch_sigchld
);
202 * Wait for the sender to connect.
204 csunlen
= sizeof(csun
);
205 if ((sock
= accept(listensock
, (struct sockaddr
*)&csun
,
210 * Give sender a chance to run. We will get going again
211 * once the SIGCHLD arrives.
219 * Grab the descriptors and credentials passed to us.
222 /* Expect 2 messages; descriptors and creds. */
224 (void) memset(&msg
, 0, sizeof(msg
));
225 msg
.msg_control
= message
;
226 msg
.msg_controllen
= MESSAGE_SIZE
;
229 iov
.iov_len
= MSG_SIZE
;
234 if (recvmsg(sock
, &msg
, 0) == -1)
240 if (msg
.msg_controllen
== 0)
241 errx(1, "no control messages received");
243 if (msg
.msg_flags
& MSG_CTRUNC
)
244 errx(1, "lost control message data");
246 for (cmp
= CMSG_FIRSTHDR(&msg
); cmp
!= NULL
;
247 cmp
= CMSG_NXTHDR(&msg
, cmp
)) {
248 if (cmp
->cmsg_level
!= SOL_SOCKET
)
249 errx(1, "bad control message level %d",
252 switch (cmp
->cmsg_type
) {
254 if (cmp
->cmsg_len
!= CMSG_LEN(FDCM_DATASIZE
))
255 errx(1, "bad fd control message "
256 "length %d", cmp
->cmsg_len
);
258 files
= (int *)CMSG_DATA(cmp
);
262 if (cmp
->cmsg_len
< CMSG_LEN(SOCKCREDSIZE(1)))
263 errx(1, "bad cred control message "
264 "length %d", cmp
->cmsg_len
);
266 sc
= (struct sockcred
*)CMSG_DATA(cmp
);
270 errx(1, "unexpected control message");
276 * Read the files and print their contents.
279 warnx("didn't get fd control message");
281 for (i
= 0; i
< NFILES
; i
++) {
283 (void) memset(buf
, 0, sizeof(buf
));
284 fstat(files
[i
], &st
);
285 if (S_ISDIR(st
.st_mode
)) {
286 printf("file %d is a directory\n", i
+1);
287 } else if (S_ISSOCK(st
.st_mode
)) {
288 printf("file %d is a socket\n", i
+1);
292 c
= read (files
[i
], buf
, sizeof(buf
));
294 err(1, "read file %d", i
+ 1);
296 printf("[eof on %d]\n", i
+ 1);
303 * Double-check credentials.
306 warnx("didn't get cred control message");
308 if (sc
->sc_uid
== getuid() &&
309 sc
->sc_euid
== geteuid() &&
310 sc
->sc_gid
== getgid() &&
311 sc
->sc_egid
== getegid())
312 printf("Credentials match.\n");
314 printf("Credentials do NOT match.\n");
316 } while (sock
!= -1);
328 fprintf(stderr
, "usage: %s [-derDES]\n", progname
);
338 (void) wait(&status
);
351 int i
, fd
, sock
, nfd
, *files
;
352 struct sockaddr_un sun
;
355 fdcm
= malloc(CMSG_SPACE(FDCM_DATASIZE
));
357 err(1, "unable to malloc fd control message");
358 memset(fdcm
, 0, CMSG_SPACE(FDCM_DATASIZE
));
361 files
= (int *)CMSG_DATA(fdcm
);
364 * Create socket and connect to the receiver.
366 if ((sock
= socket(PF_LOCAL
, SOCK_STREAM
, 0)) == -1)
367 errx(1, "child socket");
369 (void) memset(&sun
, 0, sizeof(sun
));
370 sun
.sun_family
= AF_LOCAL
;
371 (void) strcpy(sun
.sun_path
, SOCK_NAME
);
372 sun
.sun_len
= SUN_LEN(&sun
);
374 if (connect(sock
, (struct sockaddr
*)&sun
, sizeof(sun
)) == -1)
375 err(1, "child connect");
388 * Open the files again, and pass them to the child
392 for (; i
< nfd
; i
++) {
393 (void) sprintf(fname
, "file%d", i
+ 1);
394 if ((fd
= open(fname
, O_RDONLY
, 0666)) == -1)
395 err(1, "child open %s", fname
);
400 char *dirname
= pass_root_dir
? "/" : ".";
403 if ((fd
= open(dirname
, O_RDONLY
, 0)) == -1) {
404 err(1, "child open directory %s", dirname
);
409 (void) memset(&msg
, 0, sizeof(msg
));
410 msg
.msg_control
= fdcm
;
411 msg
.msg_controllen
= CMSG_LEN(FDCM_DATASIZE
);
414 iov
.iov_len
= MSG_SIZE
;
419 cmp
= CMSG_FIRSTHDR(&msg
);
420 cmp
->cmsg_len
= CMSG_LEN(FDCM_DATASIZE
);
421 cmp
->cmsg_level
= SOL_SOCKET
;
422 cmp
->cmsg_type
= SCM_RIGHTS
;
424 while (make_pretzel
> 0) {
425 if (socketpair(PF_LOCAL
, SOCK_STREAM
, 0, spair
) < 0)
426 err(1, "socketpair");
428 printf("send pretzel\n");
429 if (sendmsg(spair
[0], &msg
, 0) < 0)
430 err(1, "child prezel sendmsg");
439 if (sendmsg(sock
, &msg
, 0) == -1)
440 err(1, "child sendmsg");