xref: /minix/minix/tests/test56.c (revision 27852ebe)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc  * Test Program for Unix Domain Sockets
3433d6423SLionel Sambuc  *
4433d6423SLionel Sambuc  * Overview: This program tests Unix Domain Sockets. It attempts
5433d6423SLionel Sambuc  * to exercise the functions associated with Unix Domain Sockets.
6433d6423SLionel Sambuc  * It also attempts to make sure all of the functions which handle
7433d6423SLionel Sambuc  * file/socket descriptors work correctly when given a socket
8433d6423SLionel Sambuc  * descriptor for a Unix domain socket. It also implicitly checks
9433d6423SLionel Sambuc  * for the existance of constants like AF_UNIX and structures like
10433d6423SLionel Sambuc  * sockaddr_un (it won't compile if they aren't defined). Besides
11433d6423SLionel Sambuc  * checking that the sockets work properly, this test program also
12433d6423SLionel Sambuc  * checks that the errors returned conform to the POSIX 2008
13433d6423SLionel Sambuc  * standards. Some tests are omitted as they could adversely affect
14433d6423SLionel Sambuc  * the operation of the host system. For example, implementing a test
15433d6423SLionel Sambuc  * for socket() failing with errno = ENFILE would require using up all
16433d6423SLionel Sambuc  * of the file descriptors supported by the OS (defined in
17433d6423SLionel Sambuc  * /proc/sys/fs/file-max on Linux); this could cause problems for
18433d6423SLionel Sambuc  * daemons and other processes running on the system. Some tests are
19433d6423SLionel Sambuc  * omitted because they would require changes to libc or the kernel.
20433d6423SLionel Sambuc  * For example, getting EINTR would require  delaying the system call
21433d6423SLionel Sambuc  * execution time long enough to raise a signal to interupt it. Some
22433d6423SLionel Sambuc  * tests were omitted because the particular errors cannot occur when
23433d6423SLionel Sambuc  * using Unix domain sockets. For example, write() will never fail with
24433d6423SLionel Sambuc  * ENETDOWN because Unix domain sockets don't use network interfaces.
25433d6423SLionel Sambuc  *
26433d6423SLionel Sambuc  * Structure: Some functions can be tested or partially tested without
27433d6423SLionel Sambuc  * making a connection, socket() for example. These have test
28433d6423SLionel Sambuc  * functions like test_NAME(). The functionality that needs two way
29433d6423SLionel Sambuc  * communication is contained within test_xfer().
30433d6423SLionel Sambuc  *
31433d6423SLionel Sambuc  * Functions Tested: accept(), bind(), close(), connect(), dup(),
32433d6423SLionel Sambuc  * dup2(), fstat(), getpeername(), getsockname(), getsockopt(),
33433d6423SLionel Sambuc  * listen(), read(), readv(), recv(), recvfrom(), recvmsg(), select(),
34433d6423SLionel Sambuc  * send(), sendmsg(), sendto(), setsockopt(), shutdown(), socket(),
35433d6423SLionel Sambuc  * socketpair(), write(), writev()
36433d6423SLionel Sambuc  */
37433d6423SLionel Sambuc 
38433d6423SLionel Sambuc #include <ctype.h>
39433d6423SLionel Sambuc #include <errno.h>
40433d6423SLionel Sambuc #include <fcntl.h>
41433d6423SLionel Sambuc #include <signal.h>
42433d6423SLionel Sambuc #include <stdio.h>
43433d6423SLionel Sambuc #include <stdlib.h>
44433d6423SLionel Sambuc #include <string.h>
4546271349SDavid van Moolenbroek #include <stddef.h>
46433d6423SLionel Sambuc #include <sys/socket.h>
47433d6423SLionel Sambuc #include <sys/ucred.h>
48433d6423SLionel Sambuc #include <sys/stat.h>
49433d6423SLionel Sambuc #include <sys/time.h>
50433d6423SLionel Sambuc #include <sys/types.h>
51433d6423SLionel Sambuc #include <sys/uio.h>
52433d6423SLionel Sambuc #include <sys/un.h>
53433d6423SLionel Sambuc #include <sys/wait.h>
54433d6423SLionel Sambuc #include <time.h>
55433d6423SLionel Sambuc #include <unistd.h>
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc /* Maximum number of errors that we'll allow to occur before this test
58433d6423SLionel Sambuc  * program gives us and quits.
59433d6423SLionel Sambuc  */
60433d6423SLionel Sambuc int max_error = 4;
61433d6423SLionel Sambuc #include "common.h"
62294d1590SErik van der Kouwe #include "common-socket.h"
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc 
65433d6423SLionel Sambuc /* Use the common testing code instead of reinventing the wheel. */
66433d6423SLionel Sambuc 
67433d6423SLionel Sambuc /* path of the unix domain socket */
68433d6423SLionel Sambuc #define TEST_SUN_PATH "test.sock"
69433d6423SLionel Sambuc #define TEST_SUN_PATHB "testb.sock"
70433d6423SLionel Sambuc 
71433d6423SLionel Sambuc /* filenames for symlinks -- we link these to each other to test ELOOP .*/
72433d6423SLionel Sambuc #define TEST_SYM_A "test.a"
73433d6423SLionel Sambuc #define TEST_SYM_B "test.b"
74433d6423SLionel Sambuc 
75433d6423SLionel Sambuc /* text file and test phrase for testing file descriptor passing */
76433d6423SLionel Sambuc #define TEST_TXT_FILE "test.txt"
77433d6423SLionel Sambuc #define MSG "This raccoon loves to eat bugs.\n"
78433d6423SLionel Sambuc 
79433d6423SLionel Sambuc /* socket types supported */
80cbc8a0dfSDavid van Moolenbroek static int types[3] = {SOCK_STREAM, SOCK_SEQPACKET, SOCK_DGRAM};
81433d6423SLionel Sambuc 
test_header(void)82cbc8a0dfSDavid van Moolenbroek static void test_header(void)
83433d6423SLionel Sambuc {
84433d6423SLionel Sambuc 	struct sockaddr_un sun;
85433d6423SLionel Sambuc 	debug("entering test_header()");
86433d6423SLionel Sambuc 
87433d6423SLionel Sambuc 	sun.sun_family = AF_UNIX;
88433d6423SLionel Sambuc 	sun.sun_path[0] = 'x';
89433d6423SLionel Sambuc 	sun.sun_path[1] = 'x';
90433d6423SLionel Sambuc 	sun.sun_path[2] = 'x';
91433d6423SLionel Sambuc 	sun.sun_path[3] = '\0';
92433d6423SLionel Sambuc 
93433d6423SLionel Sambuc 	if (SUN_LEN(&sun) != 5) {
94433d6423SLionel Sambuc 		test_fail("SUN_LEN(&sun) should be 5");
95433d6423SLionel Sambuc 	}
96433d6423SLionel Sambuc 
97433d6423SLionel Sambuc 	if (PF_UNIX != PF_LOCAL || PF_UNIX != AF_UNIX) {
98433d6423SLionel Sambuc 		test_fail("PF_UNIX, PF_LOCAL and AF_UNIX");
99433d6423SLionel Sambuc 	}
100433d6423SLionel Sambuc }
101433d6423SLionel Sambuc 
test_socketpair(void)102cbc8a0dfSDavid van Moolenbroek static void test_socketpair(void)
103433d6423SLionel Sambuc {
104433d6423SLionel Sambuc 	char buf[128];
105433d6423SLionel Sambuc 	struct sockaddr_un addr;
106433d6423SLionel Sambuc 	int socket_vector[2];
107433d6423SLionel Sambuc 	int rc;
108433d6423SLionel Sambuc 	int i;
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc 	debug("entering test_socketpair()");
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc 	UNLINK(TEST_SUN_PATH);
113433d6423SLionel Sambuc 	memset(&addr, '\0', sizeof(struct sockaddr_un));
114433d6423SLionel Sambuc 	addr.sun_family = AF_UNIX;
115433d6423SLionel Sambuc 	strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
116433d6423SLionel Sambuc 
117433d6423SLionel Sambuc 	debug("Testing socketpair() success");
118433d6423SLionel Sambuc 
119433d6423SLionel Sambuc 	rc = socketpair(PF_UNIX, SOCK_STREAM, 0, socket_vector);
120433d6423SLionel Sambuc 	if (rc == -1) {
121433d6423SLionel Sambuc 		test_fail("socketpair() should have worked");
122433d6423SLionel Sambuc 	}
123433d6423SLionel Sambuc 
124433d6423SLionel Sambuc 	debug("Testing a simple read/write using sockets from socketpair()");
125433d6423SLionel Sambuc 	memset(buf, '\0', sizeof(buf));
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc 	strncpy(buf, "Howdy Partner", sizeof(buf) - 1);
128433d6423SLionel Sambuc 
129433d6423SLionel Sambuc 	rc = write(socket_vector[0], buf, sizeof(buf));
130433d6423SLionel Sambuc 	if (rc == -1) {
131433d6423SLionel Sambuc 		test_fail("write(sd, buf, sizeof(buf)) failed unexpectedly");
132433d6423SLionel Sambuc 	}
133433d6423SLionel Sambuc 
134433d6423SLionel Sambuc 	memset(buf, '\0', sizeof(buf));
135433d6423SLionel Sambuc 
136433d6423SLionel Sambuc 	rc = read(socket_vector[1], buf, sizeof(buf));
137433d6423SLionel Sambuc 	if (rc == -1) {
138433d6423SLionel Sambuc 		test_fail("read() failed unexpectedly");
139433d6423SLionel Sambuc 	}
140433d6423SLionel Sambuc 
141433d6423SLionel Sambuc 	if (strncmp(buf, "Howdy Partner", strlen("Howdy Partner")) != 0) {
142433d6423SLionel Sambuc 		test_fail("We did not read what we wrote");
143433d6423SLionel Sambuc 	}
144433d6423SLionel Sambuc 
145433d6423SLionel Sambuc 	CLOSE(socket_vector[0]);
146433d6423SLionel Sambuc 	CLOSE(socket_vector[1]);
147433d6423SLionel Sambuc 
148433d6423SLionel Sambuc 	debug("Test socketpair() with all FDs open by this process");
149433d6423SLionel Sambuc 
150433d6423SLionel Sambuc 	for (i = 3; i < getdtablesize(); i++) {
151433d6423SLionel Sambuc 		rc = open("/dev/null", O_RDONLY);
152433d6423SLionel Sambuc 		if (rc == -1) {
153433d6423SLionel Sambuc 			test_fail("we couldn't open /dev/null for read");
154433d6423SLionel Sambuc 		}
155433d6423SLionel Sambuc 	}
156433d6423SLionel Sambuc 
157433d6423SLionel Sambuc 	rc = socketpair(PF_UNIX, SOCK_STREAM, 0, socket_vector);
158433d6423SLionel Sambuc 	if (!(rc == -1 && errno == EMFILE)) {
159433d6423SLionel Sambuc 		test_fail("socketpair() should have failed with EMFILE");
160433d6423SLionel Sambuc 	}
161433d6423SLionel Sambuc 
162433d6423SLionel Sambuc 	for (i = 3; i < getdtablesize(); i++) {
163433d6423SLionel Sambuc 		CLOSE(i);
164433d6423SLionel Sambuc 	}
165433d6423SLionel Sambuc 
166433d6423SLionel Sambuc 	rc = socketpair(PF_UNIX, SOCK_STREAM, 4, socket_vector);
167433d6423SLionel Sambuc 	if (!(rc == -1 && errno == EPROTONOSUPPORT)) {
168433d6423SLionel Sambuc 		test_fail("socketpair() should have failed");
169433d6423SLionel Sambuc 	}
170433d6423SLionel Sambuc 
171433d6423SLionel Sambuc 	debug("leaving test_socketpair()");
172433d6423SLionel Sambuc }
173433d6423SLionel Sambuc 
test_ucred(void)174cbc8a0dfSDavid van Moolenbroek static void test_ucred(void)
175433d6423SLionel Sambuc {
176*27852ebeSDavid van Moolenbroek 	struct unpcbid credentials;
177433d6423SLionel Sambuc 	socklen_t ucred_length;
178433d6423SLionel Sambuc 	uid_t euid = geteuid();
179433d6423SLionel Sambuc 	gid_t egid = getegid();
180433d6423SLionel Sambuc 	int sv[2];
181433d6423SLionel Sambuc 	int rc;
182433d6423SLionel Sambuc 
183*27852ebeSDavid van Moolenbroek 	debug("Test peer credentials");
184433d6423SLionel Sambuc 
185*27852ebeSDavid van Moolenbroek 	ucred_length = sizeof(credentials);
186433d6423SLionel Sambuc 
187433d6423SLionel Sambuc 	rc = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
188433d6423SLionel Sambuc 	if (rc == -1) {
189433d6423SLionel Sambuc 		test_fail("socketpair(PF_UNIX, SOCK_STREAM, 0, sv) failed");
190433d6423SLionel Sambuc 	}
191433d6423SLionel Sambuc 
192433d6423SLionel Sambuc 	memset(&credentials, '\0', ucred_length);
193*27852ebeSDavid van Moolenbroek 	rc = getsockopt(sv[0], 0, LOCAL_PEEREID, &credentials,
194433d6423SLionel Sambuc 							&ucred_length);
195433d6423SLionel Sambuc 	if (rc == -1) {
196*27852ebeSDavid van Moolenbroek 		test_fail("getsockopt(LOCAL_PEEREID) failed");
197*27852ebeSDavid van Moolenbroek 	} else if (credentials.unp_pid != getpid() ||
198*27852ebeSDavid van Moolenbroek 			credentials.unp_euid != geteuid() ||
199*27852ebeSDavid van Moolenbroek 			credentials.unp_egid != getegid()) {
200*27852ebeSDavid van Moolenbroek 		printf("%d=%d %d=%d %d=%d",credentials.unp_pid, getpid(),
201*27852ebeSDavid van Moolenbroek 		    credentials.unp_euid, geteuid(),
202*27852ebeSDavid van Moolenbroek 		    credentials.unp_egid, getegid());
203433d6423SLionel Sambuc 		test_fail("Credential passing gave us the wrong cred");
204433d6423SLionel Sambuc 	}
205433d6423SLionel Sambuc 
206433d6423SLionel Sambuc 	rc = getpeereid(sv[0], &euid, &egid);
207433d6423SLionel Sambuc 	if (rc == -1) {
208433d6423SLionel Sambuc 		test_fail("getpeereid(sv[0], &euid, &egid) failed");
209*27852ebeSDavid van Moolenbroek 	} else if (credentials.unp_euid != euid ||
210*27852ebeSDavid van Moolenbroek 	    credentials.unp_egid != egid) {
211433d6423SLionel Sambuc 		test_fail("getpeereid() didn't give the correct euid/egid");
212433d6423SLionel Sambuc 	}
213433d6423SLionel Sambuc 
214433d6423SLionel Sambuc 	CLOSE(sv[0]);
215433d6423SLionel Sambuc 	CLOSE(sv[1]);
216433d6423SLionel Sambuc }
217433d6423SLionel Sambuc 
callback_check_sockaddr(const struct sockaddr * sockaddr,socklen_t sockaddrlen,const char * callname,int addridx)218294d1590SErik van der Kouwe static void callback_check_sockaddr(const struct sockaddr *sockaddr,
219294d1590SErik van der Kouwe 	socklen_t sockaddrlen, const char *callname, int addridx) {
220294d1590SErik van der Kouwe 	char buf[256];
221294d1590SErik van der Kouwe 	const char *path;
222294d1590SErik van der Kouwe 	const struct sockaddr_un *sockaddr_un =
223294d1590SErik van der Kouwe 		(const struct sockaddr_un *) sockaddr;
224433d6423SLionel Sambuc 
225294d1590SErik van der Kouwe 	switch (addridx) {
226294d1590SErik van der Kouwe 	case 1: path = TEST_SUN_PATH; break;
227294d1590SErik van der Kouwe 	case 2: path = TEST_SUN_PATHB; break;
228294d1590SErik van der Kouwe 	default:
229294d1590SErik van der Kouwe 		fprintf(stderr, "error: invalid addridx %d in "
230294d1590SErik van der Kouwe 			"callback_check_sockaddr\n", addridx);
231294d1590SErik van der Kouwe 		abort();
232433d6423SLionel Sambuc 	}
233433d6423SLionel Sambuc 
234294d1590SErik van der Kouwe 	if (!(sockaddr_un->sun_family == AF_UNIX &&
235294d1590SErik van der Kouwe 			strncmp(sockaddr_un->sun_path,
236*27852ebeSDavid van Moolenbroek 			path,
237294d1590SErik van der Kouwe 			sizeof(sockaddr_un->sun_path) - 1) == 0)) {
238433d6423SLionel Sambuc 
239294d1590SErik van der Kouwe 		snprintf(buf, sizeof(buf), "%s() didn't return the right addr",
240294d1590SErik van der Kouwe 			callname);
241294d1590SErik van der Kouwe 		test_fail(buf);
242294d1590SErik van der Kouwe 		fprintf(stderr, "exp: '%s' | got: '%s'\n", path,
243294d1590SErik van der Kouwe 			sockaddr_un->sun_path);
244294d1590SErik van der Kouwe 	}
245433d6423SLionel Sambuc }
246433d6423SLionel Sambuc 
callback_cleanup(void)247294d1590SErik van der Kouwe static void callback_cleanup(void) {
248294d1590SErik van der Kouwe 	UNLINK(TEST_SUN_PATH);
249294d1590SErik van der Kouwe 	UNLINK(TEST_SUN_PATHB);
250294d1590SErik van der Kouwe 	UNLINK(TEST_SYM_A);
251294d1590SErik van der Kouwe 	UNLINK(TEST_SYM_B);
252433d6423SLionel Sambuc }
253433d6423SLionel Sambuc 
test_bind_unix(void)254294d1590SErik van der Kouwe static void test_bind_unix(void)
255433d6423SLionel Sambuc {
256433d6423SLionel Sambuc 	struct sockaddr_un addr;
257433d6423SLionel Sambuc 	int sd;
258433d6423SLionel Sambuc 	int rc;
259433d6423SLionel Sambuc 
260294d1590SErik van der Kouwe 	debug("entering test_bind_unix()");
261433d6423SLionel Sambuc 	UNLINK(TEST_SUN_PATH);
262433d6423SLionel Sambuc 	memset(&addr, '\0', sizeof(struct sockaddr_un));
263433d6423SLionel Sambuc 	addr.sun_family = AF_UNIX;
264433d6423SLionel Sambuc 	strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
265433d6423SLionel Sambuc 
266433d6423SLionel Sambuc 	debug("Test bind() with an empty sun_path");
267433d6423SLionel Sambuc 
268433d6423SLionel Sambuc 	SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
269433d6423SLionel Sambuc 	memset(addr.sun_path, '\0', sizeof(addr.sun_path));
270433d6423SLionel Sambuc 	errno = 0;
271433d6423SLionel Sambuc 
272433d6423SLionel Sambuc 	rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
273433d6423SLionel Sambuc 	if (!(rc == -1 && errno == ENOENT)) {
274433d6423SLionel Sambuc 		test_fail("bind() should have failed with ENOENT");
275433d6423SLionel Sambuc 	}
276433d6423SLionel Sambuc 	CLOSE(sd);
277433d6423SLionel Sambuc 
278433d6423SLionel Sambuc 	debug("Test bind() using a symlink loop");
279433d6423SLionel Sambuc 
280433d6423SLionel Sambuc 	UNLINK(TEST_SUN_PATH);
281433d6423SLionel Sambuc 	UNLINK(TEST_SYM_A);
282433d6423SLionel Sambuc 	UNLINK(TEST_SYM_B);
283433d6423SLionel Sambuc 
284433d6423SLionel Sambuc 	SYMLINK(TEST_SYM_B, TEST_SYM_A);
285433d6423SLionel Sambuc 
286433d6423SLionel Sambuc 	SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
287433d6423SLionel Sambuc 
288433d6423SLionel Sambuc 	strncpy(addr.sun_path, TEST_SYM_A, sizeof(addr.sun_path) - 1);
289433d6423SLionel Sambuc 	errno = 0;
290433d6423SLionel Sambuc 	rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
291*27852ebeSDavid van Moolenbroek 	if (!((rc == -1) && (errno == EADDRINUSE))) {
292*27852ebeSDavid van Moolenbroek 		test_fail("bind() should have failed with EADDRINUSE");
293*27852ebeSDavid van Moolenbroek 	}
294*27852ebeSDavid van Moolenbroek 	CLOSE(sd);
295*27852ebeSDavid van Moolenbroek 
296*27852ebeSDavid van Moolenbroek 	SYMLINK(TEST_SYM_A, TEST_SYM_B);
297*27852ebeSDavid van Moolenbroek 
298*27852ebeSDavid van Moolenbroek 	SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
299*27852ebeSDavid van Moolenbroek 
300*27852ebeSDavid van Moolenbroek 	strncpy(addr.sun_path, TEST_SYM_A, sizeof(addr.sun_path) - 1);
301*27852ebeSDavid van Moolenbroek 	strlcat(addr.sun_path, "/x", sizeof(addr.sun_path));
302*27852ebeSDavid van Moolenbroek 	errno = 0;
303*27852ebeSDavid van Moolenbroek 	rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
304433d6423SLionel Sambuc 	if (!((rc == -1) && (errno == ELOOP))) {
305433d6423SLionel Sambuc 		test_fail("bind() should have failed with ELOOP");
306433d6423SLionel Sambuc 	}
307433d6423SLionel Sambuc 	CLOSE(sd);
308433d6423SLionel Sambuc 
309433d6423SLionel Sambuc 	UNLINK(TEST_SUN_PATH);
310433d6423SLionel Sambuc 	UNLINK(TEST_SYM_A);
311433d6423SLionel Sambuc 	UNLINK(TEST_SYM_B);
312433d6423SLionel Sambuc 
313433d6423SLionel Sambuc 	/* Test bind with garbage in sockaddr_un */
314433d6423SLionel Sambuc 	memset(&addr, '?', sizeof(struct sockaddr_un));
315433d6423SLionel Sambuc 	addr.sun_family = AF_UNIX;
316433d6423SLionel Sambuc 	addr.sun_path[0] = 'f';
317433d6423SLionel Sambuc 	addr.sun_path[1] = 'o';
318433d6423SLionel Sambuc 	addr.sun_path[2] = 'o';
319433d6423SLionel Sambuc 	addr.sun_path[3] = '\0';
320433d6423SLionel Sambuc 	SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
321c38dbb97SDavid van Moolenbroek 	rc = bind(sd, (struct sockaddr *) &addr,
322c38dbb97SDavid van Moolenbroek 	    offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path) +
323c38dbb97SDavid van Moolenbroek 	    1);
324433d6423SLionel Sambuc 	if (rc == -1) {
325433d6423SLionel Sambuc 		test_fail("bind() should have worked");
326433d6423SLionel Sambuc 	}
327433d6423SLionel Sambuc 	CLOSE(sd);
328433d6423SLionel Sambuc 	UNLINK("foo");
329433d6423SLionel Sambuc 
330294d1590SErik van der Kouwe 	debug("leaving test_bind_unix()");
331433d6423SLionel Sambuc }
332433d6423SLionel Sambuc 
callback_xfer_prepclient(void)333294d1590SErik van der Kouwe static void callback_xfer_prepclient(void) {
334433d6423SLionel Sambuc 	debug("Creating symlink to TEST_SUN_PATH");
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc 	SYMLINK(TEST_SUN_PATH, TEST_SYM_A);
337433d6423SLionel Sambuc }
338433d6423SLionel Sambuc 
callback_xfer_peercred(int sd)339294d1590SErik van der Kouwe static void callback_xfer_peercred(int sd) {
340*27852ebeSDavid van Moolenbroek 	struct unpcbid credentials;
341294d1590SErik van der Kouwe 	int rc;
342294d1590SErik van der Kouwe 	socklen_t ucred_length;
343433d6423SLionel Sambuc 
344*27852ebeSDavid van Moolenbroek 	ucred_length = sizeof(credentials);
345433d6423SLionel Sambuc 
346*27852ebeSDavid van Moolenbroek 	debug("Test obtaining the peer credentials");
347433d6423SLionel Sambuc 
348433d6423SLionel Sambuc 	memset(&credentials, '\0', ucred_length);
349*27852ebeSDavid van Moolenbroek 	rc = getsockopt(sd, 0, LOCAL_PEEREID, &credentials, &ucred_length);
350433d6423SLionel Sambuc 
351433d6423SLionel Sambuc 	if (rc == -1) {
352433d6423SLionel Sambuc 		test_fail("[client] getsockopt() failed");
353*27852ebeSDavid van Moolenbroek 	} else if (credentials.unp_euid != geteuid() ||
354*27852ebeSDavid van Moolenbroek 	    credentials.unp_egid != getegid()) {
355*27852ebeSDavid van Moolenbroek 		printf("%d=* %d=%d %d=%d", credentials.unp_pid,
356*27852ebeSDavid van Moolenbroek 		    credentials.unp_euid, geteuid(),
357*27852ebeSDavid van Moolenbroek 		    credentials.unp_egid, getegid());
358433d6423SLionel Sambuc 		test_fail("[client] Credential passing gave us a bad UID/GID");
359433d6423SLionel Sambuc 	}
360433d6423SLionel Sambuc }
361433d6423SLionel Sambuc 
362*27852ebeSDavid van Moolenbroek static void
callback_set_listen_opt(int sd)363*27852ebeSDavid van Moolenbroek callback_set_listen_opt(int sd)
364*27852ebeSDavid van Moolenbroek {
365*27852ebeSDavid van Moolenbroek 	int val;
366*27852ebeSDavid van Moolenbroek 
367*27852ebeSDavid van Moolenbroek 	/*
368*27852ebeSDavid van Moolenbroek 	 * Several of the tests assume that a new connection to a server will
369*27852ebeSDavid van Moolenbroek 	 * not be established (i.e., go from "connecting" to "connected" state)
370*27852ebeSDavid van Moolenbroek 	 * until the server actually accepts the connection with an accept(2)
371*27852ebeSDavid van Moolenbroek 	 * call.  With the new UDS implementation, this is no longer true: to
372*27852ebeSDavid van Moolenbroek 	 * match the behavior of other systems, UDS now preemptively connects
373*27852ebeSDavid van Moolenbroek 	 * the socket in anticipation of the accept(2) call.  We can change
374*27852ebeSDavid van Moolenbroek 	 * back to the old behavior by setting LOCAL_CONNWAIT however, and
375*27852ebeSDavid van Moolenbroek 	 * since the test effectively tests a larger set of socket transitions
376*27852ebeSDavid van Moolenbroek 	 * that way, that is what we do for these tests.
377*27852ebeSDavid van Moolenbroek 	 */
378*27852ebeSDavid van Moolenbroek 	val = 1;
379*27852ebeSDavid van Moolenbroek 	if (setsockopt(sd, 0, LOCAL_CONNWAIT, &val, sizeof(val)) != 0)
380*27852ebeSDavid van Moolenbroek 		test_fail("setsockopt(LOCAL_CONNWAIT)");
381*27852ebeSDavid van Moolenbroek }
382*27852ebeSDavid van Moolenbroek 
test_vectorio(int type)383cbc8a0dfSDavid van Moolenbroek static void test_vectorio(int type)
384433d6423SLionel Sambuc {
385433d6423SLionel Sambuc 	int sv[2];
386433d6423SLionel Sambuc 	int rc;
387433d6423SLionel Sambuc 	struct iovec iov[3];
388433d6423SLionel Sambuc 	char buf1[BUFSIZE];
389433d6423SLionel Sambuc 	char buf2[BUFSIZE];
390433d6423SLionel Sambuc 	char buf3[BUFSIZE];
391433d6423SLionel Sambuc 	char buf4[BUFSIZE*3];
392433d6423SLionel Sambuc 	const struct iovec *iovp = iov;
393433d6423SLionel Sambuc 
394433d6423SLionel Sambuc 	debug("begin vectorio tests");
395433d6423SLionel Sambuc 
396433d6423SLionel Sambuc 	memset(buf1, '\0', BUFSIZE);
397433d6423SLionel Sambuc 	strncpy(buf1, "HELLO ", BUFSIZE - 1);
398433d6423SLionel Sambuc 
399433d6423SLionel Sambuc 	memset(buf2, '\0', BUFSIZE);
400433d6423SLionel Sambuc 	strncpy(buf2, "WORLD", BUFSIZE - 1);
401433d6423SLionel Sambuc 
402433d6423SLionel Sambuc 	memset(buf3, '\0', BUFSIZE);
403433d6423SLionel Sambuc 
404433d6423SLionel Sambuc 	rc = socketpair(PF_UNIX, type, 0, sv);
405433d6423SLionel Sambuc 	if (rc == -1) {
406433d6423SLionel Sambuc 		test_fail("socketpair");
407433d6423SLionel Sambuc 	}
408433d6423SLionel Sambuc 
409433d6423SLionel Sambuc 	iov[0].iov_base = buf1;
410433d6423SLionel Sambuc 	iov[0].iov_len  = strlen(buf1);
411433d6423SLionel Sambuc 	iov[1].iov_base = buf2;
412433d6423SLionel Sambuc 	iov[1].iov_len  = strlen(buf2);
413433d6423SLionel Sambuc 	iov[2].iov_base = buf3;
414433d6423SLionel Sambuc 	iov[2].iov_len  = 1;
415433d6423SLionel Sambuc 
416433d6423SLionel Sambuc 	rc = writev(sv[0], iovp, 3);
417433d6423SLionel Sambuc 	if (rc == -1) {
418433d6423SLionel Sambuc 		test_fail("writev");
419433d6423SLionel Sambuc 	}
420433d6423SLionel Sambuc 
421433d6423SLionel Sambuc 	memset(buf4, '\0', BUFSIZE*3);
422433d6423SLionel Sambuc 
423433d6423SLionel Sambuc 	rc = read(sv[1], buf4, BUFSIZE*3);
424433d6423SLionel Sambuc 	if (rc == -1) {
425433d6423SLionel Sambuc 		test_fail("read");
426433d6423SLionel Sambuc 	}
427433d6423SLionel Sambuc 
428433d6423SLionel Sambuc 	if (strncmp(buf4, "HELLO WORLD", strlen("HELLO WORLD"))) {
429433d6423SLionel Sambuc 		test_fail("the string we read was not 'HELLO WORLD'");
430433d6423SLionel Sambuc 	}
431433d6423SLionel Sambuc 
432433d6423SLionel Sambuc 	memset(buf1, '\0', BUFSIZE);
433433d6423SLionel Sambuc 	strncpy(buf1, "Unit Test Time", BUFSIZE - 1);
434433d6423SLionel Sambuc 
435433d6423SLionel Sambuc 	rc = write(sv[1], buf1, strlen(buf1) + 1);
436433d6423SLionel Sambuc 	if (rc == -1) {
437433d6423SLionel Sambuc 		test_fail("write");
438433d6423SLionel Sambuc 	}
439433d6423SLionel Sambuc 
440433d6423SLionel Sambuc 	memset(buf2, '\0', BUFSIZE);
441433d6423SLionel Sambuc 	memset(buf3, '\0', BUFSIZE);
442433d6423SLionel Sambuc 	memset(buf4, '\0', BUFSIZE*3);
443433d6423SLionel Sambuc 
444433d6423SLionel Sambuc 	iov[0].iov_base = buf2;
445433d6423SLionel Sambuc 	iov[0].iov_len  = 5;
446433d6423SLionel Sambuc 	iov[1].iov_base = buf3;
447433d6423SLionel Sambuc 	iov[1].iov_len  = 5;
448433d6423SLionel Sambuc 	iov[2].iov_base = buf4;
449433d6423SLionel Sambuc 	iov[2].iov_len  = 32;
450433d6423SLionel Sambuc 
451433d6423SLionel Sambuc 	rc = readv(sv[0], iovp, 3);
452433d6423SLionel Sambuc 	if (rc == -1) {
453433d6423SLionel Sambuc 		test_fail("readv");
454433d6423SLionel Sambuc 	}
455433d6423SLionel Sambuc 
456433d6423SLionel Sambuc 	if (strncmp(buf2, "Unit ", 5) || strncmp(buf3, "Test ", 5) ||
457433d6423SLionel Sambuc 					strncmp(buf4, "Time", 4)) {
458433d6423SLionel Sambuc 		test_fail("readv");
459433d6423SLionel Sambuc 	}
460433d6423SLionel Sambuc 
461433d6423SLionel Sambuc 	rc = close(sv[0]);
462433d6423SLionel Sambuc 	if (rc == -1) {
463433d6423SLionel Sambuc 		test_fail("close");
464433d6423SLionel Sambuc 	}
465433d6423SLionel Sambuc 
466433d6423SLionel Sambuc 	rc = close(sv[1]);
467433d6423SLionel Sambuc 	if (rc == -1) {
468433d6423SLionel Sambuc 		test_fail("close");
469433d6423SLionel Sambuc 	}
470433d6423SLionel Sambuc 
471433d6423SLionel Sambuc 	debug("done vector io tests");
472433d6423SLionel Sambuc }
473433d6423SLionel Sambuc 
test_msg(int type)474cbc8a0dfSDavid van Moolenbroek static void test_msg(int type)
475433d6423SLionel Sambuc {
476433d6423SLionel Sambuc 	int sv[2];
477433d6423SLionel Sambuc 	int rc;
478433d6423SLionel Sambuc 	struct msghdr msg1;
479433d6423SLionel Sambuc 	struct msghdr msg2;
480433d6423SLionel Sambuc 	struct iovec iov[3];
481433d6423SLionel Sambuc 	char buf1[BUFSIZE];
482433d6423SLionel Sambuc 	char buf2[BUFSIZE];
483433d6423SLionel Sambuc 	char buf3[BUFSIZE];
484433d6423SLionel Sambuc 	char buf4[BUFSIZE*3];
485433d6423SLionel Sambuc 
486433d6423SLionel Sambuc 	debug("begin sendmsg/recvmsg tests");
487433d6423SLionel Sambuc 
488433d6423SLionel Sambuc 	memset(buf1, '\0', BUFSIZE);
489433d6423SLionel Sambuc 	strncpy(buf1, "HELLO ", BUFSIZE - 1);
490433d6423SLionel Sambuc 
491433d6423SLionel Sambuc 	memset(buf2, '\0', BUFSIZE);
492433d6423SLionel Sambuc 	strncpy(buf2, "WORLD", BUFSIZE - 1);
493433d6423SLionel Sambuc 
494433d6423SLionel Sambuc 	memset(buf3, '\0', BUFSIZE);
495433d6423SLionel Sambuc 
496433d6423SLionel Sambuc 	rc = socketpair(PF_UNIX, type, 0, sv);
497433d6423SLionel Sambuc 	if (rc == -1) {
498433d6423SLionel Sambuc 		test_fail("socketpair");
499433d6423SLionel Sambuc 	}
500433d6423SLionel Sambuc 
501433d6423SLionel Sambuc 	iov[0].iov_base = buf1;
502433d6423SLionel Sambuc 	iov[0].iov_len  = strlen(buf1);
503433d6423SLionel Sambuc 	iov[1].iov_base = buf2;
504433d6423SLionel Sambuc 	iov[1].iov_len  = strlen(buf2);
505433d6423SLionel Sambuc 	iov[2].iov_base = buf3;
506433d6423SLionel Sambuc 	iov[2].iov_len  = 1;
507433d6423SLionel Sambuc 
508433d6423SLionel Sambuc 	memset(&msg1, '\0', sizeof(struct msghdr));
509433d6423SLionel Sambuc 	msg1.msg_name = NULL;
510433d6423SLionel Sambuc 	msg1.msg_namelen = 0;
511433d6423SLionel Sambuc 	msg1.msg_iov = iov;
512433d6423SLionel Sambuc 	msg1.msg_iovlen = 3;
513433d6423SLionel Sambuc 	msg1.msg_control = NULL;
514433d6423SLionel Sambuc 	msg1.msg_controllen = 0;
515433d6423SLionel Sambuc 	msg1.msg_flags = 0;
516433d6423SLionel Sambuc 
517433d6423SLionel Sambuc 	rc = sendmsg(sv[0], &msg1, 0);
518433d6423SLionel Sambuc 	if (rc == -1) {
519433d6423SLionel Sambuc 		test_fail("writev");
520433d6423SLionel Sambuc 	}
521433d6423SLionel Sambuc 
522433d6423SLionel Sambuc 	memset(buf4, '\0', BUFSIZE*3);
523433d6423SLionel Sambuc 
524433d6423SLionel Sambuc 	rc = read(sv[1], buf4, BUFSIZE*3);
525433d6423SLionel Sambuc 	if (rc == -1) {
526433d6423SLionel Sambuc 		test_fail("read");
527433d6423SLionel Sambuc 	}
528433d6423SLionel Sambuc 
529433d6423SLionel Sambuc 	if (strncmp(buf4, "HELLO WORLD", strlen("HELLO WORLD"))) {
530433d6423SLionel Sambuc 		test_fail("the string we read was not 'HELLO WORLD'");
531433d6423SLionel Sambuc 	}
532433d6423SLionel Sambuc 
533433d6423SLionel Sambuc 	memset(buf1, '\0', BUFSIZE);
534433d6423SLionel Sambuc 	strncpy(buf1, "Unit Test Time", BUFSIZE - 1);
535433d6423SLionel Sambuc 
536433d6423SLionel Sambuc 	rc = write(sv[1], buf1, strlen(buf1) + 1);
537433d6423SLionel Sambuc 	if (rc == -1) {
538433d6423SLionel Sambuc 		test_fail("write");
539433d6423SLionel Sambuc 	}
540433d6423SLionel Sambuc 
541433d6423SLionel Sambuc 	memset(buf2, '\0', BUFSIZE);
542433d6423SLionel Sambuc 	memset(buf3, '\0', BUFSIZE);
543433d6423SLionel Sambuc 	memset(buf4, '\0', BUFSIZE*3);
544433d6423SLionel Sambuc 
545433d6423SLionel Sambuc 	iov[0].iov_base = buf2;
546433d6423SLionel Sambuc 	iov[0].iov_len  = 5;
547433d6423SLionel Sambuc 	iov[1].iov_base = buf3;
548433d6423SLionel Sambuc 	iov[1].iov_len  = 5;
549433d6423SLionel Sambuc 	iov[2].iov_base = buf4;
550433d6423SLionel Sambuc 	iov[2].iov_len  = 32;
551433d6423SLionel Sambuc 
552433d6423SLionel Sambuc 	memset(&msg2, '\0', sizeof(struct msghdr));
553433d6423SLionel Sambuc 	msg2.msg_name = NULL;
554433d6423SLionel Sambuc 	msg2.msg_namelen = 0;
555433d6423SLionel Sambuc 	msg2.msg_iov = iov;
556433d6423SLionel Sambuc 	msg2.msg_iovlen = 3;
557433d6423SLionel Sambuc 	msg2.msg_control = NULL;
558433d6423SLionel Sambuc 	msg2.msg_controllen = 0;
559433d6423SLionel Sambuc 	msg2.msg_flags = 0;
560433d6423SLionel Sambuc 
561433d6423SLionel Sambuc 	rc = recvmsg(sv[0], &msg2, 0);
562433d6423SLionel Sambuc 	if (rc == -1) {
563433d6423SLionel Sambuc 		test_fail("readv");
564433d6423SLionel Sambuc 	}
565433d6423SLionel Sambuc 
566433d6423SLionel Sambuc 	if (strncmp(buf2, "Unit ", 5) || strncmp(buf3, "Test ", 5) ||
567433d6423SLionel Sambuc 					strncmp(buf4, "Time", 4)) {
568433d6423SLionel Sambuc 		test_fail("readv");
569433d6423SLionel Sambuc 	}
570433d6423SLionel Sambuc 
571433d6423SLionel Sambuc 	rc = close(sv[0]);
572433d6423SLionel Sambuc 	if (rc == -1) {
573433d6423SLionel Sambuc 		test_fail("close");
574433d6423SLionel Sambuc 	}
575433d6423SLionel Sambuc 
576433d6423SLionel Sambuc 	rc = close(sv[1]);
577433d6423SLionel Sambuc 	if (rc == -1) {
578433d6423SLionel Sambuc 		test_fail("close");
579433d6423SLionel Sambuc 	}
580433d6423SLionel Sambuc }
581433d6423SLionel Sambuc 
test_scm_credentials(void)582cbc8a0dfSDavid van Moolenbroek static void test_scm_credentials(void)
583433d6423SLionel Sambuc {
584433d6423SLionel Sambuc 	int rc;
585433d6423SLionel Sambuc 	int src;
586433d6423SLionel Sambuc 	int dst;
587*27852ebeSDavid van Moolenbroek 	int one;
588*27852ebeSDavid van Moolenbroek 	union {
589*27852ebeSDavid van Moolenbroek 		struct sockcred cred;
590*27852ebeSDavid van Moolenbroek 		char buf[SOCKCREDSIZE(NGROUPS_MAX)];
591*27852ebeSDavid van Moolenbroek 	} cred;
592433d6423SLionel Sambuc 	struct cmsghdr *cmsg = NULL;
593433d6423SLionel Sambuc 	struct sockaddr_un addr;
594433d6423SLionel Sambuc 	struct iovec iov[3];
595433d6423SLionel Sambuc 	struct msghdr msg1;
596433d6423SLionel Sambuc 	struct msghdr msg2;
597433d6423SLionel Sambuc 	char buf1[BUFSIZE];
598433d6423SLionel Sambuc 	char buf2[BUFSIZE];
599433d6423SLionel Sambuc 	char buf3[BUFSIZE];
600433d6423SLionel Sambuc 	char ctrl[BUFSIZE];
601*27852ebeSDavid van Moolenbroek 	socklen_t len, addrlen = sizeof(struct sockaddr_un);
602433d6423SLionel Sambuc 
603433d6423SLionel Sambuc 	debug("test_scm_credentials");
604433d6423SLionel Sambuc 
605433d6423SLionel Sambuc 	UNLINK(TEST_SUN_PATH);
606433d6423SLionel Sambuc 	UNLINK(TEST_SUN_PATHB);
607433d6423SLionel Sambuc 
608433d6423SLionel Sambuc 	debug("creating src socket");
609433d6423SLionel Sambuc 
610433d6423SLionel Sambuc 	src = socket(PF_UNIX, SOCK_DGRAM, 0);
611433d6423SLionel Sambuc 	if (src == -1) {
612433d6423SLionel Sambuc 		test_fail("socket");
613433d6423SLionel Sambuc 	}
614433d6423SLionel Sambuc 
615433d6423SLionel Sambuc 	debug("creating dst socket");
616433d6423SLionel Sambuc 
617433d6423SLionel Sambuc 	dst = socket(PF_UNIX, SOCK_DGRAM, 0);
618433d6423SLionel Sambuc 	if (dst == -1) {
619433d6423SLionel Sambuc 		test_fail("socket");
620433d6423SLionel Sambuc 	}
621433d6423SLionel Sambuc 
622433d6423SLionel Sambuc 	debug("binding src socket");
623433d6423SLionel Sambuc 
624433d6423SLionel Sambuc 	memset(&addr, '\0', sizeof(struct sockaddr_un));
625433d6423SLionel Sambuc 	addr.sun_family = AF_UNIX;
626433d6423SLionel Sambuc 	strncpy(addr.sun_path, TEST_SUN_PATHB, sizeof(addr.sun_path) - 1);
627433d6423SLionel Sambuc 	rc = bind(src, (struct sockaddr *) &addr, addrlen);
628433d6423SLionel Sambuc 	if (rc == -1) {
629433d6423SLionel Sambuc 		test_fail("bind");
630433d6423SLionel Sambuc 	}
631433d6423SLionel Sambuc 
632433d6423SLionel Sambuc 	debug("binding dst socket");
633433d6423SLionel Sambuc 
634433d6423SLionel Sambuc 	memset(&addr, '\0', sizeof(struct sockaddr_un));
635433d6423SLionel Sambuc 	addr.sun_family = AF_UNIX;
636433d6423SLionel Sambuc 	strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
637433d6423SLionel Sambuc 
638433d6423SLionel Sambuc 	rc = bind(dst, (struct sockaddr *) &addr, addrlen);
639433d6423SLionel Sambuc 	if (rc == -1) {
640433d6423SLionel Sambuc 		test_fail("bind");
641433d6423SLionel Sambuc 	}
642433d6423SLionel Sambuc 
643*27852ebeSDavid van Moolenbroek 	debug("request credential passing");
644*27852ebeSDavid van Moolenbroek 
645*27852ebeSDavid van Moolenbroek 	one = 1;
646*27852ebeSDavid van Moolenbroek 	rc = setsockopt(dst, 0, LOCAL_CREDS, &one, sizeof(one));
647*27852ebeSDavid van Moolenbroek 	if (rc == -1) {
648*27852ebeSDavid van Moolenbroek 		test_fail("setsockopt(LOCAL_CREDS)");
649*27852ebeSDavid van Moolenbroek 	}
650*27852ebeSDavid van Moolenbroek 
651*27852ebeSDavid van Moolenbroek 	debug("sending msg1");
652*27852ebeSDavid van Moolenbroek 
653433d6423SLionel Sambuc 	memset(&buf1, '\0', BUFSIZE);
654433d6423SLionel Sambuc 	memset(&buf2, '\0', BUFSIZE);
655433d6423SLionel Sambuc 	memset(&buf3, '\0', BUFSIZE);
656433d6423SLionel Sambuc 	memset(&ctrl, '\0', BUFSIZE);
657433d6423SLionel Sambuc 
658433d6423SLionel Sambuc 	strncpy(buf1, "Minix ", BUFSIZE-1);
659433d6423SLionel Sambuc 	strncpy(buf2, "is ", BUFSIZE-1);
660433d6423SLionel Sambuc 	strncpy(buf3, "great!", BUFSIZE-1);
661433d6423SLionel Sambuc 
662433d6423SLionel Sambuc 	iov[0].iov_base = buf1;
663433d6423SLionel Sambuc 	iov[0].iov_len  = 6;
664433d6423SLionel Sambuc 	iov[1].iov_base = buf2;
665433d6423SLionel Sambuc 	iov[1].iov_len  = 3;
666433d6423SLionel Sambuc 	iov[2].iov_base = buf3;
667433d6423SLionel Sambuc 	iov[2].iov_len  = 32;
668433d6423SLionel Sambuc 
669433d6423SLionel Sambuc 	memset(&msg1, '\0', sizeof(struct msghdr));
670433d6423SLionel Sambuc 	msg1.msg_name = &addr;
671433d6423SLionel Sambuc 	msg1.msg_namelen = addrlen;
672433d6423SLionel Sambuc 	msg1.msg_iov = iov;
673433d6423SLionel Sambuc 	msg1.msg_iovlen = 3;
674433d6423SLionel Sambuc 	msg1.msg_control = NULL;
675433d6423SLionel Sambuc 	msg1.msg_controllen = 0;
676433d6423SLionel Sambuc 	msg1.msg_flags = 0;
677433d6423SLionel Sambuc 
678433d6423SLionel Sambuc 	rc = sendmsg(src, &msg1, 0);
679433d6423SLionel Sambuc 	if (rc == -1) {
680433d6423SLionel Sambuc 		test_fail("sendmsg");
681433d6423SLionel Sambuc 	}
682433d6423SLionel Sambuc 
683433d6423SLionel Sambuc 	memset(&buf1, '\0', BUFSIZE);
684433d6423SLionel Sambuc 	memset(&buf2, '\0', BUFSIZE);
685433d6423SLionel Sambuc 	memset(&buf3, '\0', BUFSIZE);
686433d6423SLionel Sambuc 	memset(&ctrl, '\0', BUFSIZE);
687433d6423SLionel Sambuc 
688433d6423SLionel Sambuc 	iov[0].iov_base = buf1;
689433d6423SLionel Sambuc 	iov[0].iov_len  = 9;
690433d6423SLionel Sambuc 	iov[1].iov_base = buf2;
691433d6423SLionel Sambuc 	iov[1].iov_len  = 32;
692433d6423SLionel Sambuc 
693433d6423SLionel Sambuc 	memset(&addr, '\0', sizeof(struct sockaddr_un));
694433d6423SLionel Sambuc 	memset(&msg2, '\0', sizeof(struct msghdr));
695433d6423SLionel Sambuc 	msg2.msg_name = &addr;
696433d6423SLionel Sambuc 	msg2.msg_namelen = sizeof(struct sockaddr_un);
697433d6423SLionel Sambuc 	msg2.msg_iov = iov;
698433d6423SLionel Sambuc 	msg2.msg_iovlen = 2;
699433d6423SLionel Sambuc 	msg2.msg_control = ctrl;
700433d6423SLionel Sambuc 	msg2.msg_controllen = BUFSIZE;
701433d6423SLionel Sambuc 	msg2.msg_flags = 0;
702433d6423SLionel Sambuc 
703433d6423SLionel Sambuc 	debug("recv msg2");
704433d6423SLionel Sambuc 
705433d6423SLionel Sambuc 	rc = recvmsg(dst, &msg2, 0);
706433d6423SLionel Sambuc 	if (rc == -1) {
707433d6423SLionel Sambuc 		test_fail("recvmsg");
708433d6423SLionel Sambuc 	}
709433d6423SLionel Sambuc 
710433d6423SLionel Sambuc 	debug("checking results");
711433d6423SLionel Sambuc 
712433d6423SLionel Sambuc 	if (strncmp(buf1, "Minix is ", 9) || strncmp(buf2, "great!", 6)) {
713433d6423SLionel Sambuc 		test_fail("recvmsg");
714433d6423SLionel Sambuc 	}
715433d6423SLionel Sambuc 
716433d6423SLionel Sambuc 	/* we need to use the full path "/usr/src/test/DIR_56/testb.sock"
717433d6423SLionel Sambuc 	 * because that is what is returned by recvmsg().
718433d6423SLionel Sambuc 	 */
719433d6423SLionel Sambuc 	if (addr.sun_family != AF_UNIX || strcmp(addr.sun_path,
720*27852ebeSDavid van Moolenbroek 					TEST_SUN_PATHB)) {
721433d6423SLionel Sambuc 		test_fail("recvmsg");
722433d6423SLionel Sambuc 	}
723433d6423SLionel Sambuc 
724433d6423SLionel Sambuc 	debug("looking for credentials");
725433d6423SLionel Sambuc 
726*27852ebeSDavid van Moolenbroek 	len = 0;
727*27852ebeSDavid van Moolenbroek 
728*27852ebeSDavid van Moolenbroek 	memset(&cred, 'x', sizeof(cred));
729433d6423SLionel Sambuc 	for (cmsg = CMSG_FIRSTHDR(&msg2); cmsg != NULL;
730433d6423SLionel Sambuc 					cmsg = CMSG_NXTHDR(&msg2, cmsg)) {
731433d6423SLionel Sambuc 
732433d6423SLionel Sambuc 		if (cmsg->cmsg_level == SOL_SOCKET &&
733433d6423SLionel Sambuc 				cmsg->cmsg_type == SCM_CREDS) {
734*27852ebeSDavid van Moolenbroek 			/* Great, this alignment business!  But then at least
735*27852ebeSDavid van Moolenbroek 			 * give me a macro to compute the actual data length..
736*27852ebeSDavid van Moolenbroek 			 */
737*27852ebeSDavid van Moolenbroek 			len = cmsg->cmsg_len - (socklen_t)
738*27852ebeSDavid van Moolenbroek 			    ((char *)CMSG_DATA(cmsg) - (char *)cmsg);
739433d6423SLionel Sambuc 
740*27852ebeSDavid van Moolenbroek 			if (len < sizeof(struct sockcred))
741*27852ebeSDavid van Moolenbroek 				test_fail("credentials too small");
742*27852ebeSDavid van Moolenbroek 			else if (len > sizeof(cred))
743*27852ebeSDavid van Moolenbroek 				test_fail("credentials too large");
744*27852ebeSDavid van Moolenbroek 			memcpy(cred.buf, CMSG_DATA(cmsg), len);
745433d6423SLionel Sambuc 			break;
746433d6423SLionel Sambuc 		}
747433d6423SLionel Sambuc 	}
748433d6423SLionel Sambuc 
749*27852ebeSDavid van Moolenbroek 	if (len == 0)
750*27852ebeSDavid van Moolenbroek 		test_fail("no credentials found");
751433d6423SLionel Sambuc 
752*27852ebeSDavid van Moolenbroek 	if (len != SOCKCREDSIZE(cred.cred.sc_ngroups))
753*27852ebeSDavid van Moolenbroek 		test_fail("wrong credentials size");
754*27852ebeSDavid van Moolenbroek 
755*27852ebeSDavid van Moolenbroek 	/*
756*27852ebeSDavid van Moolenbroek 	 * TODO: check supplementary groups.  This whole test is pretty much
757*27852ebeSDavid van Moolenbroek 	 * pointless since we're running with very standard credentials anyway.
758*27852ebeSDavid van Moolenbroek 	 */
759*27852ebeSDavid van Moolenbroek 	if (cred.cred.sc_uid != getuid() ||
760*27852ebeSDavid van Moolenbroek 	    cred.cred.sc_euid != geteuid() ||
761*27852ebeSDavid van Moolenbroek 	    cred.cred.sc_gid != getgid() ||
762*27852ebeSDavid van Moolenbroek 	    cred.cred.sc_egid != getegid() ||
763*27852ebeSDavid van Moolenbroek 	    cred.cred.sc_ngroups < 0 || cred.cred.sc_ngroups > NGROUPS_MAX) {
764433d6423SLionel Sambuc 		test_fail("did no receive the proper credentials");
765433d6423SLionel Sambuc 	}
766433d6423SLionel Sambuc 
767433d6423SLionel Sambuc 	rc = close(dst);
768433d6423SLionel Sambuc 	if (rc == -1) {
769433d6423SLionel Sambuc 		test_fail("close");
770433d6423SLionel Sambuc 	}
771433d6423SLionel Sambuc 
772433d6423SLionel Sambuc 	rc = close(src);
773433d6423SLionel Sambuc 	if (rc == -1) {
774433d6423SLionel Sambuc 		test_fail("close");
775433d6423SLionel Sambuc 	}
776433d6423SLionel Sambuc 
777433d6423SLionel Sambuc 	UNLINK(TEST_SUN_PATH);
778433d6423SLionel Sambuc 	UNLINK(TEST_SUN_PATHB);
779433d6423SLionel Sambuc }
780433d6423SLionel Sambuc 
test_connect(const struct socket_test_info * info)781294d1590SErik van der Kouwe static void test_connect(const struct socket_test_info *info)
782433d6423SLionel Sambuc {
783433d6423SLionel Sambuc 	int i, sd, sds[2], rc;
784433d6423SLionel Sambuc 
785433d6423SLionel Sambuc 	/* connect() is already tested throughout test56, but
786433d6423SLionel Sambuc 	 * in most cases the client and server end up on /dev/uds
787433d6423SLionel Sambuc 	 * minor 0 and minor 1. This test opens some sockets first and
788433d6423SLionel Sambuc 	 * then calls test_simple_client_server(). This forces the
789433d6423SLionel Sambuc 	 * client and server minor numbers higher in the descriptor table.
790433d6423SLionel Sambuc 	 */
791433d6423SLionel Sambuc 
792433d6423SLionel Sambuc 	debug("starting test_connect()");
793433d6423SLionel Sambuc 
794433d6423SLionel Sambuc 	sd = socket(AF_UNIX, SOCK_DGRAM, 0);
795433d6423SLionel Sambuc 	if (sd == -1) {
796433d6423SLionel Sambuc 		test_fail("couldn't create a socket");
797433d6423SLionel Sambuc 	}
798433d6423SLionel Sambuc 
799433d6423SLionel Sambuc 	rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sds);
800433d6423SLionel Sambuc 	if (rc == -1) {
801433d6423SLionel Sambuc 		test_fail("couldn't create a socketpair");
802433d6423SLionel Sambuc 	}
803433d6423SLionel Sambuc 
804433d6423SLionel Sambuc 	for (i = 0; i < 3; i++) {
805294d1590SErik van der Kouwe 		test_simple_client_server(info, types[i]);
806433d6423SLionel Sambuc 	}
807433d6423SLionel Sambuc 
808433d6423SLionel Sambuc 	rc = close(sds[1]);
809433d6423SLionel Sambuc 	if (rc == -1) {
810433d6423SLionel Sambuc 		test_fail("close() failed");
811433d6423SLionel Sambuc 	}
812433d6423SLionel Sambuc 
813433d6423SLionel Sambuc 	rc = close(sds[0]);
814433d6423SLionel Sambuc 	if (rc == -1) {
815433d6423SLionel Sambuc 		test_fail("close() failed");
816433d6423SLionel Sambuc 	}
817433d6423SLionel Sambuc 
818433d6423SLionel Sambuc 	rc = close(sd);
819433d6423SLionel Sambuc 	if (rc == -1) {
820433d6423SLionel Sambuc 		test_fail("close() failed");
821433d6423SLionel Sambuc 	}
822433d6423SLionel Sambuc 
823433d6423SLionel Sambuc 	debug("exiting test_connect()");
824433d6423SLionel Sambuc }
825433d6423SLionel Sambuc 
test_multiproc_read(void)826cbc8a0dfSDavid van Moolenbroek static int test_multiproc_read(void)
827433d6423SLionel Sambuc {
828433d6423SLionel Sambuc /* test that when we fork() a process with an open socket descriptor,
829433d6423SLionel Sambuc  * the descriptor in each process points to the same thing.
830433d6423SLionel Sambuc  */
831433d6423SLionel Sambuc 
832433d6423SLionel Sambuc 	pid_t pid;
833433d6423SLionel Sambuc 	int sds[2];
834433d6423SLionel Sambuc 	int rc, status;
835433d6423SLionel Sambuc 	char buf[3];
836433d6423SLionel Sambuc 
837433d6423SLionel Sambuc 	debug("entering test_multiproc_read()");
838433d6423SLionel Sambuc 
839433d6423SLionel Sambuc 	rc = socketpair(PF_UNIX, SOCK_STREAM, 0, sds);
840433d6423SLionel Sambuc 	if (rc == -1) {
841433d6423SLionel Sambuc 		test_fail("socketpair");
842433d6423SLionel Sambuc 		return 1;
843433d6423SLionel Sambuc 	}
844433d6423SLionel Sambuc 
845433d6423SLionel Sambuc 	memset(buf, '\0', 3);
846433d6423SLionel Sambuc 
847433d6423SLionel Sambuc 
848433d6423SLionel Sambuc 	/* the signal handler is only used by the client, but we have to
849433d6423SLionel Sambuc 	 * install it now. if we don't the server may signal the client
850433d6423SLionel Sambuc 	 * before the handler is installed.
851433d6423SLionel Sambuc 	 */
852433d6423SLionel Sambuc 	debug("installing signal handler");
853433d6423SLionel Sambuc 	if (signal(SIGUSR1, test_xfer_sighdlr) == SIG_ERR) {
854433d6423SLionel Sambuc 		test_fail("signal(SIGUSR1, test_xfer_sighdlr) failed");
855433d6423SLionel Sambuc 		return 1;
856433d6423SLionel Sambuc 	}
857433d6423SLionel Sambuc 
858433d6423SLionel Sambuc 	debug("signal handler installed");
859433d6423SLionel Sambuc 
860433d6423SLionel Sambuc 	server_ready = 0;
861433d6423SLionel Sambuc 
862433d6423SLionel Sambuc 	pid = fork();
863433d6423SLionel Sambuc 
864433d6423SLionel Sambuc 	if (pid == -1) {
865433d6423SLionel Sambuc 
866433d6423SLionel Sambuc 		test_fail("fork");
867433d6423SLionel Sambuc 		return 1;
868433d6423SLionel Sambuc 
869433d6423SLionel Sambuc 	} else if (pid == 0) {
870433d6423SLionel Sambuc 
871433d6423SLionel Sambuc 		while (server_ready == 0) {
872433d6423SLionel Sambuc 			debug("waiting for SIGUSR1 from parent");
873433d6423SLionel Sambuc 			sleep(1);
874433d6423SLionel Sambuc 		}
875433d6423SLionel Sambuc 
876433d6423SLionel Sambuc 		rc = read(sds[1], buf, 2);
877433d6423SLionel Sambuc 		if (rc == -1) {
878433d6423SLionel Sambuc 			test_fail("read");
879433d6423SLionel Sambuc 			exit(1);
880433d6423SLionel Sambuc 		}
881433d6423SLionel Sambuc 
882433d6423SLionel Sambuc 		if (!(buf[0] == 'X' && buf[1] == '3')) {
883433d6423SLionel Sambuc 			test_fail("Didn't read X3");
884433d6423SLionel Sambuc 			exit(1);
885433d6423SLionel Sambuc 		}
886433d6423SLionel Sambuc 
887433d6423SLionel Sambuc 		exit(0);
888433d6423SLionel Sambuc 	} else {
889433d6423SLionel Sambuc 
890433d6423SLionel Sambuc 		rc = write(sds[0], "MNX3", 4);
891433d6423SLionel Sambuc 		if (rc == -1) {
892433d6423SLionel Sambuc 			test_fail("write");
893433d6423SLionel Sambuc 		}
894433d6423SLionel Sambuc 
895433d6423SLionel Sambuc 		rc = read(sds[1], buf, 2);
896433d6423SLionel Sambuc 		if (rc == -1) {
897433d6423SLionel Sambuc 			test_fail("read");
898433d6423SLionel Sambuc 		}
899433d6423SLionel Sambuc 
900433d6423SLionel Sambuc 		if (!(buf[0] == 'M' && buf[1] == 'N')) {
901433d6423SLionel Sambuc 			test_fail("Didn't read MN");
902433d6423SLionel Sambuc 		}
903433d6423SLionel Sambuc 
904433d6423SLionel Sambuc 		/* time to tell the client to start the test */
905433d6423SLionel Sambuc 		kill(pid, SIGUSR1);
906433d6423SLionel Sambuc 
907433d6423SLionel Sambuc 		do {
908433d6423SLionel Sambuc 			rc = waitpid(pid, &status, 0);
909433d6423SLionel Sambuc 		} while (rc == -1 && errno == EINTR);
910433d6423SLionel Sambuc 
911433d6423SLionel Sambuc 		/* we use the exit status to get its error count */
912433d6423SLionel Sambuc 		errct += WEXITSTATUS(status);
913433d6423SLionel Sambuc 	}
914433d6423SLionel Sambuc 
915433d6423SLionel Sambuc 	return 0;
916433d6423SLionel Sambuc }
917433d6423SLionel Sambuc 
test_multiproc_write(void)918cbc8a0dfSDavid van Moolenbroek static int test_multiproc_write(void)
919433d6423SLionel Sambuc {
920433d6423SLionel Sambuc /* test that when we fork() a process with an open socket descriptor,
921433d6423SLionel Sambuc  * the descriptor in each process points to the same thing.
922433d6423SLionel Sambuc  */
923433d6423SLionel Sambuc 
924433d6423SLionel Sambuc 	pid_t pid;
925433d6423SLionel Sambuc 	int sds[2];
926433d6423SLionel Sambuc 	int rc, status;
927433d6423SLionel Sambuc 	char buf[7];
928433d6423SLionel Sambuc 
929433d6423SLionel Sambuc 	debug("entering test_multiproc_write()");
930433d6423SLionel Sambuc 
931433d6423SLionel Sambuc 	rc = socketpair(PF_UNIX, SOCK_STREAM, 0, sds);
932433d6423SLionel Sambuc 	if (rc == -1) {
933433d6423SLionel Sambuc 		test_fail("socketpair");
934433d6423SLionel Sambuc 		return 1;
935433d6423SLionel Sambuc 	}
936433d6423SLionel Sambuc 
937433d6423SLionel Sambuc 	memset(buf, '\0', 7);
938433d6423SLionel Sambuc 
939433d6423SLionel Sambuc 
940433d6423SLionel Sambuc 	/* the signal handler is only used by the client, but we have to
941433d6423SLionel Sambuc 	 * install it now. if we don't the server may signal the client
942433d6423SLionel Sambuc 	 * before the handler is installed.
943433d6423SLionel Sambuc 	 */
944433d6423SLionel Sambuc 	debug("installing signal handler");
945433d6423SLionel Sambuc 	if (signal(SIGUSR1, test_xfer_sighdlr) == SIG_ERR) {
946433d6423SLionel Sambuc 		test_fail("signal(SIGUSR1, test_xfer_sighdlr) failed");
947433d6423SLionel Sambuc 		return 1;
948433d6423SLionel Sambuc 	}
949433d6423SLionel Sambuc 
950433d6423SLionel Sambuc 	debug("signal handler installed");
951433d6423SLionel Sambuc 
952433d6423SLionel Sambuc 	server_ready = 0;
953433d6423SLionel Sambuc 
954433d6423SLionel Sambuc 	pid = fork();
955433d6423SLionel Sambuc 
956433d6423SLionel Sambuc 	if (pid == -1) {
957433d6423SLionel Sambuc 
958433d6423SLionel Sambuc 		test_fail("fork");
959433d6423SLionel Sambuc 		return 1;
960433d6423SLionel Sambuc 
961433d6423SLionel Sambuc 	} else if (pid == 0) {
962433d6423SLionel Sambuc 
963433d6423SLionel Sambuc 		while (server_ready == 0) {
964433d6423SLionel Sambuc 			debug("waiting for SIGUSR1 from parent");
965433d6423SLionel Sambuc 			sleep(1);
966433d6423SLionel Sambuc 		}
967433d6423SLionel Sambuc 
968433d6423SLionel Sambuc 		rc = write(sds[1], "IX3", 3);
969433d6423SLionel Sambuc 		if (rc == -1) {
970433d6423SLionel Sambuc 			test_fail("write");
971433d6423SLionel Sambuc 			exit(1);
972433d6423SLionel Sambuc 		}
973433d6423SLionel Sambuc 
974433d6423SLionel Sambuc 		rc = read(sds[0], buf, 6);
975433d6423SLionel Sambuc 		if (rc == -1) {
976433d6423SLionel Sambuc 			test_fail("read");
977433d6423SLionel Sambuc 			exit(1);
978433d6423SLionel Sambuc 		}
979433d6423SLionel Sambuc 
980433d6423SLionel Sambuc 		if (strcmp(buf, "MINIX3") != 0) {
981433d6423SLionel Sambuc 			test_fail("didn't read MINIX3");
982433d6423SLionel Sambuc 			exit(1);
983433d6423SLionel Sambuc 		}
984433d6423SLionel Sambuc 
985433d6423SLionel Sambuc 		exit(0);
986433d6423SLionel Sambuc 	} else {
987433d6423SLionel Sambuc 
988433d6423SLionel Sambuc 		rc = write(sds[1], "MIN", 3);
989433d6423SLionel Sambuc 		if (rc == -1) {
990433d6423SLionel Sambuc 			test_fail("write");
991433d6423SLionel Sambuc 		}
992433d6423SLionel Sambuc 
993433d6423SLionel Sambuc 		/* time to tell the client to start the test */
994433d6423SLionel Sambuc 		kill(pid, SIGUSR1);
995433d6423SLionel Sambuc 
996433d6423SLionel Sambuc 		do {
997433d6423SLionel Sambuc 			rc = waitpid(pid, &status, 0);
998433d6423SLionel Sambuc 		} while (rc == -1 && errno == EINTR);
999433d6423SLionel Sambuc 
1000433d6423SLionel Sambuc 		/* we use the exit status to get its error count */
1001433d6423SLionel Sambuc 		errct += WEXITSTATUS(status);
1002433d6423SLionel Sambuc 	}
1003433d6423SLionel Sambuc 
1004433d6423SLionel Sambuc 	return 0;
1005433d6423SLionel Sambuc }
1006433d6423SLionel Sambuc 
test_fd_passing_child(int sd)1007cbc8a0dfSDavid van Moolenbroek static void test_fd_passing_child(int sd)
1008433d6423SLionel Sambuc {
1009433d6423SLionel Sambuc 	int fd, rc;
1010433d6423SLionel Sambuc 	char x = 'x';
1011433d6423SLionel Sambuc 	struct msghdr msghdr;
1012433d6423SLionel Sambuc 	struct cmsghdr *cmsg;
1013433d6423SLionel Sambuc 	struct iovec iov;
1014433d6423SLionel Sambuc 	char buf[BUFSIZE];
1015433d6423SLionel Sambuc 
1016433d6423SLionel Sambuc 	memset(buf, '\0', BUFSIZE);
1017433d6423SLionel Sambuc 
1018433d6423SLionel Sambuc 	fd = open(TEST_TXT_FILE, O_CREAT|O_TRUNC|O_RDWR);
1019433d6423SLionel Sambuc 	if (fd == -1) {
1020433d6423SLionel Sambuc 		test_fail("could not open test.txt");
1021433d6423SLionel Sambuc 	}
1022433d6423SLionel Sambuc 
1023433d6423SLionel Sambuc 	msghdr.msg_name = NULL;
1024433d6423SLionel Sambuc 	msghdr.msg_namelen = 0;
1025433d6423SLionel Sambuc 
1026433d6423SLionel Sambuc 	iov.iov_base = &x;
1027433d6423SLionel Sambuc 	iov.iov_len = 1;
1028433d6423SLionel Sambuc 	msghdr.msg_iov = &iov;
1029433d6423SLionel Sambuc 	msghdr.msg_iovlen = 1;
1030433d6423SLionel Sambuc 
1031433d6423SLionel Sambuc 	msghdr.msg_control = buf;
1032433d6423SLionel Sambuc 	msghdr.msg_controllen = CMSG_SPACE(sizeof(int));
1033433d6423SLionel Sambuc 
1034433d6423SLionel Sambuc 	msghdr.msg_flags = 0;
1035433d6423SLionel Sambuc 
1036433d6423SLionel Sambuc 	cmsg = CMSG_FIRSTHDR(&msghdr);
1037433d6423SLionel Sambuc 	cmsg->cmsg_len = CMSG_SPACE(sizeof(int));
1038433d6423SLionel Sambuc 	cmsg->cmsg_level = SOL_SOCKET;
1039433d6423SLionel Sambuc 	cmsg->cmsg_type = SCM_RIGHTS;
1040433d6423SLionel Sambuc 
1041433d6423SLionel Sambuc 	((int *) CMSG_DATA(cmsg))[0] = fd;
1042433d6423SLionel Sambuc 
1043433d6423SLionel Sambuc 	rc = sendmsg(sd, &msghdr, 0);
1044433d6423SLionel Sambuc 	if (rc == -1) {
1045433d6423SLionel Sambuc 		test_fail("could not send message");
1046433d6423SLionel Sambuc 	}
1047433d6423SLionel Sambuc 
1048433d6423SLionel Sambuc 	memset(buf, '\0', BUFSIZE);
1049433d6423SLionel Sambuc 	rc = read(sd, buf, BUFSIZE);
1050433d6423SLionel Sambuc 	if (rc == -1) {
1051433d6423SLionel Sambuc 		test_fail("could not read from socket");
1052433d6423SLionel Sambuc 	}
1053433d6423SLionel Sambuc 
1054433d6423SLionel Sambuc 	if (strcmp(buf, "done") != 0) {
1055433d6423SLionel Sambuc 		test_fail("we didn't read the right message");
1056433d6423SLionel Sambuc 	}
1057433d6423SLionel Sambuc 
1058433d6423SLionel Sambuc 	memset(buf, '\0', BUFSIZE);
1059433d6423SLionel Sambuc 	rc = lseek(fd, 0, SEEK_SET);
1060433d6423SLionel Sambuc 	if (rc == -1) {
1061433d6423SLionel Sambuc 		test_fail("could not seek to start of test.txt");
1062433d6423SLionel Sambuc 	}
1063433d6423SLionel Sambuc 
1064433d6423SLionel Sambuc 	rc = read(fd, buf, BUFSIZE);
1065433d6423SLionel Sambuc 	if (rc == -1) {
1066433d6423SLionel Sambuc 		test_fail("could not read from test.txt");
1067433d6423SLionel Sambuc 	}
1068433d6423SLionel Sambuc 
1069433d6423SLionel Sambuc 	if (strcmp(buf, MSG) != 0) {
1070433d6423SLionel Sambuc 		test_fail("other process didn't write MSG to test.txt");
1071433d6423SLionel Sambuc 	}
1072433d6423SLionel Sambuc 
1073433d6423SLionel Sambuc 	rc = close(fd);
1074433d6423SLionel Sambuc 	if (rc == -1) {
1075433d6423SLionel Sambuc 		test_fail("could not close test.txt");
1076433d6423SLionel Sambuc 	}
1077433d6423SLionel Sambuc 
1078433d6423SLionel Sambuc 	rc = close(sd);
1079433d6423SLionel Sambuc 	if (rc == -1) {
1080433d6423SLionel Sambuc 		test_fail("could not close socket");
1081433d6423SLionel Sambuc 	}
1082433d6423SLionel Sambuc 
1083433d6423SLionel Sambuc 	rc = unlink(TEST_TXT_FILE);
1084433d6423SLionel Sambuc 	if (rc == -1) {
1085433d6423SLionel Sambuc 		test_fail("could not unlink test.txt");
1086433d6423SLionel Sambuc 	}
1087433d6423SLionel Sambuc 
1088433d6423SLionel Sambuc 	exit(errct);
1089433d6423SLionel Sambuc }
1090433d6423SLionel Sambuc 
test_fd_passing_parent(int sd)1091cbc8a0dfSDavid van Moolenbroek static void test_fd_passing_parent(int sd)
1092433d6423SLionel Sambuc {
1093433d6423SLionel Sambuc 	int rc, fd;
1094433d6423SLionel Sambuc 	char x;
1095433d6423SLionel Sambuc 	struct msghdr msghdr;
1096433d6423SLionel Sambuc 	struct cmsghdr *cmsg;
1097433d6423SLionel Sambuc 	struct iovec iov;
1098433d6423SLionel Sambuc 	char buf[BUFSIZE];
1099433d6423SLionel Sambuc 
1100433d6423SLionel Sambuc 	memset(buf, '\0', BUFSIZE);
1101433d6423SLionel Sambuc 
1102433d6423SLionel Sambuc 	msghdr.msg_name = NULL;
1103433d6423SLionel Sambuc 	msghdr.msg_namelen = 0;
1104433d6423SLionel Sambuc 
1105433d6423SLionel Sambuc 	iov.iov_base = &x;
1106433d6423SLionel Sambuc 	iov.iov_len = 1;
1107433d6423SLionel Sambuc 	msghdr.msg_iov = &iov;
1108433d6423SLionel Sambuc 	msghdr.msg_iovlen = 1;
1109433d6423SLionel Sambuc 
1110433d6423SLionel Sambuc 	msghdr.msg_iov = &iov;
1111433d6423SLionel Sambuc 	msghdr.msg_iovlen = 1;
1112433d6423SLionel Sambuc 
1113433d6423SLionel Sambuc 	msghdr.msg_control = buf;
1114433d6423SLionel Sambuc 	msghdr.msg_controllen = BUFSIZE;
1115433d6423SLionel Sambuc 
1116433d6423SLionel Sambuc 	msghdr.msg_flags = 0;
1117433d6423SLionel Sambuc 
1118433d6423SLionel Sambuc 	rc = recvmsg(sd, &msghdr, 0);
1119433d6423SLionel Sambuc 	if (rc == -1) {
1120433d6423SLionel Sambuc 		test_fail("could not recv message.");
1121433d6423SLionel Sambuc 	}
1122433d6423SLionel Sambuc 
1123433d6423SLionel Sambuc 	cmsg = CMSG_FIRSTHDR(&msghdr);
1124433d6423SLionel Sambuc 	fd = ((int *) CMSG_DATA(cmsg))[0];
1125433d6423SLionel Sambuc 
1126433d6423SLionel Sambuc 	rc = write(fd, MSG, strlen(MSG));
1127433d6423SLionel Sambuc 	if (rc != strlen(MSG)) {
1128433d6423SLionel Sambuc 		test_fail("could not write the full message to test.txt");
1129433d6423SLionel Sambuc 	}
1130433d6423SLionel Sambuc 
1131433d6423SLionel Sambuc 	rc = close(fd);
1132433d6423SLionel Sambuc 	if (rc == -1) {
1133433d6423SLionel Sambuc 		test_fail("could not close test.txt");
1134433d6423SLionel Sambuc 	}
1135433d6423SLionel Sambuc 
1136433d6423SLionel Sambuc 	memset(buf, '\0', BUFSIZE);
1137433d6423SLionel Sambuc 	strcpy(buf, "done");
1138433d6423SLionel Sambuc 	rc = write(sd, buf, BUFSIZE);
1139433d6423SLionel Sambuc 	if (rc == -1) {
1140433d6423SLionel Sambuc 		test_fail("could not write to socket");
1141433d6423SLionel Sambuc 	}
1142433d6423SLionel Sambuc 
1143433d6423SLionel Sambuc 	rc = close(sd);
1144433d6423SLionel Sambuc 	if (rc == -1) {
1145433d6423SLionel Sambuc 		test_fail("could not close socket");
1146433d6423SLionel Sambuc 	}
1147433d6423SLionel Sambuc }
1148433d6423SLionel Sambuc 
test_permissions(void)1149cbc8a0dfSDavid van Moolenbroek static void test_permissions(void) {
1150433d6423SLionel Sambuc 	/* Test bind and connect for permission verification
1151433d6423SLionel Sambuc 	 *
1152433d6423SLionel Sambuc 	 * After creating a UDS socket we change user credentials. At that
1153433d6423SLionel Sambuc 	 * point we should not be allowed to bind or connect to the UDS socket
1154433d6423SLionel Sambuc 	 */
1155433d6423SLionel Sambuc 
1156433d6423SLionel Sambuc 	pid_t pid;
1157433d6423SLionel Sambuc 	int sd, rc, status;
1158433d6423SLionel Sambuc 	struct sockaddr_un addr;
1159433d6423SLionel Sambuc 
1160433d6423SLionel Sambuc 	memset(&addr, '\0', sizeof(struct sockaddr_un));
1161433d6423SLionel Sambuc 	addr.sun_family = AF_UNIX;
1162433d6423SLionel Sambuc 	strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
1163433d6423SLionel Sambuc 
1164433d6423SLionel Sambuc 	UNLINK(TEST_SUN_PATH);
1165433d6423SLionel Sambuc 
1166433d6423SLionel Sambuc 	pid = fork();
1167433d6423SLionel Sambuc 	if (pid < 0) test_fail("unable to fork");
1168433d6423SLionel Sambuc 	else if (pid == 0) {
1169433d6423SLionel Sambuc 		SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
1170433d6423SLionel Sambuc 		if (setuid(999) != 0) test_fail("unable to chance uid");
1171433d6423SLionel Sambuc 		rc = bind(sd, (struct sockaddr *) &addr,
1172433d6423SLionel Sambuc 				 sizeof(struct sockaddr_un));
1173433d6423SLionel Sambuc 		if (rc != -1) {
1174433d6423SLionel Sambuc 			test_fail("bind() should not have worked");
1175433d6423SLionel Sambuc 		}
1176433d6423SLionel Sambuc 		exit(errct);
1177433d6423SLionel Sambuc 	} else {
1178433d6423SLionel Sambuc 		rc = waitpid(pid, &status, 0);
1179433d6423SLionel Sambuc 		errct += WEXITSTATUS(status);
1180433d6423SLionel Sambuc 	}
1181433d6423SLionel Sambuc 
1182433d6423SLionel Sambuc 	/* the signal handler is only used by the client, but we have to
1183433d6423SLionel Sambuc 	 * install it now. if we don't the server may signal the client
1184433d6423SLionel Sambuc 	 * before the handler is installed.
1185433d6423SLionel Sambuc 	 */
1186433d6423SLionel Sambuc 	debug("installing signal handler");
1187433d6423SLionel Sambuc 	if (signal(SIGUSR1, test_xfer_sighdlr) == SIG_ERR) {
1188433d6423SLionel Sambuc 		test_fail("signal(SIGUSR1, test_xfer_sighdlr) failed");
1189433d6423SLionel Sambuc 	}
1190433d6423SLionel Sambuc 
1191433d6423SLionel Sambuc 	debug("signal handler installed");
1192433d6423SLionel Sambuc 
1193433d6423SLionel Sambuc 	server_ready = 0;
1194433d6423SLionel Sambuc 
1195433d6423SLionel Sambuc 	pid = fork();
1196433d6423SLionel Sambuc 	if (pid < 0) test_fail("unable to fork");
1197433d6423SLionel Sambuc 	else if (pid == 0) {
1198433d6423SLionel Sambuc 		while (server_ready == 0) {
1199433d6423SLionel Sambuc 			debug("[client] waiting for the server to signal");
1200433d6423SLionel Sambuc 			sleep(1);
1201433d6423SLionel Sambuc 		}
1202433d6423SLionel Sambuc 		SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
1203433d6423SLionel Sambuc 		if (setuid(999) != 0) test_fail("unable to chance uid");
1204433d6423SLionel Sambuc 		rc = connect(sd, (struct sockaddr *) &addr,
1205433d6423SLionel Sambuc 						sizeof(struct sockaddr_un));
1206433d6423SLionel Sambuc 		if (rc != -1)
1207433d6423SLionel Sambuc 			test_fail("connect should not have worked");
1208433d6423SLionel Sambuc 		exit(errct);
1209433d6423SLionel Sambuc 	} else {
1210433d6423SLionel Sambuc 		SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
1211433d6423SLionel Sambuc 		rc = bind(sd, (struct sockaddr *) &addr,
1212433d6423SLionel Sambuc 				 sizeof(struct sockaddr_un));
1213433d6423SLionel Sambuc 		if (rc == -1) {
1214433d6423SLionel Sambuc 			test_fail("bind() should have worked");
1215433d6423SLionel Sambuc 		}
1216433d6423SLionel Sambuc 
1217433d6423SLionel Sambuc 		rc = listen(sd, 8);
1218433d6423SLionel Sambuc 		if (rc == -1) {
1219433d6423SLionel Sambuc 			test_fail("listen(sd, 8) should have worked");
1220433d6423SLionel Sambuc 		}
1221433d6423SLionel Sambuc 		kill(pid, SIGUSR1);
1222433d6423SLionel Sambuc 		sleep(1);
1223433d6423SLionel Sambuc 		CLOSE(sd);
1224433d6423SLionel Sambuc 
1225433d6423SLionel Sambuc 		rc = waitpid(pid, &status, 0);
1226433d6423SLionel Sambuc 		errct += WEXITSTATUS(status);
1227433d6423SLionel Sambuc 	}
1228433d6423SLionel Sambuc 
1229433d6423SLionel Sambuc 	UNLINK(TEST_SUN_PATH);
1230433d6423SLionel Sambuc }
1231433d6423SLionel Sambuc 
test_fd_passing(void)1232cbc8a0dfSDavid van Moolenbroek static void test_fd_passing(void) {
1233433d6423SLionel Sambuc 	int status;
1234433d6423SLionel Sambuc 	int sv[2];
1235433d6423SLionel Sambuc 	pid_t pid;
1236433d6423SLionel Sambuc 	int rc;
1237433d6423SLionel Sambuc 
1238433d6423SLionel Sambuc 	rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
1239433d6423SLionel Sambuc 	if (rc == -1) {
1240433d6423SLionel Sambuc 		test_fail("socketpair failed");
1241433d6423SLionel Sambuc 	}
1242433d6423SLionel Sambuc 
1243433d6423SLionel Sambuc 	pid = fork();
1244433d6423SLionel Sambuc 	if (pid == -1) {
1245433d6423SLionel Sambuc 		test_fail("fork() failed");
1246433d6423SLionel Sambuc 
1247433d6423SLionel Sambuc 		rc = close(sv[0]);
1248433d6423SLionel Sambuc 		if (rc == -1) {
1249433d6423SLionel Sambuc 			test_fail("could not close sv[0]");
1250433d6423SLionel Sambuc 		}
1251433d6423SLionel Sambuc 
1252433d6423SLionel Sambuc 		rc = close(sv[1]);
1253433d6423SLionel Sambuc 		if (rc == -1) {
1254433d6423SLionel Sambuc 			test_fail("could not close sv[1]");
1255433d6423SLionel Sambuc 		}
1256433d6423SLionel Sambuc 
1257433d6423SLionel Sambuc 		exit(0);
1258433d6423SLionel Sambuc 	} else if (pid == 0) {
1259433d6423SLionel Sambuc 		rc = close(sv[0]);
1260433d6423SLionel Sambuc 		if (rc == -1) {
1261433d6423SLionel Sambuc 			test_fail("could not close sv[0]");
1262433d6423SLionel Sambuc 		}
1263433d6423SLionel Sambuc 
1264433d6423SLionel Sambuc 		test_fd_passing_child(sv[1]);
1265433d6423SLionel Sambuc 		test_fail("should never get here");
1266433d6423SLionel Sambuc 		exit(1);
1267433d6423SLionel Sambuc 	} else {
1268433d6423SLionel Sambuc 		rc = close(sv[1]);
1269433d6423SLionel Sambuc 		if (rc == -1) {
1270433d6423SLionel Sambuc 			test_fail("could not close sv[1]");
1271433d6423SLionel Sambuc 		}
1272433d6423SLionel Sambuc 
1273433d6423SLionel Sambuc 		test_fd_passing_parent(sv[0]);
1274433d6423SLionel Sambuc 
1275433d6423SLionel Sambuc 		/* wait for client to exit */
1276433d6423SLionel Sambuc 		do {
1277433d6423SLionel Sambuc 			errno = 0;
1278433d6423SLionel Sambuc 			rc = waitpid(pid, &status, 0);
1279433d6423SLionel Sambuc 		} while (rc == -1 && errno == EINTR);
1280433d6423SLionel Sambuc 
1281433d6423SLionel Sambuc 		/* we use the exit status to get its error count */
1282433d6423SLionel Sambuc 		errct += WEXITSTATUS(status);
1283433d6423SLionel Sambuc 	}
1284433d6423SLionel Sambuc }
1285433d6423SLionel Sambuc 
test_select(void)12867c48de6cSDavid van Moolenbroek static void test_select(void)
1287433d6423SLionel Sambuc {
1288cbc8a0dfSDavid van Moolenbroek 	int nfds = -1;
1289433d6423SLionel Sambuc 	int socks[2];
1290433d6423SLionel Sambuc 	fd_set readfds, writefds;
1291433d6423SLionel Sambuc 	struct timeval tv;
1292433d6423SLionel Sambuc 	int res = 0;
1293433d6423SLionel Sambuc 	char buf[1];
1294433d6423SLionel Sambuc 
1295433d6423SLionel Sambuc 	FD_ZERO(&readfds);
1296433d6423SLionel Sambuc 	FD_ZERO(&writefds);
1297433d6423SLionel Sambuc 
1298433d6423SLionel Sambuc 	tv.tv_sec = 2;
1299433d6423SLionel Sambuc 	tv.tv_usec = 0;	/* 2 sec time out */
1300433d6423SLionel Sambuc 
1301433d6423SLionel Sambuc 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0) {
1302433d6423SLionel Sambuc 		test_fail("Can't open socket pair.");
1303433d6423SLionel Sambuc 	}
1304433d6423SLionel Sambuc 	FD_SET(socks[0], &readfds);
1305433d6423SLionel Sambuc 	nfds = socks[0] + 1;
1306433d6423SLionel Sambuc 
1307433d6423SLionel Sambuc 	/* Close the write end of the socket to generate EOF on read end */
1308433d6423SLionel Sambuc 	if ((res = shutdown(socks[1], SHUT_WR)) != 0) {
1309433d6423SLionel Sambuc 		test_fail("shutdown failed\n");
1310433d6423SLionel Sambuc 	}
1311433d6423SLionel Sambuc 
1312433d6423SLionel Sambuc 	res = select(nfds, &readfds, NULL, NULL, &tv);
1313433d6423SLionel Sambuc 	if (res != 1) {
1314433d6423SLionel Sambuc 		test_fail("select should've returned 1 ready fd\n");
1315433d6423SLionel Sambuc 	}
1316433d6423SLionel Sambuc 	if (!(FD_ISSET(socks[0], &readfds))) {
1317433d6423SLionel Sambuc 		test_fail("The server didn't respond within 2 seconds");
1318433d6423SLionel Sambuc 	}
1319433d6423SLionel Sambuc 	/* Now try to read from empty, closed pipe */
1320433d6423SLionel Sambuc 	if (read(socks[0], buf, sizeof(buf)) != 0) {
1321433d6423SLionel Sambuc 		test_fail("reading from empty, closed pipe should return EOF");
1322433d6423SLionel Sambuc 	}
1323433d6423SLionel Sambuc 
1324433d6423SLionel Sambuc 	close(socks[0]);
1325433d6423SLionel Sambuc 
1326433d6423SLionel Sambuc 	/* Try again the other way around: create a socketpair, close the
1327433d6423SLionel Sambuc 	 * read end, and try to write. This should cause an EPIPE */
1328433d6423SLionel Sambuc 
1329433d6423SLionel Sambuc 	tv.tv_sec = 2;
1330433d6423SLionel Sambuc 	tv.tv_usec = 0;	/* 2 sec time out */
1331433d6423SLionel Sambuc 
1332433d6423SLionel Sambuc 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0) {
1333433d6423SLionel Sambuc 		test_fail("Can't open socket pair.");
1334433d6423SLionel Sambuc 	}
1335433d6423SLionel Sambuc 	FD_SET(socks[1], &writefds);
1336433d6423SLionel Sambuc 	nfds = socks[1] + 1;
1337433d6423SLionel Sambuc 
1338433d6423SLionel Sambuc 	/* kill the read end of the socket to generate EPIPE on write end */
1339433d6423SLionel Sambuc 	if ((res = shutdown(socks[0], SHUT_RD)) != 0) {
1340433d6423SLionel Sambuc 		test_fail("shutdown failed\n");
1341433d6423SLionel Sambuc 	}
1342433d6423SLionel Sambuc 
1343433d6423SLionel Sambuc 	res = select(nfds, NULL, &writefds, NULL, &tv);
1344433d6423SLionel Sambuc 	if (res != 1) {
1345433d6423SLionel Sambuc 		test_fail("select should've returned 1 ready fd\n");
1346433d6423SLionel Sambuc 	}
1347433d6423SLionel Sambuc 	if (!(FD_ISSET(socks[1], &writefds))) {
1348433d6423SLionel Sambuc 		test_fail("The server didn't respond within 2 seconds");
1349433d6423SLionel Sambuc 	}
1350433d6423SLionel Sambuc 
1351433d6423SLionel Sambuc 	/* Now try to write to closed pipe */
1352433d6423SLionel Sambuc 	errno = 0;
1353433d6423SLionel Sambuc 	if ((res = write(socks[1], buf, sizeof(buf))) != -1) {
1354433d6423SLionel Sambuc 		printf("write res = %d\n", res);
1355433d6423SLionel Sambuc 		test_fail("writing to empty, closed pipe should fail");
1356433d6423SLionel Sambuc 	}
1357433d6423SLionel Sambuc 	if (errno != EPIPE) {
1358433d6423SLionel Sambuc 		printf("errno = %d\n", errno);
1359433d6423SLionel Sambuc 		test_fail("writing to closed pipe should return EPIPE\n");
1360433d6423SLionel Sambuc 	}
1361433d6423SLionel Sambuc 
1362433d6423SLionel Sambuc 	close(socks[1]);
1363433d6423SLionel Sambuc }
1364433d6423SLionel Sambuc 
test_select_close(void)1365cbc8a0dfSDavid van Moolenbroek static void test_select_close(void)
1366433d6423SLionel Sambuc {
1367433d6423SLionel Sambuc 	int res, socks[2];
1368433d6423SLionel Sambuc 	fd_set readfds;
1369433d6423SLionel Sambuc 	struct timeval tv;
1370433d6423SLionel Sambuc 
1371433d6423SLionel Sambuc 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0) {
1372433d6423SLionel Sambuc 		test_fail("Can't open socket pair.");
1373433d6423SLionel Sambuc 	}
1374433d6423SLionel Sambuc 
1375433d6423SLionel Sambuc 	switch (fork()) {
1376433d6423SLionel Sambuc 	case 0:
1377433d6423SLionel Sambuc 		sleep(1);
1378433d6423SLionel Sambuc 
1379433d6423SLionel Sambuc 		exit(0);
1380433d6423SLionel Sambuc 	case -1:
1381433d6423SLionel Sambuc 		test_fail("Can't fork.");
1382433d6423SLionel Sambuc 	default:
1383433d6423SLionel Sambuc 		break;
1384433d6423SLionel Sambuc 	}
1385433d6423SLionel Sambuc 
1386433d6423SLionel Sambuc 	close(socks[1]);
1387433d6423SLionel Sambuc 
1388433d6423SLionel Sambuc 	FD_ZERO(&readfds);
1389433d6423SLionel Sambuc 	FD_SET(socks[0], &readfds);
1390433d6423SLionel Sambuc 	tv.tv_sec = 2;
1391433d6423SLionel Sambuc 	tv.tv_usec = 0;	/* 2 sec time out */
1392433d6423SLionel Sambuc 
1393433d6423SLionel Sambuc 	res = select(socks[0] + 1, &readfds, NULL, NULL, &tv);
1394433d6423SLionel Sambuc 	if (res != 1) {
1395433d6423SLionel Sambuc 		test_fail("select should've returned 1 ready fd\n");
1396433d6423SLionel Sambuc 	}
1397433d6423SLionel Sambuc 	if (!(FD_ISSET(socks[0], &readfds))) {
1398433d6423SLionel Sambuc 		test_fail("The server didn't respond within 2 seconds");
1399433d6423SLionel Sambuc 	}
1400433d6423SLionel Sambuc 
1401433d6423SLionel Sambuc 	wait(NULL);
1402433d6423SLionel Sambuc 
1403433d6423SLionel Sambuc 	close(socks[0]);
1404433d6423SLionel Sambuc }
1405433d6423SLionel Sambuc 
test_fchmod(void)14067c48de6cSDavid van Moolenbroek static void test_fchmod(void)
1407433d6423SLionel Sambuc {
1408433d6423SLionel Sambuc 	int socks[2];
1409433d6423SLionel Sambuc 	struct stat st1, st2;
1410433d6423SLionel Sambuc 
1411433d6423SLionel Sambuc 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0) {
1412433d6423SLionel Sambuc 		test_fail("Can't open socket pair.");
1413433d6423SLionel Sambuc 	}
1414433d6423SLionel Sambuc 
1415433d6423SLionel Sambuc 	if (fstat(socks[0], &st1) < 0 || fstat(socks[1], &st2) < 0) {
1416433d6423SLionel Sambuc 		test_fail("fstat failed.");
1417433d6423SLionel Sambuc 	}
1418433d6423SLionel Sambuc 
1419433d6423SLionel Sambuc 	if ((st1.st_mode & (S_IRUSR|S_IWUSR)) == S_IRUSR &&
1420433d6423SLionel Sambuc 		(st2.st_mode & (S_IRUSR|S_IWUSR)) == S_IWUSR) {
1421433d6423SLionel Sambuc 		test_fail("fstat failed.");
1422433d6423SLionel Sambuc 	}
1423433d6423SLionel Sambuc 
1424433d6423SLionel Sambuc 	if (fchmod(socks[0], S_IRUSR) < 0 ||
1425433d6423SLionel Sambuc                     fstat(socks[0], &st1) < 0 ||
1426433d6423SLionel Sambuc                     (st1.st_mode & (S_IRUSR|S_IWUSR)) != S_IRUSR) {
1427433d6423SLionel Sambuc 		test_fail("fchmod/fstat mode set/check failed (1).");
1428433d6423SLionel Sambuc 	}
1429433d6423SLionel Sambuc 
1430433d6423SLionel Sambuc 	if (fchmod(socks[1], S_IWUSR) < 0 || fstat(socks[1], &st2) < 0 ||
1431433d6423SLionel Sambuc                     (st2.st_mode & (S_IRUSR|S_IWUSR)) != S_IWUSR) {
1432433d6423SLionel Sambuc 		test_fail("fchmod/fstat mode set/check failed (2).");
1433433d6423SLionel Sambuc 	}
1434433d6423SLionel Sambuc 
1435433d6423SLionel Sambuc 	close(socks[0]);
1436433d6423SLionel Sambuc 	close(socks[1]);
1437433d6423SLionel Sambuc }
1438433d6423SLionel Sambuc 
14390eb6caa0SDavid van Moolenbroek /*
14400eb6caa0SDavid van Moolenbroek  * Test various aspects related to the socket files on the file system.
14410eb6caa0SDavid van Moolenbroek  * This subtest is woefully incomplete and currently only attempts to test
14420eb6caa0SDavid van Moolenbroek  * aspects that have recently been affected by code changes.  In the future,
1443*27852ebeSDavid van Moolenbroek  * there should be tests for the entire range of file system path and access
1444*27852ebeSDavid van Moolenbroek  * related error codes (TODO).
14450eb6caa0SDavid van Moolenbroek  */
14460eb6caa0SDavid van Moolenbroek static void
test_file(void)14470eb6caa0SDavid van Moolenbroek test_file(void)
14480eb6caa0SDavid van Moolenbroek {
1449*27852ebeSDavid van Moolenbroek 	struct sockaddr_un addr, saddr, saddr2;
1450dd969671SDavid van Moolenbroek 	char buf[1];
1451dd969671SDavid van Moolenbroek 	socklen_t len;
1452dd969671SDavid van Moolenbroek 	struct stat st;
1453dd969671SDavid van Moolenbroek 	mode_t omask;
1454*27852ebeSDavid van Moolenbroek 	int sd, sd2, csd, fd;
14550eb6caa0SDavid van Moolenbroek 
1456dd969671SDavid van Moolenbroek 	/*
1457dd969671SDavid van Moolenbroek 	 * If the provided socket path exists on the file system, the bind(2)
1458dd969671SDavid van Moolenbroek 	 * call must fail, regardless of whether there is a socket that is
1459dd969671SDavid van Moolenbroek 	 * bound to that address.
1460dd969671SDavid van Moolenbroek 	 */
14610eb6caa0SDavid van Moolenbroek 	UNLINK(TEST_SUN_PATH);
14620eb6caa0SDavid van Moolenbroek 
14630eb6caa0SDavid van Moolenbroek 	memset(&addr, 0, sizeof(addr));
14640eb6caa0SDavid van Moolenbroek 	addr.sun_family = AF_UNIX;
14650eb6caa0SDavid van Moolenbroek 	strlcpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path));
14660eb6caa0SDavid van Moolenbroek 
1467dd969671SDavid van Moolenbroek 	if ((sd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1)
1468dd969671SDavid van Moolenbroek 		test_fail("Can't open socket");
1469dd969671SDavid van Moolenbroek 	if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
1470dd969671SDavid van Moolenbroek 		test_fail("Can't bind socket");
1471dd969671SDavid van Moolenbroek 
1472dd969671SDavid van Moolenbroek 	if ((sd2 = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1)
1473dd969671SDavid van Moolenbroek 		test_fail("Can't open socket");
1474dd969671SDavid van Moolenbroek 	if (bind(sd2, (struct sockaddr *)&addr, sizeof(addr)) != -1)
1475dd969671SDavid van Moolenbroek 		test_fail("Binding socket unexpectedly succeeded");
1476dd969671SDavid van Moolenbroek 	if (errno != EADDRINUSE)
1477dd969671SDavid van Moolenbroek 		test_fail("Binding socket failed with wrong error");
1478dd969671SDavid van Moolenbroek 
1479dd969671SDavid van Moolenbroek 	CLOSE(sd);
1480dd969671SDavid van Moolenbroek 
1481dd969671SDavid van Moolenbroek 	if (bind(sd2, (struct sockaddr *)&addr, sizeof(addr)) != -1)
1482dd969671SDavid van Moolenbroek 		test_fail("Binding socket unexpectedly succeeded");
1483dd969671SDavid van Moolenbroek 	if (errno != EADDRINUSE)
1484dd969671SDavid van Moolenbroek 		test_fail("Binding socket failed with wrong error");
1485dd969671SDavid van Moolenbroek 
1486dd969671SDavid van Moolenbroek 	CLOSE(sd2);
1487dd969671SDavid van Moolenbroek 
1488dd969671SDavid van Moolenbroek 	UNLINK(TEST_SUN_PATH);
1489dd969671SDavid van Moolenbroek 
1490dd969671SDavid van Moolenbroek 	/*
1491dd969671SDavid van Moolenbroek 	 * If the socket is removed from the file system while there is still a
1492dd969671SDavid van Moolenbroek 	 * socket bound to it, it should be possible to bind a new socket to
1493dd969671SDavid van Moolenbroek 	 * the address.  The old socket should then become unreachable in terms
1494dd969671SDavid van Moolenbroek 	 * of connections and data directed to the address, even though it
1495dd969671SDavid van Moolenbroek 	 * should still appear to be bound to the same address.
1496dd969671SDavid van Moolenbroek 	 */
1497dd969671SDavid van Moolenbroek 	if ((sd = socket(PF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0)) == -1)
1498dd969671SDavid van Moolenbroek 		test_fail("Can't open socket");
1499dd969671SDavid van Moolenbroek 	if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
1500dd969671SDavid van Moolenbroek 		test_fail("Can't bind socket");
1501dd969671SDavid van Moolenbroek 	memset(&saddr, 0, sizeof(saddr));
1502dd969671SDavid van Moolenbroek 	len = sizeof(saddr);
1503dd969671SDavid van Moolenbroek 	if (getsockname(sd, (struct sockaddr *)&saddr, &len) != 0)
1504dd969671SDavid van Moolenbroek 		test_fail("Can't get socket address");
1505dd969671SDavid van Moolenbroek 
1506dd969671SDavid van Moolenbroek 	if ((csd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1)
1507dd969671SDavid van Moolenbroek 		test_fail("Can't open client socket");
1508dd969671SDavid van Moolenbroek 
1509dd969671SDavid van Moolenbroek 	memset(buf, 'X', sizeof(buf));
1510dd969671SDavid van Moolenbroek 	if (sendto(csd, buf, sizeof(buf), 0, (struct sockaddr *)&addr,
1511dd969671SDavid van Moolenbroek 	    sizeof(addr)) != sizeof(buf))
1512dd969671SDavid van Moolenbroek 		test_fail("Can't send to socket");
1513dd969671SDavid van Moolenbroek 	if (recvfrom(sd, buf, sizeof(buf), 0, NULL, 0) != sizeof(buf))
1514dd969671SDavid van Moolenbroek 		test_fail("Can't receive from socket");
1515dd969671SDavid van Moolenbroek 	if (buf[0] != 'X')
1516dd969671SDavid van Moolenbroek 		test_fail("Transmission failure");
1517dd969671SDavid van Moolenbroek 
1518dd969671SDavid van Moolenbroek 	if (unlink(TEST_SUN_PATH) != 0)
1519dd969671SDavid van Moolenbroek 		test_fail("Can't unlink socket");
1520dd969671SDavid van Moolenbroek 
1521dd969671SDavid van Moolenbroek 	if ((sd2 = socket(PF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0)) == -1)
1522dd969671SDavid van Moolenbroek 		test_fail("Can't open socket");
1523dd969671SDavid van Moolenbroek 	if (bind(sd2, (struct sockaddr *)&addr, sizeof(addr)) != 0)
1524dd969671SDavid van Moolenbroek 		test_fail("Can't bind socket");
1525dd969671SDavid van Moolenbroek 	memset(&saddr2, 0, sizeof(saddr2));
1526dd969671SDavid van Moolenbroek 	len = sizeof(saddr2);
1527dd969671SDavid van Moolenbroek 	if (getsockname(sd2, (struct sockaddr *)&saddr2, &len) != 0)
1528dd969671SDavid van Moolenbroek 		test_fail("Can't get socket address");
1529dd969671SDavid van Moolenbroek 	if (memcmp(&saddr, &saddr2, sizeof(saddr)))
1530dd969671SDavid van Moolenbroek 		test_fail("Unexpected socket address");
1531dd969671SDavid van Moolenbroek 
1532dd969671SDavid van Moolenbroek 	memset(buf, 'Y', sizeof(buf));
1533dd969671SDavid van Moolenbroek 	if (sendto(csd, buf, sizeof(buf), 0, (struct sockaddr *)&addr,
1534dd969671SDavid van Moolenbroek 	    sizeof(addr)) != sizeof(buf))
1535dd969671SDavid van Moolenbroek 		test_fail("Can't send to socket");
1536dd969671SDavid van Moolenbroek 	if (recvfrom(sd, buf, sizeof(buf), 0, NULL, 0) != -1)
1537dd969671SDavid van Moolenbroek 		test_fail("Unexpectedly received from old socket");
1538dd969671SDavid van Moolenbroek 	if (errno != EWOULDBLOCK)
1539dd969671SDavid van Moolenbroek 		test_fail("Wrong receive failure from old socket");
1540dd969671SDavid van Moolenbroek 	if (recvfrom(sd2, buf, sizeof(buf), 0, NULL, 0) != sizeof(buf))
1541dd969671SDavid van Moolenbroek 		test_fail("Can't receive from new socket");
1542dd969671SDavid van Moolenbroek 	if (buf[0] != 'Y')
1543dd969671SDavid van Moolenbroek 		test_fail("Transmission failure");
1544dd969671SDavid van Moolenbroek 
1545dd969671SDavid van Moolenbroek 	len = sizeof(saddr2);
1546dd969671SDavid van Moolenbroek 	if (getsockname(sd, (struct sockaddr *)&saddr2, &len) != 0)
1547dd969671SDavid van Moolenbroek 		test_fail("Can't get old socket address");
1548dd969671SDavid van Moolenbroek 	if (memcmp(&saddr, &saddr2, sizeof(saddr)))
1549dd969671SDavid van Moolenbroek 		test_fail("Unexpected old socket address");
1550dd969671SDavid van Moolenbroek 
1551dd969671SDavid van Moolenbroek 	if (unlink(TEST_SUN_PATH) != 0)
1552dd969671SDavid van Moolenbroek 		test_fail("Can't unlink socket");
1553dd969671SDavid van Moolenbroek 
1554dd969671SDavid van Moolenbroek 	CLOSE(sd);
1555dd969671SDavid van Moolenbroek 	CLOSE(sd2);
1556dd969671SDavid van Moolenbroek 	CLOSE(csd);
1557dd969671SDavid van Moolenbroek 
1558dd969671SDavid van Moolenbroek 	/*
1559dd969671SDavid van Moolenbroek 	 * If the socket path identifies a file that is not a socket, bind(2)
1560dd969671SDavid van Moolenbroek 	 * should still fail with EADDRINUSE, but connect(2) and sendto(2)
1561dd969671SDavid van Moolenbroek 	 * should fail with ENOTSOCK (the latter is not specified by POSIX, so
1562dd969671SDavid van Moolenbroek 	 * we follow NetBSD here).
1563dd969671SDavid van Moolenbroek 	 */
1564dd969671SDavid van Moolenbroek 	if ((fd = open(TEST_SUN_PATH, O_WRONLY | O_CREAT | O_EXCL, 0700)) < 0)
1565dd969671SDavid van Moolenbroek 		test_fail("Can't create regular file");
1566dd969671SDavid van Moolenbroek 	CLOSE(fd);
1567dd969671SDavid van Moolenbroek 
1568dd969671SDavid van Moolenbroek 	if ((sd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1)
1569dd969671SDavid van Moolenbroek 		test_fail("Can't open socket");
1570dd969671SDavid van Moolenbroek 	if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != -1)
1571dd969671SDavid van Moolenbroek 		test_fail("Binding socket unexpectedly succeeded");
1572dd969671SDavid van Moolenbroek 	if (errno != EADDRINUSE)
1573dd969671SDavid van Moolenbroek 		test_fail("Binding socket failed with wrong error");
1574dd969671SDavid van Moolenbroek 	if (sendto(sd, buf, sizeof(buf), 0, (struct sockaddr *)&addr,
1575dd969671SDavid van Moolenbroek 	    sizeof(addr)) != -1)
1576dd969671SDavid van Moolenbroek 		test_fail("Sending to socket unexpectedly succeeded");
1577dd969671SDavid van Moolenbroek 	if (errno != ENOTSOCK)
1578dd969671SDavid van Moolenbroek 		test_fail("Sending to socket failed with wrong error");
1579dd969671SDavid van Moolenbroek 	CLOSE(sd);
1580dd969671SDavid van Moolenbroek 
1581dd969671SDavid van Moolenbroek 	if ((sd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
1582dd969671SDavid van Moolenbroek 		test_fail("Can't open socket");
1583dd969671SDavid van Moolenbroek 	if (connect(sd, (struct sockaddr *)&addr, sizeof(addr)) != -1)
1584dd969671SDavid van Moolenbroek 		test_fail("Connecting socket unexpectedly succeeded");
1585dd969671SDavid van Moolenbroek 	if (errno != ENOTSOCK)
1586dd969671SDavid van Moolenbroek 		test_fail("Connecting socket failed with wrong error");
1587dd969671SDavid van Moolenbroek 	CLOSE(sd);
1588dd969671SDavid van Moolenbroek 
1589dd969671SDavid van Moolenbroek 	UNLINK(TEST_SUN_PATH);
1590dd969671SDavid van Moolenbroek 
1591dd969671SDavid van Moolenbroek 	/*
1592dd969671SDavid van Moolenbroek 	 * The created socket file should have an access mode of 0777 corrected
1593dd969671SDavid van Moolenbroek 	 * with the calling process's file mode creation mask.
1594dd969671SDavid van Moolenbroek 	 */
1595dd969671SDavid van Moolenbroek 	omask = umask(045123);
1596dd969671SDavid van Moolenbroek 
1597dd969671SDavid van Moolenbroek 	if ((sd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1)
1598dd969671SDavid van Moolenbroek 		test_fail("Can't open socket");
1599dd969671SDavid van Moolenbroek 	if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
1600dd969671SDavid van Moolenbroek 		test_fail("Can't bind socket");
1601dd969671SDavid van Moolenbroek 
1602dd969671SDavid van Moolenbroek 	if (stat(TEST_SUN_PATH, &st) != 0)
1603dd969671SDavid van Moolenbroek 		test_fail("Can't stat socket");
1604dd969671SDavid van Moolenbroek 	if (!S_ISSOCK(st.st_mode))
1605dd969671SDavid van Moolenbroek 		test_fail("File is not a socket");
1606dd969671SDavid van Moolenbroek 	if ((st.st_mode & ALLPERMS) != (ACCESSPERMS & ~0123))
1607dd969671SDavid van Moolenbroek 		test_fail("Unexpected file permission mask");
1608dd969671SDavid van Moolenbroek 
1609dd969671SDavid van Moolenbroek 	CLOSE(sd);
1610dd969671SDavid van Moolenbroek 	UNLINK(TEST_SUN_PATH);
1611dd969671SDavid van Moolenbroek 
1612dd969671SDavid van Moolenbroek 	umask(omask);
1613dd969671SDavid van Moolenbroek 
16140eb6caa0SDavid van Moolenbroek 	/*
16150eb6caa0SDavid van Moolenbroek 	 * Only socket(2), socketpair(2), and accept(2) may be used to obtain
16160eb6caa0SDavid van Moolenbroek 	 * new file descriptors to sockets (or "sockets"); open(2) on a socket
16170eb6caa0SDavid van Moolenbroek 	 * file is expected to fail with EOPNOTSUPP (Austin Group Issue #943),
16180eb6caa0SDavid van Moolenbroek 	 * regardless of whether the socket is in use.
16190eb6caa0SDavid van Moolenbroek 	 */
16200eb6caa0SDavid van Moolenbroek 	if ((sd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1)
16210eb6caa0SDavid van Moolenbroek 		test_fail("Can't open socket");
16220eb6caa0SDavid van Moolenbroek 	if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
16230eb6caa0SDavid van Moolenbroek 		test_fail("Can't bind socket");
16240eb6caa0SDavid van Moolenbroek 
16250eb6caa0SDavid van Moolenbroek 	if (open(TEST_SUN_PATH, O_RDWR) != -1)
16260eb6caa0SDavid van Moolenbroek 		test_fail("Unexpectedly opened socket file");
16270eb6caa0SDavid van Moolenbroek 	if (errno != EOPNOTSUPP)
16280eb6caa0SDavid van Moolenbroek 		test_fail("Open failed with wrong error");
16290eb6caa0SDavid van Moolenbroek 
16300eb6caa0SDavid van Moolenbroek 	CLOSE(sd);
16310eb6caa0SDavid van Moolenbroek 
16320eb6caa0SDavid van Moolenbroek 	if (open(TEST_SUN_PATH, O_RDONLY) != -1)
16330eb6caa0SDavid van Moolenbroek 		test_fail("Unexpectedly opened socket file");
16340eb6caa0SDavid van Moolenbroek 	if (errno != EOPNOTSUPP)
16350eb6caa0SDavid van Moolenbroek 		test_fail("Open failed with wrong error");
16360eb6caa0SDavid van Moolenbroek 
16370eb6caa0SDavid van Moolenbroek 	UNLINK(TEST_SUN_PATH);
16380eb6caa0SDavid van Moolenbroek }
16390eb6caa0SDavid van Moolenbroek 
main(int argc,char * argv[])1640433d6423SLionel Sambuc int main(int argc, char *argv[])
1641433d6423SLionel Sambuc {
1642433d6423SLionel Sambuc 	int i;
1643294d1590SErik van der Kouwe 	struct sockaddr_un clientaddr = {
1644294d1590SErik van der Kouwe 		.sun_family = AF_UNIX,
1645294d1590SErik van der Kouwe 		.sun_path = TEST_SUN_PATH,
1646294d1590SErik van der Kouwe 	};
1647294d1590SErik van der Kouwe 	struct sockaddr_un clientaddr2 = {
1648294d1590SErik van der Kouwe 		.sun_family = AF_UNIX,
1649294d1590SErik van der Kouwe 		.sun_path = TEST_SUN_PATHB,
1650294d1590SErik van der Kouwe 	};
1651294d1590SErik van der Kouwe 	struct sockaddr_un clientaddrsym = {
1652294d1590SErik van der Kouwe 		.sun_family = AF_UNIX,
1653294d1590SErik van der Kouwe 		.sun_path = TEST_SYM_A,
1654294d1590SErik van der Kouwe 	};
1655294d1590SErik van der Kouwe 	const struct socket_test_info info = {
1656294d1590SErik van der Kouwe 		.clientaddr               = (struct sockaddr *) &clientaddr,
1657294d1590SErik van der Kouwe 		.clientaddrlen            = sizeof(clientaddr),
1658294d1590SErik van der Kouwe 		.clientaddr2              = (struct sockaddr *) &clientaddr2,
1659294d1590SErik van der Kouwe 		.clientaddr2len           = sizeof(clientaddr2),
1660294d1590SErik van der Kouwe 		.clientaddrsym            = (struct sockaddr *) &clientaddrsym,
1661294d1590SErik van der Kouwe 		.clientaddrsymlen         = sizeof(clientaddrsym),
1662294d1590SErik van der Kouwe 		.domain                   = PF_UNIX,
1663*27852ebeSDavid van Moolenbroek 		.expected_rcvbuf          = 32768 - 5, /* no constants: */
1664*27852ebeSDavid van Moolenbroek 		.expected_sndbuf          = 32768 - 5, /* UDS internals */
1665294d1590SErik van der Kouwe 		.serveraddr               = (struct sockaddr *) &clientaddr,
1666294d1590SErik van der Kouwe 		.serveraddrlen            = sizeof(clientaddr),
1667294d1590SErik van der Kouwe 		.serveraddr2              = (struct sockaddr *) &clientaddr2,
1668294d1590SErik van der Kouwe 		.serveraddr2len           = sizeof(clientaddr2),
1669294d1590SErik van der Kouwe 		.type                     = SOCK_STREAM,
1670294d1590SErik van der Kouwe 		.types                    = types,
1671294d1590SErik van der Kouwe 		.typecount                = 3,
1672294d1590SErik van der Kouwe 		.callback_check_sockaddr  = callback_check_sockaddr,
1673294d1590SErik van der Kouwe 		.callback_cleanup         = callback_cleanup,
1674294d1590SErik van der Kouwe 		.callback_xfer_prepclient = callback_xfer_prepclient,
1675294d1590SErik van der Kouwe 		.callback_xfer_peercred   = callback_xfer_peercred,
1676*27852ebeSDavid van Moolenbroek 		.callback_set_listen_opt  = callback_set_listen_opt,
1677294d1590SErik van der Kouwe 	};
1678433d6423SLionel Sambuc 
1679433d6423SLionel Sambuc 	debug("entering main()");
1680433d6423SLionel Sambuc 
1681433d6423SLionel Sambuc 	start(56);
1682433d6423SLionel Sambuc 
1683*27852ebeSDavid van Moolenbroek 	/* This test was written before UDS started supporting SIGPIPE. */
1684*27852ebeSDavid van Moolenbroek 	signal(SIGPIPE, SIG_IGN);
1685*27852ebeSDavid van Moolenbroek 
1686294d1590SErik van der Kouwe 	test_socket(&info);
1687294d1590SErik van der Kouwe 	test_bind(&info);
1688294d1590SErik van der Kouwe 	test_bind_unix();
1689294d1590SErik van der Kouwe 	test_listen(&info);
1690294d1590SErik van der Kouwe 	test_getsockname(&info);
1691433d6423SLionel Sambuc 	test_header();
1692294d1590SErik van der Kouwe 	test_shutdown(&info);
1693294d1590SErik van der Kouwe 	test_close(&info);
1694433d6423SLionel Sambuc 	test_permissions();
1695294d1590SErik van der Kouwe 	test_dup(&info);
1696294d1590SErik van der Kouwe 	test_dup2(&info);
1697433d6423SLionel Sambuc 	test_socketpair();
1698294d1590SErik van der Kouwe 	test_shutdown(&info);
1699294d1590SErik van der Kouwe 	test_read(&info);
1700294d1590SErik van der Kouwe 	test_write(&info);
1701294d1590SErik van der Kouwe 	test_sockopts(&info);
1702433d6423SLionel Sambuc 	test_ucred();
1703294d1590SErik van der Kouwe 	test_xfer(&info);
1704433d6423SLionel Sambuc 
1705433d6423SLionel Sambuc 	for (i = 0; i < 3; i++) {
1706294d1590SErik van der Kouwe 		test_simple_client_server(&info, types[i]);
1707433d6423SLionel Sambuc 		if (types[i] != SOCK_DGRAM) test_vectorio(types[i]);
1708433d6423SLionel Sambuc 		if (types[i] != SOCK_DGRAM) test_msg(types[i]);
1709433d6423SLionel Sambuc 	}
1710294d1590SErik van der Kouwe 
1711294d1590SErik van der Kouwe 	test_abort_client_server(&info, 1);
1712294d1590SErik van der Kouwe 	test_abort_client_server(&info, 2);
1713294d1590SErik van der Kouwe 	test_msg_dgram(&info);
1714294d1590SErik van der Kouwe 	test_connect(&info);
1715433d6423SLionel Sambuc 	test_multiproc_read();
1716433d6423SLionel Sambuc 	test_multiproc_write();
1717433d6423SLionel Sambuc 	test_scm_credentials();
1718433d6423SLionel Sambuc 	test_fd_passing();
1719433d6423SLionel Sambuc 	test_select();
1720433d6423SLionel Sambuc 	test_select_close();
1721433d6423SLionel Sambuc 	test_fchmod();
1722294d1590SErik van der Kouwe 	test_nonblock(&info);
1723294d1590SErik van der Kouwe 	test_connect_nb(&info);
1724294d1590SErik van der Kouwe 	test_intr(&info);
1725294d1590SErik van der Kouwe 	test_connect_close(&info);
1726294d1590SErik van der Kouwe 	test_listen_close(&info);
1727294d1590SErik van der Kouwe 	test_listen_close_nb(&info);
17280eb6caa0SDavid van Moolenbroek 	test_file();
1729433d6423SLionel Sambuc 
1730433d6423SLionel Sambuc 	quit();
1731433d6423SLionel Sambuc 
1732433d6423SLionel Sambuc 	return -1;	/* we should never get here */
1733433d6423SLionel Sambuc }
1734