Deleted Added
full compact
unix_cmsg.c (243314) unix_cmsg.c (246670)
1/*-
2 * Copyright (c) 2005 Andrey Simonenko
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2005 Andrey Simonenko
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/tools/regression/sockets/unix_cmsg/unix_cmsg.c 243314 2012-11-19 22:56:51Z emaste $");
28__FBSDID("$FreeBSD: head/tools/regression/sockets/unix_cmsg/unix_cmsg.c 246670 2013-02-11 12:56:23Z pluknet $");
29
29
30#include <sys/types.h>
30#include <sys/param.h>
31#include <sys/resource.h>
32#include <sys/time.h>
31#include <sys/resource.h>
32#include <sys/time.h>
33#include <sys/select.h>
33#include <sys/socket.h>
34#include <sys/socket.h>
35#include <sys/ucred.h>
34#include <sys/un.h>
35#include <sys/wait.h>
36
36#include <sys/un.h>
37#include <sys/wait.h>
38
37#include <assert.h>
38#include <ctype.h>
39#include <err.h>
40#include <errno.h>
39#include <ctype.h>
40#include <err.h>
41#include <errno.h>
42#include <fcntl.h>
41#include <inttypes.h>
42#include <limits.h>
43#include <inttypes.h>
44#include <limits.h>
43#include <setjmp.h>
45#include <paths.h>
44#include <signal.h>
45#include <stdarg.h>
46#include <signal.h>
47#include <stdarg.h>
48#include <stdbool.h>
46#include <stdint.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
49#include <stdint.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
50#include <sysexits.h>
51#include <unistd.h>
52
53/*
54 * There are tables with tests descriptions and pointers to test
55 * functions. Each t_*() function returns 0 if its test passed,
53#include <unistd.h>
54
55/*
56 * There are tables with tests descriptions and pointers to test
57 * functions. Each t_*() function returns 0 if its test passed,
56 * -1 if its test failed (something wrong was found in local domain
57 * control messages), -2 if some system error occurred. If test
58 * function returns -2, then a program exits.
58 * -1 if its test failed, -2 if some system error occurred.
59 * If a test function returns -2, then a program exits.
59 *
60 *
60 * Each test function completely control what to do (eg. fork or
61 * do not fork a client process). If a test function forks a client
62 * process, then it waits for its termination. If a return code of a
63 * client process is not equal to zero, or if a client process was
64 * terminated by a signal, then test function returns -2.
61 * If a test function forks a client process, then it waits for its
62 * termination. If a return code of a client process is not equal
63 * to zero, or if a client process was terminated by a signal, then
64 * a test function returns -1 or -2 depending on exit status of
65 * a client process.
65 *
66 *
66 * Each test function and complete program are not optimized
67 * a lot to allow easy to modify tests.
68 *
69 * Each function which can block, is run under TIMEOUT, if timeout
70 * occurs, then test function returns -2 or a client process exits
71 * with nonzero return code.
67 * Each function which can block, is run under TIMEOUT. If timeout
68 * occurs, then a test function returns -2 or a client process exits
69 * with a non-zero return code.
72 */
73
74#ifndef LISTENQ
75# define LISTENQ 1
76#endif
77
78#ifndef TIMEOUT
70 */
71
72#ifndef LISTENQ
73# define LISTENQ 1
74#endif
75
76#ifndef TIMEOUT
79# define TIMEOUT 60
77# define TIMEOUT 2
80#endif
81
78#endif
79
82#define EXTRA_CMSG_SPACE 512 /* Memory for not expected control data. */
80static int t_cmsgcred(void);
81static int t_sockcred_1(void);
82static int t_sockcred_2(void);
83static int t_cmsgcred_sockcred(void);
84static int t_timeval(void);
85static int t_bintime(void);
86static int t_cmsg_len(void);
87static int t_peercred(void);
83
88
84static int t_cmsgcred(void), t_sockcred_stream1(void);
85static int t_sockcred_stream2(void), t_cmsgcred_sockcred(void);
86static int t_sockcred_dgram(void), t_timestamp(void);
87
88struct test_func {
89struct test_func {
89 int (*func)(void); /* Pointer to function. */
90 const char *desc; /* Test description. */
90 int (*func)(void);
91 const char *desc;
91};
92
92};
93
93static struct test_func test_stream_tbl[] = {
94 { NULL, " 0: All tests" },
95 { t_cmsgcred, " 1: Sending, receiving cmsgcred" },
96 { t_sockcred_stream1, " 2: Receiving sockcred (listening socket has LOCAL_CREDS)" },
97 { t_sockcred_stream2, " 3: Receiving sockcred (accepted socket has LOCAL_CREDS)" },
98 { t_cmsgcred_sockcred, " 4: Sending cmsgcred, receiving sockcred" },
99 { t_timestamp, " 5: Sending, receiving timestamp" },
100 { NULL, NULL }
94static const struct test_func test_stream_tbl[] = {
95 {
96 .func = NULL,
97 .desc = "All tests"
98 },
99 {
100 .func = t_cmsgcred,
101 .desc = "Sending, receiving cmsgcred"
102 },
103 {
104 .func = t_sockcred_1,
105 .desc = "Receiving sockcred (listening socket)"
106 },
107 {
108 .func = t_sockcred_2,
109 .desc = "Receiving sockcred (accepted socket)"
110 },
111 {
112 .func = t_cmsgcred_sockcred,
113 .desc = "Sending cmsgcred, receiving sockcred"
114 },
115 {
116 .func = t_timeval,
117 .desc = "Sending, receiving timeval"
118 },
119 {
120 .func = t_bintime,
121 .desc = "Sending, receiving bintime"
122 },
123 {
124 .func = t_cmsg_len,
125 .desc = "Check cmsghdr.cmsg_len"
126 },
127 {
128 .func = t_peercred,
129 .desc = "Check LOCAL_PEERCRED socket option"
130 }
101};
102
131};
132
103static struct test_func test_dgram_tbl[] = {
104 { NULL, " 0: All tests" },
105 { t_cmsgcred, " 1: Sending, receiving cmsgcred" },
106 { t_sockcred_dgram, " 2: Receiving sockcred" },
107 { t_cmsgcred_sockcred, " 3: Sending cmsgcred, receiving sockcred" },
108 { t_timestamp, " 4: Sending, receiving timestamp" },
109 { NULL, NULL }
133#define TEST_STREAM_TBL_SIZE \
134 (sizeof(test_stream_tbl) / sizeof(test_stream_tbl[0]))
135
136static const struct test_func test_dgram_tbl[] = {
137 {
138 .func = NULL,
139 .desc = "All tests"
140 },
141 {
142 .func = t_cmsgcred,
143 .desc = "Sending, receiving cmsgcred"
144 },
145 {
146 .func = t_sockcred_2,
147 .desc = "Receiving sockcred"
148 },
149 {
150 .func = t_cmsgcred_sockcred,
151 .desc = "Sending cmsgcred, receiving sockcred"
152 },
153 {
154 .func = t_timeval,
155 .desc = "Sending, receiving timeval"
156 },
157 {
158 .func = t_bintime,
159 .desc = "Sending, receiving bintime"
160 },
161 {
162 .func = t_cmsg_len,
163 .desc = "Check cmsghdr.cmsg_len"
164 }
110};
111
165};
166
112#define TEST_STREAM_NO_MAX (sizeof(test_stream_tbl) / sizeof(struct test_func) - 2)
113#define TEST_DGRAM_NO_MAX (sizeof(test_dgram_tbl) / sizeof(struct test_func) - 2)
167#define TEST_DGRAM_TBL_SIZE \
168 (sizeof(test_dgram_tbl) / sizeof(test_dgram_tbl[0]))
114
169
115static const char *myname = "SERVER"; /* "SERVER" or "CLIENT" */
170static bool debug = false;
171static bool server_flag = true;
172static bool send_data_flag = true;
173static bool send_array_flag = true;
174static bool failed_flag = false;
116
175
117static int debug = 0; /* 1, if -d. */
118static int no_control_data = 0; /* 1, if -z. */
176static int sock_type;
177static const char *sock_type_str;
119
178
120static u_int nfailed = 0; /* Number of failed tests. */
179static const char *proc_name;
121
180
122static int sock_type; /* SOCK_STREAM or SOCK_DGRAM */
123static const char *sock_type_str; /* "SOCK_STREAM" or "SOCK_DGRAN" */
181static char work_dir[] = _PATH_TMP "unix_cmsg.XXXXXXX";
182static int serv_sock_fd;
183static struct sockaddr_un serv_addr_sun;
124
184
125static char tempdir[] = "/tmp/unix_cmsg.XXXXXXX";
126static char serv_sock_path[PATH_MAX];
185static struct {
186 char *buf_send;
187 char *buf_recv;
188 size_t buf_size;
189 u_int msg_num;
190} ipc_msg;
127
191
128static char ipc_message[] = "hello";
192#define IPC_MSG_NUM_DEF 5
193#define IPC_MSG_NUM_MAX 10
194#define IPC_MSG_SIZE_DEF 7
195#define IPC_MSG_SIZE_MAX 128
129
196
130#define IPC_MESSAGE_SIZE (sizeof(ipc_message))
197static struct {
198 uid_t uid;
199 uid_t euid;
200 gid_t gid;
201 gid_t egid;
202 gid_t *gid_arr;
203 int gid_num;
204} proc_cred;
131
205
132static struct sockaddr_un servaddr; /* Server address. */
206static pid_t client_pid;
133
207
134static sigjmp_buf env_alrm;
208#define SYNC_SERVER 0
209#define SYNC_CLIENT 1
210#define SYNC_RECV 0
211#define SYNC_SEND 1
135
212
136static uid_t my_uid;
137static uid_t my_euid;
138static gid_t my_gid;
139static gid_t my_egid;
213static int sync_fd[2][2];
140
214
141/*
142 * my_gids[0] is EGID, next items are supplementary GIDs,
143 * my_ngids determines valid items in my_gids array.
144 */
145static gid_t my_gids[NGROUPS_MAX];
146static int my_ngids;
215#define LOGMSG_SIZE 128
147
216
148static pid_t client_pid; /* PID of forked client. */
149
150#define dbgmsg(x) do { \
151 if (debug) \
152 logmsgx x ; \
153} while (/* CONSTCOND */0)
154
155static void logmsg(const char *, ...) __printflike(1, 2);
156static void logmsgx(const char *, ...) __printflike(1, 2);
217static void logmsg(const char *, ...) __printflike(1, 2);
218static void logmsgx(const char *, ...) __printflike(1, 2);
219static void dbgmsg(const char *, ...) __printflike(1, 2);
157static void output(const char *, ...) __printflike(1, 2);
158
220static void output(const char *, ...) __printflike(1, 2);
221
159extern char *__progname; /* The name of program. */
160
161/*
162 * Output the help message (-h switch).
163 */
164static void
222static void
165usage(int quick)
223usage(bool verbose)
166{
224{
167 const struct test_func *test_func;
225 u_int i;
168
226
169 fprintf(stderr, "Usage: %s [-dhz] [-t <socktype>] [testno]\n",
170 __progname);
171 if (quick)
227 printf("usage: %s [-dh] [-n num] [-s size] [-t type] "
228 "[-z value] [testno]\n", getprogname());
229 if (!verbose)
172 return;
230 return;
173 fprintf(stderr, "\n Options are:\n\
174 -d\t\t\tOutput debugging information\n\
175 -h\t\t\tOutput this help message and exit\n\
176 -t <socktype>\t\tRun test only for the given socket type:\n\
177\t\t\tstream or dgram\n\
178 -z\t\t\tDo not send real control data if possible\n\n");
179 fprintf(stderr, " Available tests for stream sockets:\n");
180 for (test_func = test_stream_tbl; test_func->desc != NULL; ++test_func)
181 fprintf(stderr, " %s\n", test_func->desc);
182 fprintf(stderr, "\n Available tests for datagram sockets:\n");
183 for (test_func = test_dgram_tbl; test_func->desc != NULL; ++test_func)
184 fprintf(stderr, " %s\n", test_func->desc);
231 printf("\n Options are:\n\
232 -d Output debugging information\n\
233 -h Output the help message and exit\n\
234 -n num Number of messages to send\n\
235 -s size Specify size of data for IPC\n\
236 -t type Specify socket type (stream, dgram) for tests\n\
237 -z value Do not send data in a message (bit 0x1), do not send\n\
238 data array associated with a cmsghdr structure (bit 0x2)\n\
239 testno Run one test by its number (require the -t option)\n\n");
240 printf(" Available tests for stream sockets:\n");
241 for (i = 0; i < TEST_STREAM_TBL_SIZE; ++i)
242 printf(" %u: %s\n", i, test_stream_tbl[i].desc);
243 printf("\n Available tests for datagram sockets:\n");
244 for (i = 0; i < TEST_DGRAM_TBL_SIZE; ++i)
245 printf(" %u: %s\n", i, test_dgram_tbl[i].desc);
185}
186
246}
247
187/*
188 * printf-like function for outputting to STDOUT_FILENO.
189 */
190static void
191output(const char *format, ...)
192{
248static void
249output(const char *format, ...)
250{
193 char buf[128];
251 char buf[LOGMSG_SIZE];
194 va_list ap;
195
196 va_start(ap, format);
197 if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
252 va_list ap;
253
254 va_start(ap, format);
255 if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
198 err(EX_SOFTWARE, "output: vsnprintf failed");
256 err(EXIT_FAILURE, "output: vsnprintf failed");
199 write(STDOUT_FILENO, buf, strlen(buf));
200 va_end(ap);
201}
202
257 write(STDOUT_FILENO, buf, strlen(buf));
258 va_end(ap);
259}
260
203/*
204 * printf-like function for logging, also outputs message for errno.
205 */
206static void
207logmsg(const char *format, ...)
208{
261static void
262logmsg(const char *format, ...)
263{
209 char buf[128];
264 char buf[LOGMSG_SIZE];
210 va_list ap;
211 int errno_save;
212
265 va_list ap;
266 int errno_save;
267
213 errno_save = errno; /* Save errno. */
214
268 errno_save = errno;
215 va_start(ap, format);
216 if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
269 va_start(ap, format);
270 if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
217 err(EX_SOFTWARE, "logmsg: vsnprintf failed");
271 err(EXIT_FAILURE, "logmsg: vsnprintf failed");
218 if (errno_save == 0)
272 if (errno_save == 0)
219 output("%s: %s\n", myname, buf);
273 output("%s: %s\n", proc_name, buf);
220 else
274 else
221 output("%s: %s: %s\n", myname, buf, strerror(errno_save));
275 output("%s: %s: %s\n", proc_name, buf, strerror(errno_save));
222 va_end(ap);
276 va_end(ap);
277 errno = errno_save;
278}
223
279
224 errno = errno_save; /* Restore errno. */
280static void
281vlogmsgx(const char *format, va_list ap)
282{
283 char buf[LOGMSG_SIZE];
284
285 if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
286 err(EXIT_FAILURE, "logmsgx: vsnprintf failed");
287 output("%s: %s\n", proc_name, buf);
288
225}
226
289}
290
227/*
228 * printf-like function for logging, do not output message for errno.
229 */
230static void
231logmsgx(const char *format, ...)
232{
291static void
292logmsgx(const char *format, ...)
293{
233 char buf[128];
234 va_list ap;
235
236 va_start(ap, format);
294 va_list ap;
295
296 va_start(ap, format);
237 if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
238 err(EX_SOFTWARE, "logmsgx: vsnprintf failed");
239 output("%s: %s\n", myname, buf);
297 vlogmsgx(format, ap);
240 va_end(ap);
241}
242
298 va_end(ap);
299}
300
243/*
244 * Run tests from testno1 to testno2.
245 */
301static void
302dbgmsg(const char *format, ...)
303{
304 va_list ap;
305
306 if (debug) {
307 va_start(ap, format);
308 vlogmsgx(format, ap);
309 va_end(ap);
310 }
311}
312
246static int
313static int
247run_tests(u_int testno1, u_int testno2)
314run_tests(int type, u_int testno1)
248{
315{
249 const struct test_func *test_func;
250 u_int i, nfailed1;
316 const struct test_func *tf;
317 u_int i, testno2, failed_num;
251
318
252 output("Running tests for %s sockets:\n", sock_type_str);
253 test_func = (sock_type == SOCK_STREAM ?
254 test_stream_tbl : test_dgram_tbl) + testno1;
319 sock_type = type;
320 if (type == SOCK_STREAM) {
321 sock_type_str = "SOCK_STREAM";
322 tf = test_stream_tbl;
323 i = TEST_STREAM_TBL_SIZE - 1;
324 } else {
325 sock_type_str = "SOCK_DGRAM";
326 tf = test_dgram_tbl;
327 i = TEST_DGRAM_TBL_SIZE - 1;
328 }
329 if (testno1 == 0) {
330 testno1 = 1;
331 testno2 = i;
332 } else
333 testno2 = testno1;
255
334
256 nfailed1 = 0;
257 for (i = testno1; i <= testno2; ++test_func, ++i) {
258 output(" %s\n", test_func->desc);
259 switch (test_func->func()) {
335 output("Running tests for %s sockets:\n", sock_type_str);
336 failed_num = 0;
337 for (i = testno1, tf += testno1; i <= testno2; ++tf, ++i) {
338 output(" %u: %s\n", i, tf->desc);
339 switch (tf->func()) {
260 case -1:
340 case -1:
261 ++nfailed1;
341 ++failed_num;
262 break;
263 case -2:
342 break;
343 case -2:
264 logmsgx("some system error occurred, exiting");
344 logmsgx("some system error or timeout occurred");
265 return (-1);
266 }
267 }
268
345 return (-1);
346 }
347 }
348
269 nfailed += nfailed1;
349 if (failed_num != 0)
350 failed_flag = true;
270
271 if (testno1 != testno2) {
351
352 if (testno1 != testno2) {
272 if (nfailed1 == 0)
273 output("-- all tests were passed!\n");
353 if (failed_num == 0)
354 output("-- all tests passed!\n");
274 else
355 else
275 output("-- %u test%s failed!\n", nfailed1,
276 nfailed1 == 1 ? "" : "s");
356 output("-- %u test%s failed!\n",
357 failed_num, failed_num == 1 ? "" : "s");
277 } else {
358 } else {
278 if (nfailed == 0)
279 output("-- test was passed!\n");
359 if (failed_num == 0)
360 output("-- test passed!\n");
280 else
281 output("-- test failed!\n");
282 }
283
284 return (0);
285}
286
361 else
362 output("-- test failed!\n");
363 }
364
365 return (0);
366}
367
287/* ARGSUSED */
288static void
289sig_alrm(int signo __unused)
368static int
369init(void)
290{
370{
291 siglongjmp(env_alrm, 1);
371 struct sigaction sigact;
372 size_t idx;
373 int rv;
374
375 proc_name = "SERVER";
376
377 sigact.sa_handler = SIG_IGN;
378 sigact.sa_flags = 0;
379 sigemptyset(&sigact.sa_mask);
380 if (sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL) < 0) {
381 logmsg("init: sigaction");
382 return (-1);
383 }
384
385 if (ipc_msg.buf_size == 0)
386 ipc_msg.buf_send = ipc_msg.buf_recv = NULL;
387 else {
388 ipc_msg.buf_send = malloc(ipc_msg.buf_size);
389 ipc_msg.buf_recv = malloc(ipc_msg.buf_size);
390 if (ipc_msg.buf_send == NULL || ipc_msg.buf_recv == NULL) {
391 logmsg("init: malloc");
392 return (-1);
393 }
394 for (idx = 0; idx < ipc_msg.buf_size; ++idx)
395 ipc_msg.buf_send[idx] = (char)idx;
396 }
397
398 proc_cred.uid = getuid();
399 proc_cred.euid = geteuid();
400 proc_cred.gid = getgid();
401 proc_cred.egid = getegid();
402 proc_cred.gid_num = getgroups(0, (gid_t *)NULL);
403 if (proc_cred.gid_num < 0) {
404 logmsg("init: getgroups");
405 return (-1);
406 }
407 proc_cred.gid_arr = malloc(proc_cred.gid_num *
408 sizeof(*proc_cred.gid_arr));
409 if (proc_cred.gid_arr == NULL) {
410 logmsg("init: malloc");
411 return (-1);
412 }
413 if (getgroups(proc_cred.gid_num, proc_cred.gid_arr) < 0) {
414 logmsg("init: getgroups");
415 return (-1);
416 }
417
418 memset(&serv_addr_sun, 0, sizeof(serv_addr_sun));
419 rv = snprintf(serv_addr_sun.sun_path, sizeof(serv_addr_sun.sun_path),
420 "%s/%s", work_dir, proc_name);
421 if (rv < 0) {
422 logmsg("init: snprintf");
423 return (-1);
424 }
425 if ((size_t)rv >= sizeof(serv_addr_sun.sun_path)) {
426 logmsgx("init: not enough space for socket pathname");
427 return (-1);
428 }
429 serv_addr_sun.sun_family = PF_LOCAL;
430 serv_addr_sun.sun_len = SUN_LEN(&serv_addr_sun);
431
432 return (0);
292}
293
433}
434
294/*
295 * Initialize signals handlers.
296 */
435static int
436client_fork(void)
437{
438 int fd1, fd2;
439
440 if (pipe(sync_fd[SYNC_SERVER]) < 0 ||
441 pipe(sync_fd[SYNC_CLIENT]) < 0) {
442 logmsg("client_fork: pipe");
443 return (-1);
444 }
445 client_pid = fork();
446 if (client_pid == (pid_t)-1) {
447 logmsg("client_fork: fork");
448 return (-1);
449 }
450 if (client_pid == 0) {
451 proc_name = "CLIENT";
452 server_flag = false;
453 fd1 = sync_fd[SYNC_SERVER][SYNC_RECV];
454 fd2 = sync_fd[SYNC_CLIENT][SYNC_SEND];
455 } else {
456 fd1 = sync_fd[SYNC_SERVER][SYNC_SEND];
457 fd2 = sync_fd[SYNC_CLIENT][SYNC_RECV];
458 }
459 if (close(fd1) < 0 || close(fd2) < 0) {
460 logmsg("client_fork: close");
461 return (-1);
462 }
463 return (client_pid != 0);
464}
465
297static void
466static void
298sig_init(void)
467client_exit(int rv)
299{
468{
300 struct sigaction sa;
469 if (close(sync_fd[SYNC_SERVER][SYNC_SEND]) < 0 ||
470 close(sync_fd[SYNC_CLIENT][SYNC_RECV]) < 0) {
471 logmsg("client_exit: close");
472 rv = -1;
473 }
474 rv = rv == 0 ? EXIT_SUCCESS : -rv;
475 dbgmsg("exit: code %d", rv);
476 _exit(rv);
477}
301
478
302 sa.sa_handler = SIG_IGN;
303 sigemptyset(&sa.sa_mask);
304 sa.sa_flags = 0;
305 if (sigaction(SIGPIPE, &sa, (struct sigaction *)NULL) < 0)
306 err(EX_OSERR, "sigaction(SIGPIPE)");
479static int
480client_wait(void)
481{
482 int status;
483 pid_t pid;
307
484
308 sa.sa_handler = sig_alrm;
309 if (sigaction(SIGALRM, &sa, (struct sigaction *)NULL) < 0)
310 err(EX_OSERR, "sigaction(SIGALRM)");
485 dbgmsg("waiting for client");
486
487 if (close(sync_fd[SYNC_SERVER][SYNC_RECV]) < 0 ||
488 close(sync_fd[SYNC_CLIENT][SYNC_SEND]) < 0) {
489 logmsg("client_wait: close");
490 return (-1);
491 }
492
493 pid = waitpid(client_pid, &status, 0);
494 if (pid == (pid_t)-1) {
495 logmsg("client_wait: waitpid");
496 return (-1);
497 }
498
499 if (WIFEXITED(status)) {
500 if (WEXITSTATUS(status) != EXIT_SUCCESS) {
501 logmsgx("client exit status is %d",
502 WEXITSTATUS(status));
503 return (-WEXITSTATUS(status));
504 }
505 } else {
506 if (WIFSIGNALED(status))
507 logmsgx("abnormal termination of client, signal %d%s",
508 WTERMSIG(status), WCOREDUMP(status) ?
509 " (core file generated)" : "");
510 else
511 logmsgx("termination of client, unknown status");
512 return (-1);
513 }
514
515 return (0);
311}
312
313int
314main(int argc, char *argv[])
315{
316 const char *errstr;
516}
517
518int
519main(int argc, char *argv[])
520{
521 const char *errstr;
317 int opt, dgramflag, streamflag;
318 u_int testno1, testno2;
522 u_int testno, zvalue;
523 int opt, rv;
524 bool dgram_flag, stream_flag;
319
525
320 dgramflag = streamflag = 0;
321 while ((opt = getopt(argc, argv, "dht:z")) != -1)
526 ipc_msg.buf_size = IPC_MSG_SIZE_DEF;
527 ipc_msg.msg_num = IPC_MSG_NUM_DEF;
528 dgram_flag = stream_flag = false;
529 while ((opt = getopt(argc, argv, "dhn:s:t:z:")) != -1)
322 switch (opt) {
323 case 'd':
530 switch (opt) {
531 case 'd':
324 debug = 1;
532 debug = true;
325 break;
326 case 'h':
533 break;
534 case 'h':
327 usage(0);
328 return (EX_OK);
535 usage(true);
536 return (EXIT_SUCCESS);
537 case 'n':
538 ipc_msg.msg_num = strtonum(optarg, 1,
539 IPC_MSG_NUM_MAX, &errstr);
540 if (errstr != NULL)
541 errx(EXIT_FAILURE, "option -n: number is %s",
542 errstr);
543 break;
544 case 's':
545 ipc_msg.buf_size = strtonum(optarg, 0,
546 IPC_MSG_SIZE_MAX, &errstr);
547 if (errstr != NULL)
548 errx(EXIT_FAILURE, "option -s: number is %s",
549 errstr);
550 break;
329 case 't':
330 if (strcmp(optarg, "stream") == 0)
551 case 't':
552 if (strcmp(optarg, "stream") == 0)
331 streamflag = 1;
553 stream_flag = true;
332 else if (strcmp(optarg, "dgram") == 0)
554 else if (strcmp(optarg, "dgram") == 0)
333 dgramflag = 1;
555 dgram_flag = true;
334 else
556 else
335 errx(EX_USAGE, "wrong socket type in -t option");
557 errx(EXIT_FAILURE, "option -t: "
558 "wrong socket type");
336 break;
337 case 'z':
559 break;
560 case 'z':
338 no_control_data = 1;
561 zvalue = strtonum(optarg, 0, 3, &errstr);
562 if (errstr != NULL)
563 errx(EXIT_FAILURE, "option -z: number is %s",
564 errstr);
565 if (zvalue & 0x1)
566 send_data_flag = false;
567 if (zvalue & 0x2)
568 send_array_flag = false;
339 break;
569 break;
340 case '?':
341 default:
570 default:
342 usage(1);
343 return (EX_USAGE);
571 usage(false);
572 return (EXIT_FAILURE);
344 }
345
346 if (optind < argc) {
347 if (optind + 1 != argc)
573 }
574
575 if (optind < argc) {
576 if (optind + 1 != argc)
348 errx(EX_USAGE, "too many arguments");
349 testno1 = strtonum(argv[optind], 0, UINT_MAX, &errstr);
577 errx(EXIT_FAILURE, "too many arguments");
578 testno = strtonum(argv[optind], 0, UINT_MAX, &errstr);
350 if (errstr != NULL)
579 if (errstr != NULL)
351 errx(EX_USAGE, "wrong test number: %s", errstr);
580 errx(EXIT_FAILURE, "test number is %s", errstr);
581 if (stream_flag && testno >= TEST_STREAM_TBL_SIZE)
582 errx(EXIT_FAILURE, "given test %u for stream "
583 "sockets does not exist", testno);
584 if (dgram_flag && testno >= TEST_DGRAM_TBL_SIZE)
585 errx(EXIT_FAILURE, "given test %u for datagram "
586 "sockets does not exist", testno);
352 } else
587 } else
353 testno1 = 0;
588 testno = 0;
354
589
355 if (dgramflag == 0 && streamflag == 0)
356 dgramflag = streamflag = 1;
357
358 if (dgramflag && streamflag && testno1 != 0)
359 errx(EX_USAGE, "you can use particular test, only with datagram or stream sockets");
360
361 if (streamflag) {
362 if (testno1 > TEST_STREAM_NO_MAX)
363 errx(EX_USAGE, "given test %u for stream sockets does not exist",
364 testno1);
365 } else {
366 if (testno1 > TEST_DGRAM_NO_MAX)
367 errx(EX_USAGE, "given test %u for datagram sockets does not exist",
368 testno1);
590 if (!dgram_flag && !stream_flag) {
591 if (testno != 0)
592 errx(EXIT_FAILURE, "particular test number "
593 "can be used with the -t option only");
594 dgram_flag = stream_flag = true;
369 }
370
595 }
596
371 my_uid = getuid();
372 my_euid = geteuid();
373 my_gid = getgid();
374 my_egid = getegid();
375 switch (my_ngids = getgroups(sizeof(my_gids) / sizeof(my_gids[0]), my_gids)) {
376 case -1:
377 err(EX_SOFTWARE, "getgroups");
378 /* NOTREACHED */
379 case 0:
380 errx(EX_OSERR, "getgroups returned 0 groups");
381 }
597 if (mkdtemp(work_dir) == NULL)
598 err(EXIT_FAILURE, "mkdtemp(%s)", work_dir);
382
599
383 sig_init();
600 rv = EXIT_FAILURE;
601 if (init() < 0)
602 goto done;
384
603
385 if (mkdtemp(tempdir) == NULL)
386 err(EX_OSERR, "mkdtemp");
604 if (stream_flag)
605 if (run_tests(SOCK_STREAM, testno) < 0)
606 goto done;
607 if (dgram_flag)
608 if (run_tests(SOCK_DGRAM, testno) < 0)
609 goto done;
387
610
388 if (streamflag) {
389 sock_type = SOCK_STREAM;
390 sock_type_str = "SOCK_STREAM";
391 if (testno1 == 0) {
392 testno1 = 1;
393 testno2 = TEST_STREAM_NO_MAX;
394 } else
395 testno2 = testno1;
396 if (run_tests(testno1, testno2) < 0)
397 goto failed;
398 testno1 = 0;
611 rv = EXIT_SUCCESS;
612done:
613 if (rmdir(work_dir) < 0) {
614 logmsg("rmdir(%s)", work_dir);
615 rv = EXIT_FAILURE;
399 }
616 }
617 return (failed_flag ? EXIT_FAILURE : rv);
618}
400
619
401 if (dgramflag) {
402 sock_type = SOCK_DGRAM;
403 sock_type_str = "SOCK_DGRAM";
404 if (testno1 == 0) {
405 testno1 = 1;
406 testno2 = TEST_DGRAM_NO_MAX;
407 } else
408 testno2 = testno1;
409 if (run_tests(testno1, testno2) < 0)
410 goto failed;
411 }
620static int
621socket_close(int fd)
622{
623 int rv;
412
624
413 if (rmdir(tempdir) < 0) {
414 logmsg("rmdir(%s)", tempdir);
415 return (EX_OSERR);
625 rv = 0;
626 if (close(fd) < 0) {
627 logmsg("socket_close: close");
628 rv = -1;
416 }
629 }
417
418 return (nfailed ? EX_OSERR : EX_OK);
419
420failed:
421 if (rmdir(tempdir) < 0)
422 logmsg("rmdir(%s)", tempdir);
423 return (EX_OSERR);
630 if (server_flag && fd == serv_sock_fd)
631 if (unlink(serv_addr_sun.sun_path) < 0) {
632 logmsg("socket_close: unlink(%s)",
633 serv_addr_sun.sun_path);
634 rv = -1;
635 }
636 return (rv);
424}
425
637}
638
426/*
427 * Create PF_LOCAL socket, if sock_path is not equal to NULL, then
428 * bind() it. Return socket address in addr. Return file descriptor
429 * or -1 if some error occurred.
430 */
431static int
639static int
432create_socket(char *sock_path, size_t sock_path_len, struct sockaddr_un *addr)
640socket_create(void)
433{
641{
434 int rv, fd;
642 struct timeval tv;
643 int fd;
435
644
436 if ((fd = socket(PF_LOCAL, sock_type, 0)) < 0) {
437 logmsg("create_socket: socket(PF_LOCAL, %s, 0)", sock_type_str);
645 fd = socket(PF_LOCAL, sock_type, 0);
646 if (fd < 0) {
647 logmsg("socket_create: socket(PF_LOCAL, %s, 0)", sock_type_str);
438 return (-1);
439 }
648 return (-1);
649 }
650 if (server_flag)
651 serv_sock_fd = fd;
440
652
441 if (sock_path != NULL) {
442 if ((rv = snprintf(sock_path, sock_path_len, "%s/%s",
443 tempdir, myname)) < 0) {
444 logmsg("create_socket: snprintf failed");
445 goto failed;
446 }
447 if ((size_t)rv >= sock_path_len) {
448 logmsgx("create_socket: too long path name for given buffer");
449 goto failed;
450 }
653 tv.tv_sec = TIMEOUT;
654 tv.tv_usec = 0;
655 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 ||
656 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
657 logmsg("socket_create: setsockopt(SO_RCVTIMEO/SO_SNDTIMEO)");
658 goto failed;
659 }
451
660
452 memset(addr, 0, sizeof(*addr));
453 addr->sun_family = AF_LOCAL;
454 if (strlen(sock_path) >= sizeof(addr->sun_path)) {
455 logmsgx("create_socket: too long path name (>= %lu) for local domain socket",
456 (u_long)sizeof(addr->sun_path));
661 if (server_flag) {
662 if (bind(fd, (struct sockaddr *)&serv_addr_sun,
663 serv_addr_sun.sun_len) < 0) {
664 logmsg("socket_create: bind(%s)",
665 serv_addr_sun.sun_path);
457 goto failed;
458 }
666 goto failed;
667 }
459 strcpy(addr->sun_path, sock_path);
668 if (sock_type == SOCK_STREAM) {
669 int val;
460
670
461 if (bind(fd, (struct sockaddr *)addr, SUN_LEN(addr)) < 0) {
462 logmsg("create_socket: bind(%s)", sock_path);
463 goto failed;
671 if (listen(fd, LISTENQ) < 0) {
672 logmsg("socket_create: listen");
673 goto failed;
674 }
675 val = fcntl(fd, F_GETFL, 0);
676 if (val < 0) {
677 logmsg("socket_create: fcntl(F_GETFL)");
678 goto failed;
679 }
680 if (fcntl(fd, F_SETFL, val | O_NONBLOCK) < 0) {
681 logmsg("socket_create: fcntl(F_SETFL)");
682 goto failed;
683 }
464 }
465 }
466
467 return (fd);
468
469failed:
470 if (close(fd) < 0)
684 }
685 }
686
687 return (fd);
688
689failed:
690 if (close(fd) < 0)
471 logmsg("create_socket: close");
691 logmsg("socket_create: close");
692 if (server_flag)
693 if (unlink(serv_addr_sun.sun_path) < 0)
694 logmsg("socket_close: unlink(%s)",
695 serv_addr_sun.sun_path);
472 return (-1);
473}
474
696 return (-1);
697}
698
475/*
476 * Call create_socket() for server listening socket.
477 * Return socket descriptor or -1 if some error occurred.
478 */
479static int
699static int
480create_server_socket(void)
700socket_connect(int fd)
481{
701{
482 return (create_socket(serv_sock_path, sizeof(serv_sock_path), &servaddr));
483}
702 dbgmsg("connect");
484
703
485/*
486 * Create unbound socket.
487 */
488static int
489create_unbound_socket(void)
490{
491 return (create_socket((char *)NULL, 0, (struct sockaddr_un *)NULL));
704 if (connect(fd, (struct sockaddr *)&serv_addr_sun,
705 serv_addr_sun.sun_len) < 0) {
706 logmsg("socket_connect: connect(%s)", serv_addr_sun.sun_path);
707 return (-1);
708 }
709 return (0);
492}
493
710}
711
494/*
495 * Close socket descriptor, if sock_path is not equal to NULL,
496 * then unlink the given path.
497 */
498static int
712static int
499close_socket(const char *sock_path, int fd)
713sync_recv(void)
500{
714{
501 int error = 0;
715 ssize_t ssize;
716 int fd;
717 char buf;
502
718
503 if (close(fd) < 0) {
504 logmsg("close_socket: close");
505 error = -1;
506 }
507 if (sock_path != NULL)
508 if (unlink(sock_path) < 0) {
509 logmsg("close_socket: unlink(%s)", sock_path);
510 error = -1;
511 }
512 return (error);
513}
719 dbgmsg("sync: wait");
514
720
515/*
516 * Connect to server (socket address in servaddr).
517 */
518static int
519connect_server(int fd)
520{
521 dbgmsg(("connecting to %s", serv_sock_path));
721 fd = sync_fd[server_flag ? SYNC_SERVER : SYNC_CLIENT][SYNC_RECV];
522
722
523 /*
524 * If PF_LOCAL listening socket's queue is full, then connect()
525 * returns ECONNREFUSED immediately, do not need timeout.
526 */
527 if (connect(fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
528 logmsg("connect_server: connect(%s)", serv_sock_path);
723 ssize = read(fd, &buf, 1);
724 if (ssize < 0) {
725 logmsg("sync_recv: read");
529 return (-1);
530 }
726 return (-1);
727 }
728 if (ssize < 1) {
729 logmsgx("sync_recv: read %zd of 1 byte", ssize);
730 return (-1);
731 }
531
732
733 dbgmsg("sync: received");
734
532 return (0);
533}
534
735 return (0);
736}
737
535/*
536 * sendmsg() with timeout.
537 */
538static int
738static int
539sendmsg_timeout(int fd, struct msghdr *msg, size_t n)
739sync_send(void)
540{
740{
541 ssize_t nsent;
741 ssize_t ssize;
742 int fd;
542
743
543 dbgmsg(("sending %lu bytes", (u_long)n));
744 dbgmsg("sync: send");
544
745
545 if (sigsetjmp(env_alrm, 1) != 0) {
546 logmsgx("sendmsg_timeout: cannot send message to %s (timeout)", serv_sock_path);
547 return (-1);
548 }
746 fd = sync_fd[server_flag ? SYNC_CLIENT : SYNC_SERVER][SYNC_SEND];
549
747
550 (void)alarm(TIMEOUT);
551
552 nsent = sendmsg(fd, msg, 0);
553
554 (void)alarm(0);
555
556 if (nsent < 0) {
557 logmsg("sendmsg_timeout: sendmsg");
748 ssize = write(fd, "", 1);
749 if (ssize < 0) {
750 logmsg("sync_send: write");
558 return (-1);
559 }
751 return (-1);
752 }
560
561 if ((size_t)nsent != n) {
562 logmsgx("sendmsg_timeout: sendmsg: short send: %ld of %lu bytes",
563 (long)nsent, (u_long)n);
753 if (ssize < 1) {
754 logmsgx("sync_send: sent %zd of 1 byte", ssize);
564 return (-1);
565 }
566
567 return (0);
568}
569
755 return (-1);
756 }
757
758 return (0);
759}
760
570/*
571 * accept() with timeout.
572 */
573static int
761static int
574accept_timeout(int listenfd)
762message_send(int fd, const struct msghdr *msghdr)
575{
763{
576 int fd;
764 const struct cmsghdr *cmsghdr;
765 size_t size;
766 ssize_t ssize;
577
767
578 dbgmsg(("accepting connection"));
768 size = msghdr->msg_iov != 0 ? msghdr->msg_iov->iov_len : 0;
769 dbgmsg("send: data size %zu", size);
770 dbgmsg("send: msghdr.msg_controllen %u",
771 (u_int)msghdr->msg_controllen);
772 cmsghdr = CMSG_FIRSTHDR(msghdr);
773 if (cmsghdr != NULL)
774 dbgmsg("send: cmsghdr.cmsg_len %u",
775 (u_int)cmsghdr->cmsg_len);
579
776
580 if (sigsetjmp(env_alrm, 1) != 0) {
581 logmsgx("accept_timeout: cannot accept connection (timeout)");
777 ssize = sendmsg(fd, msghdr, 0);
778 if (ssize < 0) {
779 logmsg("message_send: sendmsg");
582 return (-1);
583 }
780 return (-1);
781 }
782 if ((size_t)ssize != size) {
783 logmsgx("message_send: sendmsg: sent %zd of %zu bytes",
784 ssize, size);
785 return (-1);
786 }
584
787
585 (void)alarm(TIMEOUT);
788 if (!send_data_flag)
789 if (sync_send() < 0)
790 return (-1);
586
791
587 fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL);
792 return (0);
793}
588
794
589 (void)alarm(0);
795static int
796message_sendn(int fd, struct msghdr *msghdr)
797{
798 u_int i;
590
799
591 if (fd < 0) {
592 logmsg("accept_timeout: accept");
593 return (-1);
800 for (i = 1; i <= ipc_msg.msg_num; ++i) {
801 dbgmsg("message #%u", i);
802 if (message_send(fd, msghdr) < 0)
803 return (-1);
594 }
804 }
595
596 return (fd);
805 return (0);
597}
598
806}
807
599/*
600 * recvmsg() with timeout.
601 */
602static int
808static int
603recvmsg_timeout(int fd, struct msghdr *msg, size_t n)
809message_recv(int fd, struct msghdr *msghdr)
604{
810{
605 ssize_t nread;
811 const struct cmsghdr *cmsghdr;
812 size_t size;
813 ssize_t ssize;
606
814
607 dbgmsg(("receiving %lu bytes", (u_long)n));
815 if (!send_data_flag)
816 if (sync_recv() < 0)
817 return (-1);
608
818
609 if (sigsetjmp(env_alrm, 1) != 0) {
610 logmsgx("recvmsg_timeout: cannot receive message (timeout)");
819 size = msghdr->msg_iov != NULL ? msghdr->msg_iov->iov_len : 0;
820 ssize = recvmsg(fd, msghdr, MSG_WAITALL);
821 if (ssize < 0) {
822 logmsg("message_recv: recvmsg");
611 return (-1);
612 }
823 return (-1);
824 }
613
614 (void)alarm(TIMEOUT);
615
616 nread = recvmsg(fd, msg, MSG_WAITALL);
617
618 (void)alarm(0);
619
620 if (nread < 0) {
621 logmsg("recvmsg_timeout: recvmsg");
825 if ((size_t)ssize != size) {
826 logmsgx("message_recv: recvmsg: received %zd of %zu bytes",
827 ssize, size);
622 return (-1);
623 }
624
828 return (-1);
829 }
830
625 if ((size_t)nread != n) {
626 logmsgx("recvmsg_timeout: recvmsg: short read: %ld of %lu bytes",
627 (long)nread, (u_long)n);
831 dbgmsg("recv: data size %zd", ssize);
832 dbgmsg("recv: msghdr.msg_controllen %u",
833 (u_int)msghdr->msg_controllen);
834 cmsghdr = CMSG_FIRSTHDR(msghdr);
835 if (cmsghdr != NULL)
836 dbgmsg("recv: cmsghdr.cmsg_len %u",
837 (u_int)cmsghdr->cmsg_len);
838
839 if (memcmp(ipc_msg.buf_recv, ipc_msg.buf_send, size) != 0) {
840 logmsgx("message_recv: received message has wrong content");
628 return (-1);
629 }
630
631 return (0);
632}
633
841 return (-1);
842 }
843
844 return (0);
845}
846
634/*
635 * Wait for synchronization message (1 byte) with timeout.
636 */
637static int
847static int
638sync_recv(int fd)
848socket_accept(int listenfd)
639{
849{
640 ssize_t nread;
641 char buf;
850 fd_set rset;
851 struct timeval tv;
852 int fd, rv, val;
642
853
643 dbgmsg(("waiting for sync message"));
854 dbgmsg("accept");
644
855
645 if (sigsetjmp(env_alrm, 1) != 0) {
646 logmsgx("sync_recv: cannot receive sync message (timeout)");
856 FD_ZERO(&rset);
857 FD_SET(listenfd, &rset);
858 tv.tv_sec = TIMEOUT;
859 tv.tv_usec = 0;
860 rv = select(listenfd + 1, &rset, (fd_set *)NULL, (fd_set *)NULL, &tv);
861 if (rv < 0) {
862 logmsg("socket_accept: select");
647 return (-1);
648 }
863 return (-1);
864 }
649
650 (void)alarm(TIMEOUT);
651
652 nread = read(fd, &buf, 1);
653
654 (void)alarm(0);
655
656 if (nread < 0) {
657 logmsg("sync_recv: read");
865 if (rv == 0) {
866 logmsgx("socket_accept: select timeout");
658 return (-1);
659 }
660
867 return (-1);
868 }
869
661 if (nread != 1) {
662 logmsgx("sync_recv: read: short read: %ld of 1 byte",
663 (long)nread);
870 fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL);
871 if (fd < 0) {
872 logmsg("socket_accept: accept");
664 return (-1);
665 }
666
873 return (-1);
874 }
875
667 return (0);
876 val = fcntl(fd, F_GETFL, 0);
877 if (val < 0) {
878 logmsg("socket_accept: fcntl(F_GETFL)");
879 goto failed;
880 }
881 if (fcntl(fd, F_SETFL, val & ~O_NONBLOCK) < 0) {
882 logmsg("socket_accept: fcntl(F_SETFL)");
883 goto failed;
884 }
885
886 return (fd);
887
888failed:
889 if (close(fd) < 0)
890 logmsg("socket_accept: close");
891 return (-1);
668}
669
892}
893
670/*
671 * Send synchronization message (1 byte) with timeout.
672 */
673static int
894static int
674sync_send(int fd)
895check_msghdr(const struct msghdr *msghdr, size_t size)
675{
896{
676 ssize_t nsent;
677
678 dbgmsg(("sending sync message"));
679
680 if (sigsetjmp(env_alrm, 1) != 0) {
681 logmsgx("sync_send: cannot send sync message (timeout)");
897 if (msghdr->msg_flags & MSG_TRUNC) {
898 logmsgx("msghdr.msg_flags has MSG_TRUNC");
682 return (-1);
683 }
899 return (-1);
900 }
684
685 (void)alarm(TIMEOUT);
686
687 nsent = write(fd, "", 1);
688
689 (void)alarm(0);
690
691 if (nsent < 0) {
692 logmsg("sync_send: write");
901 if (msghdr->msg_flags & MSG_CTRUNC) {
902 logmsgx("msghdr.msg_flags has MSG_CTRUNC");
693 return (-1);
694 }
903 return (-1);
904 }
695
696 if (nsent != 1) {
697 logmsgx("sync_send: write: short write: %ld of 1 byte",
698 (long)nsent);
905 if (msghdr->msg_controllen < size) {
906 logmsgx("msghdr.msg_controllen %u < %zu",
907 (u_int)msghdr->msg_controllen, size);
699 return (-1);
700 }
908 return (-1);
909 }
701
910 if (msghdr->msg_controllen > 0 && size == 0) {
911 logmsgx("msghdr.msg_controllen %u > 0",
912 (u_int)msghdr->msg_controllen);
913 return (-1);
914 }
702 return (0);
703}
704
915 return (0);
916}
917
705/*
706 * waitpid() for client with timeout.
707 */
708static int
918static int
709wait_client(void)
919check_cmsghdr(const struct cmsghdr *cmsghdr, int type, size_t size)
710{
920{
711 int status;
712 pid_t pid;
713
714 if (sigsetjmp(env_alrm, 1) != 0) {
715 logmsgx("wait_client: cannot get exit status of client PID %ld (timeout)",
716 (long)client_pid);
921 if (cmsghdr == NULL) {
922 logmsgx("cmsghdr is NULL");
717 return (-1);
718 }
923 return (-1);
924 }
719
720 (void)alarm(TIMEOUT);
721
722 pid = waitpid(client_pid, &status, 0);
723
724 (void)alarm(0);
725
726 if (pid == (pid_t)-1) {
727 logmsg("wait_client: waitpid");
925 if (cmsghdr->cmsg_level != SOL_SOCKET) {
926 logmsgx("cmsghdr.cmsg_level %d != SOL_SOCKET",
927 cmsghdr->cmsg_level);
728 return (-1);
729 }
928 return (-1);
929 }
730
731 if (WIFEXITED(status)) {
732 if (WEXITSTATUS(status) != 0) {
733 logmsgx("wait_client: exit status of client PID %ld is %d",
734 (long)client_pid, WEXITSTATUS(status));
735 return (-1);
736 }
737 } else {
738 if (WIFSIGNALED(status))
739 logmsgx("wait_client: abnormal termination of client PID %ld, signal %d%s",
740 (long)client_pid, WTERMSIG(status), WCOREDUMP(status) ? " (core file generated)" : "");
741 else
742 logmsgx("wait_client: termination of client PID %ld, unknown status",
743 (long)client_pid);
930 if (cmsghdr->cmsg_type != type) {
931 logmsgx("cmsghdr.cmsg_type %d != %d",
932 cmsghdr->cmsg_type, type);
744 return (-1);
745 }
933 return (-1);
934 }
746
935 if (cmsghdr->cmsg_len != CMSG_LEN(size)) {
936 logmsgx("cmsghdr.cmsg_len %u != %zu",
937 (u_int)cmsghdr->cmsg_len, CMSG_LEN(size));
938 return (-1);
939 }
747 return (0);
748}
749
940 return (0);
941}
942
750/*
751 * Check if n supplementary GIDs in gids are correct. (my_gids + 1)
752 * has (my_ngids - 1) supplementary GIDs of current process.
753 */
754static int
943static int
755check_groups(const gid_t *gids, int n)
944check_groups(const char *gid_arr_str, const gid_t *gid_arr,
945 const char *gid_num_str, int gid_num, bool all_gids)
756{
946{
757 char match[NGROUPS_MAX] = { 0 };
758 int error, i, j;
947 int i;
759
948
760 if (n != my_ngids - 1) {
761 logmsgx("wrong number of groups %d != %d (returned from getgroups() - 1)",
762 n, my_ngids - 1);
763 error = -1;
764 } else
765 error = 0;
766 for (i = 0; i < n; ++i) {
767 for (j = 1; j < my_ngids; ++j) {
768 if (gids[i] == my_gids[j]) {
769 if (match[j]) {
770 logmsgx("duplicated GID %lu",
771 (u_long)gids[i]);
772 error = -1;
773 } else
774 match[j] = 1;
775 break;
776 }
949 for (i = 0; i < gid_num; ++i)
950 dbgmsg("%s[%d] %lu", gid_arr_str, i, (u_long)gid_arr[i]);
951
952 if (all_gids) {
953 if (gid_num != proc_cred.gid_num) {
954 logmsgx("%s %d != %d", gid_num_str, gid_num,
955 proc_cred.gid_num);
956 return (-1);
777 }
957 }
778 if (j == my_ngids) {
779 logmsgx("unexpected GID %lu", (u_long)gids[i]);
780 error = -1;
958 } else {
959 if (gid_num > proc_cred.gid_num) {
960 logmsgx("%s %d > %d", gid_num_str, gid_num,
961 proc_cred.gid_num);
962 return (-1);
781 }
782 }
963 }
964 }
783 for (j = 1; j < my_ngids; ++j)
784 if (match[j] == 0) {
785 logmsgx("did not receive supplementary GID %u", my_gids[j]);
786 error = -1;
787 }
788 return (error);
965 if (memcmp(gid_arr, proc_cred.gid_arr,
966 gid_num * sizeof(*gid_arr)) != 0) {
967 logmsgx("%s content is wrong", gid_arr_str);
968 for (i = 0; i < gid_num; ++i)
969 if (gid_arr[i] != proc_cred.gid_arr[i]) {
970 logmsgx("%s[%d] %lu != %lu",
971 gid_arr_str, i, (u_long)gid_arr[i],
972 (u_long)proc_cred.gid_arr[i]);
973 break;
974 }
975 return (-1);
976 }
977 return (0);
789}
790
978}
979
791/*
792 * Send n messages with data and control message with SCM_CREDS type
793 * to server and exit.
794 */
795static void
796t_cmsgcred_client(u_int n)
980static int
981check_xucred(const struct xucred *xucred, socklen_t len)
797{
982{
798 union {
799 struct cmsghdr cm;
800 char control[CMSG_SPACE(sizeof(struct cmsgcred))];
801 } control_un;
802 struct msghdr msg;
803 struct iovec iov[1];
804 struct cmsghdr *cmptr;
805 int fd;
806 u_int i;
983 if (len != sizeof(*xucred)) {
984 logmsgx("option value size %zu != %zu",
985 (size_t)len, sizeof(*xucred));
986 return (-1);
987 }
807
988
808 assert(n == 1 || n == 2);
989 dbgmsg("xucred.cr_version %u", xucred->cr_version);
990 dbgmsg("xucred.cr_uid %lu", (u_long)xucred->cr_uid);
991 dbgmsg("xucred.cr_ngroups %d", xucred->cr_ngroups);
809
992
810 if ((fd = create_unbound_socket()) < 0)
811 goto failed;
993 if (xucred->cr_version != XUCRED_VERSION) {
994 logmsgx("xucred.cr_version %u != %d",
995 xucred->cr_version, XUCRED_VERSION);
996 return (-1);
997 }
998 if (xucred->cr_uid != proc_cred.euid) {
999 logmsgx("xucred.cr_uid %lu != %lu (EUID)",
1000 (u_long)xucred->cr_uid, (u_long)proc_cred.euid);
1001 return (-1);
1002 }
1003 if (xucred->cr_ngroups == 0) {
1004 logmsgx("xucred.cr_ngroups == 0");
1005 return (-1);
1006 }
1007 if (xucred->cr_ngroups < 0) {
1008 logmsgx("xucred.cr_ngroups < 0");
1009 return (-1);
1010 }
1011 if (xucred->cr_ngroups > XU_NGROUPS) {
1012 logmsgx("xucred.cr_ngroups %hu > %u (max)",
1013 xucred->cr_ngroups, XU_NGROUPS);
1014 return (-1);
1015 }
1016 if (xucred->cr_groups[0] != proc_cred.egid) {
1017 logmsgx("xucred.cr_groups[0] %lu != %lu (EGID)",
1018 (u_long)xucred->cr_groups[0], (u_long)proc_cred.egid);
1019 return (-1);
1020 }
1021 if (check_groups("xucred.cr_groups", xucred->cr_groups,
1022 "xucred.cr_ngroups", xucred->cr_ngroups, false) < 0)
1023 return (-1);
1024 return (0);
1025}
812
1026
813 if (connect_server(fd) < 0)
814 goto failed_close;
1027static int
1028check_scm_creds_cmsgcred(struct cmsghdr *cmsghdr)
1029{
1030 const struct cmsgcred *cmsgcred;
815
1031
816 iov[0].iov_base = ipc_message;
817 iov[0].iov_len = IPC_MESSAGE_SIZE;
1032 if (check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(*cmsgcred)) < 0)
1033 return (-1);
818
1034
819 msg.msg_name = NULL;
820 msg.msg_namelen = 0;
821 msg.msg_iov = iov;
822 msg.msg_iovlen = 1;
823 msg.msg_control = control_un.control;
824 msg.msg_controllen = no_control_data ?
825 sizeof(struct cmsghdr) : sizeof(control_un.control);
826 msg.msg_flags = 0;
1035 cmsgcred = (struct cmsgcred *)CMSG_DATA(cmsghdr);
827
1036
828 cmptr = CMSG_FIRSTHDR(&msg);
829 cmptr->cmsg_len = CMSG_LEN(no_control_data ?
830 0 : sizeof(struct cmsgcred));
831 cmptr->cmsg_level = SOL_SOCKET;
832 cmptr->cmsg_type = SCM_CREDS;
1037 dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmsgcred->cmcred_pid);
1038 dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmsgcred->cmcred_uid);
1039 dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmsgcred->cmcred_euid);
1040 dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmsgcred->cmcred_gid);
1041 dbgmsg("cmsgcred.cmcred_ngroups %d", cmsgcred->cmcred_ngroups);
833
1042
834 for (i = 0; i < n; ++i) {
835 dbgmsg(("#%u msg_controllen = %u, cmsg_len = %u", i,
836 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len));
837 if (sendmsg_timeout(fd, &msg, IPC_MESSAGE_SIZE) < 0)
838 goto failed_close;
1043 if (cmsgcred->cmcred_pid != client_pid) {
1044 logmsgx("cmsgcred.cmcred_pid %ld != %ld",
1045 (long)cmsgcred->cmcred_pid, (long)client_pid);
1046 return (-1);
839 }
1047 }
1048 if (cmsgcred->cmcred_uid != proc_cred.uid) {
1049 logmsgx("cmsgcred.cmcred_uid %lu != %lu",
1050 (u_long)cmsgcred->cmcred_uid, (u_long)proc_cred.uid);
1051 return (-1);
1052 }
1053 if (cmsgcred->cmcred_euid != proc_cred.euid) {
1054 logmsgx("cmsgcred.cmcred_euid %lu != %lu",
1055 (u_long)cmsgcred->cmcred_euid, (u_long)proc_cred.euid);
1056 return (-1);
1057 }
1058 if (cmsgcred->cmcred_gid != proc_cred.gid) {
1059 logmsgx("cmsgcred.cmcred_gid %lu != %lu",
1060 (u_long)cmsgcred->cmcred_gid, (u_long)proc_cred.gid);
1061 return (-1);
1062 }
1063 if (cmsgcred->cmcred_ngroups == 0) {
1064 logmsgx("cmsgcred.cmcred_ngroups == 0");
1065 return (-1);
1066 }
1067 if (cmsgcred->cmcred_ngroups < 0) {
1068 logmsgx("cmsgcred.cmcred_ngroups %d < 0",
1069 cmsgcred->cmcred_ngroups);
1070 return (-1);
1071 }
1072 if (cmsgcred->cmcred_ngroups > CMGROUP_MAX) {
1073 logmsgx("cmsgcred.cmcred_ngroups %d > %d",
1074 cmsgcred->cmcred_ngroups, CMGROUP_MAX);
1075 return (-1);
1076 }
1077 if (cmsgcred->cmcred_groups[0] != proc_cred.egid) {
1078 logmsgx("cmsgcred.cmcred_groups[0] %lu != %lu (EGID)",
1079 (u_long)cmsgcred->cmcred_groups[0], (u_long)proc_cred.egid);
1080 return (-1);
1081 }
1082 if (check_groups("cmsgcred.cmcred_groups", cmsgcred->cmcred_groups,
1083 "cmsgcred.cmcred_ngroups", cmsgcred->cmcred_ngroups, false) < 0)
1084 return (-1);
1085 return (0);
1086}
840
1087
841 if (close_socket((const char *)NULL, fd) < 0)
842 goto failed;
1088static int
1089check_scm_creds_sockcred(struct cmsghdr *cmsghdr)
1090{
1091 const struct sockcred *sockcred;
843
1092
844 _exit(0);
1093 if (check_cmsghdr(cmsghdr, SCM_CREDS,
1094 SOCKCREDSIZE(proc_cred.gid_num)) < 0)
1095 return (-1);
845
1096
846failed_close:
847 (void)close_socket((const char *)NULL, fd);
1097 sockcred = (struct sockcred *)CMSG_DATA(cmsghdr);
848
1098
849failed:
850 _exit(1);
1099 dbgmsg("sockcred.sc_uid %lu", (u_long)sockcred->sc_uid);
1100 dbgmsg("sockcred.sc_euid %lu", (u_long)sockcred->sc_euid);
1101 dbgmsg("sockcred.sc_gid %lu", (u_long)sockcred->sc_gid);
1102 dbgmsg("sockcred.sc_egid %lu", (u_long)sockcred->sc_egid);
1103 dbgmsg("sockcred.sc_ngroups %d", sockcred->sc_ngroups);
1104
1105 if (sockcred->sc_uid != proc_cred.uid) {
1106 logmsgx("sockcred.sc_uid %lu != %lu",
1107 (u_long)sockcred->sc_uid, (u_long)proc_cred.uid);
1108 return (-1);
1109 }
1110 if (sockcred->sc_euid != proc_cred.euid) {
1111 logmsgx("sockcred.sc_euid %lu != %lu",
1112 (u_long)sockcred->sc_euid, (u_long)proc_cred.euid);
1113 return (-1);
1114 }
1115 if (sockcred->sc_gid != proc_cred.gid) {
1116 logmsgx("sockcred.sc_gid %lu != %lu",
1117 (u_long)sockcred->sc_gid, (u_long)proc_cred.gid);
1118 return (-1);
1119 }
1120 if (sockcred->sc_egid != proc_cred.egid) {
1121 logmsgx("sockcred.sc_egid %lu != %lu",
1122 (u_long)sockcred->sc_egid, (u_long)proc_cred.egid);
1123 return (-1);
1124 }
1125 if (sockcred->sc_ngroups == 0) {
1126 logmsgx("sockcred.sc_ngroups == 0");
1127 return (-1);
1128 }
1129 if (sockcred->sc_ngroups < 0) {
1130 logmsgx("sockcred.sc_ngroups %d < 0",
1131 sockcred->sc_ngroups);
1132 return (-1);
1133 }
1134 if (sockcred->sc_ngroups != proc_cred.gid_num) {
1135 logmsgx("sockcred.sc_ngroups %d != %u",
1136 sockcred->sc_ngroups, proc_cred.gid_num);
1137 return (-1);
1138 }
1139 if (check_groups("sockcred.sc_groups", sockcred->sc_groups,
1140 "sockcred.sc_ngroups", sockcred->sc_ngroups, true) < 0)
1141 return (-1);
1142 return (0);
851}
852
1143}
1144
853/*
854 * Receive two messages with data and control message with SCM_CREDS
855 * type followed by struct cmsgcred{} from client. fd1 is a listen
856 * socket for stream sockets or simply socket for datagram sockets.
857 */
858static int
1145static int
859t_cmsgcred_server(int fd1)
1146check_scm_timestamp(struct cmsghdr *cmsghdr)
860{
1147{
861 char buf[IPC_MESSAGE_SIZE];
862 union {
863 struct cmsghdr cm;
864 char control[CMSG_SPACE(sizeof(struct cmsgcred)) + EXTRA_CMSG_SPACE];
865 } control_un;
866 struct msghdr msg;
867 struct iovec iov[1];
868 struct cmsghdr *cmptr;
869 const struct cmsgcred *cmcredptr;
870 socklen_t controllen;
871 int error, error2, fd2;
872 u_int i;
1148 const struct timeval *timeval;
873
1149
874 if (sock_type == SOCK_STREAM) {
875 if ((fd2 = accept_timeout(fd1)) < 0)
876 return (-2);
877 } else
878 fd2 = fd1;
1150 if (check_cmsghdr(cmsghdr, SCM_TIMESTAMP, sizeof(struct timeval)) < 0)
1151 return (-1);
879
1152
880 error = 0;
1153 timeval = (struct timeval *)CMSG_DATA(cmsghdr);
881
1154
882 controllen = sizeof(control_un.control);
1155 dbgmsg("timeval.tv_sec %"PRIdMAX", timeval.tv_usec %"PRIdMAX,
1156 (intmax_t)timeval->tv_sec, (intmax_t)timeval->tv_usec);
883
1157
884 for (i = 0; i < 2; ++i) {
885 iov[0].iov_base = buf;
886 iov[0].iov_len = sizeof(buf);
1158 return (0);
1159}
887
1160
888 msg.msg_name = NULL;
889 msg.msg_namelen = 0;
890 msg.msg_iov = iov;
891 msg.msg_iovlen = 1;
892 msg.msg_control = control_un.control;
893 msg.msg_controllen = controllen;
894 msg.msg_flags = 0;
1161static int
1162check_scm_bintime(struct cmsghdr *cmsghdr)
1163{
1164 const struct bintime *bintime;
895
1165
896 controllen = CMSG_SPACE(sizeof(struct cmsgcred));
1166 if (check_cmsghdr(cmsghdr, SCM_BINTIME, sizeof(struct bintime)) < 0)
1167 return (-1);
897
1168
898 if (recvmsg_timeout(fd2, &msg, sizeof(buf)) < 0)
899 goto failed;
1169 bintime = (struct bintime *)CMSG_DATA(cmsghdr);
900
1170
901 if (msg.msg_flags & MSG_CTRUNC) {
902 logmsgx("#%u control data was truncated, MSG_CTRUNC flag is on",
903 i);
904 goto next_error;
905 }
1171 dbgmsg("bintime.sec %"PRIdMAX", bintime.frac %"PRIu64,
1172 (intmax_t)bintime->sec, bintime->frac);
906
1173
907 if (msg.msg_controllen < sizeof(struct cmsghdr)) {
908 logmsgx("#%u msg_controllen %u < %lu (sizeof(struct cmsghdr))",
909 i, (u_int)msg.msg_controllen, (u_long)sizeof(struct cmsghdr));
910 goto next_error;
911 }
1174 return (0);
1175}
912
1176
913 if ((cmptr = CMSG_FIRSTHDR(&msg)) == NULL) {
914 logmsgx("CMSG_FIRSTHDR is NULL");
915 goto next_error;
916 }
1177static void
1178msghdr_init_generic(struct msghdr *msghdr, struct iovec *iov, void *cmsg_data)
1179{
1180 msghdr->msg_name = NULL;
1181 msghdr->msg_namelen = 0;
1182 if (send_data_flag) {
1183 iov->iov_base = server_flag ?
1184 ipc_msg.buf_recv : ipc_msg.buf_send;
1185 iov->iov_len = ipc_msg.buf_size;
1186 msghdr->msg_iov = iov;
1187 msghdr->msg_iovlen = 1;
1188 } else {
1189 msghdr->msg_iov = NULL;
1190 msghdr->msg_iovlen = 0;
1191 }
1192 msghdr->msg_control = cmsg_data;
1193 msghdr->msg_flags = 0;
1194}
917
1195
918 dbgmsg(("#%u msg_controllen = %u, cmsg_len = %u", i,
919 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len));
1196static void
1197msghdr_init_server(struct msghdr *msghdr, struct iovec *iov,
1198 void *cmsg_data, size_t cmsg_size)
1199{
1200 msghdr_init_generic(msghdr, iov, cmsg_data);
1201 msghdr->msg_controllen = cmsg_size;
1202 dbgmsg("init: data size %zu", msghdr->msg_iov != NULL ?
1203 msghdr->msg_iov->iov_len : (size_t)0);
1204 dbgmsg("init: msghdr.msg_controllen %u",
1205 (u_int)msghdr->msg_controllen);
1206}
920
1207
921 if (cmptr->cmsg_level != SOL_SOCKET) {
922 logmsgx("#%u cmsg_level %d != SOL_SOCKET", i,
923 cmptr->cmsg_level);
924 goto next_error;
925 }
1208static void
1209msghdr_init_client(struct msghdr *msghdr, struct iovec *iov,
1210 void *cmsg_data, size_t cmsg_size, int type, size_t arr_size)
1211{
1212 struct cmsghdr *cmsghdr;
926
1213
927 if (cmptr->cmsg_type != SCM_CREDS) {
928 logmsgx("#%u cmsg_type %d != SCM_CREDS", i,
929 cmptr->cmsg_type);
930 goto next_error;
931 }
1214 msghdr_init_generic(msghdr, iov, cmsg_data);
1215 if (cmsg_data != NULL) {
1216 msghdr->msg_controllen = send_array_flag ?
1217 cmsg_size : CMSG_SPACE(0);
1218 cmsghdr = CMSG_FIRSTHDR(msghdr);
1219 cmsghdr->cmsg_level = SOL_SOCKET;
1220 cmsghdr->cmsg_type = type;
1221 cmsghdr->cmsg_len = CMSG_LEN(send_array_flag ? arr_size : 0);
1222 } else
1223 msghdr->msg_controllen = 0;
1224}
932
1225
933 if (cmptr->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred))) {
934 logmsgx("#%u cmsg_len %u != %lu (CMSG_LEN(sizeof(struct cmsgcred))",
935 i, (u_int)cmptr->cmsg_len, (u_long)CMSG_LEN(sizeof(struct cmsgcred)));
936 goto next_error;
937 }
1226static int
1227t_generic(int (*client_func)(int), int (*server_func)(int))
1228{
1229 int fd, rv, rv_client;
938
1230
939 cmcredptr = (const struct cmsgcred *)CMSG_DATA(cmptr);
940
941 error2 = 0;
942 if (cmcredptr->cmcred_pid != client_pid) {
943 logmsgx("#%u cmcred_pid %ld != %ld (PID of client)",
944 i, (long)cmcredptr->cmcred_pid, (long)client_pid);
945 error2 = 1;
1231 switch (client_fork()) {
1232 case 0:
1233 fd = socket_create();
1234 if (fd < 0)
1235 rv = -2;
1236 else {
1237 rv = client_func(fd);
1238 if (socket_close(fd) < 0)
1239 rv = -2;
946 }
1240 }
947 if (cmcredptr->cmcred_uid != my_uid) {
948 logmsgx("#%u cmcred_uid %lu != %lu (UID of current process)",
949 i, (u_long)cmcredptr->cmcred_uid, (u_long)my_uid);
950 error2 = 1;
1241 client_exit(rv);
1242 break;
1243 case 1:
1244 fd = socket_create();
1245 if (fd < 0)
1246 rv = -2;
1247 else {
1248 rv = server_func(fd);
1249 rv_client = client_wait();
1250 if (rv == 0 || (rv == -2 && rv_client != 0))
1251 rv = rv_client;
1252 if (socket_close(fd) < 0)
1253 rv = -2;
951 }
1254 }
952 if (cmcredptr->cmcred_euid != my_euid) {
953 logmsgx("#%u cmcred_euid %lu != %lu (EUID of current process)",
954 i, (u_long)cmcredptr->cmcred_euid, (u_long)my_euid);
955 error2 = 1;
956 }
957 if (cmcredptr->cmcred_gid != my_gid) {
958 logmsgx("#%u cmcred_gid %lu != %lu (GID of current process)",
959 i, (u_long)cmcredptr->cmcred_gid, (u_long)my_gid);
960 error2 = 1;
961 }
962 if (cmcredptr->cmcred_ngroups == 0) {
963 logmsgx("#%u cmcred_ngroups = 0, this is wrong", i);
964 error2 = 1;
965 } else {
966 if (cmcredptr->cmcred_ngroups > NGROUPS_MAX) {
967 logmsgx("#%u cmcred_ngroups %d > %u (NGROUPS_MAX)",
968 i, cmcredptr->cmcred_ngroups, NGROUPS_MAX);
969 error2 = 1;
970 } else if (cmcredptr->cmcred_ngroups < 0) {
971 logmsgx("#%u cmcred_ngroups %d < 0",
972 i, cmcredptr->cmcred_ngroups);
973 error2 = 1;
974 } else {
975 dbgmsg(("#%u cmcred_ngroups = %d", i,
976 cmcredptr->cmcred_ngroups));
977 if (cmcredptr->cmcred_groups[0] != my_egid) {
978 logmsgx("#%u cmcred_groups[0] %lu != %lu (EGID of current process)",
979 i, (u_long)cmcredptr->cmcred_groups[0], (u_long)my_egid);
980 error2 = 1;
981 }
982 if (check_groups(cmcredptr->cmcred_groups + 1, cmcredptr->cmcred_ngroups - 1) < 0) {
983 logmsgx("#%u cmcred_groups has wrong GIDs", i);
984 error2 = 1;
985 }
986 }
987 }
1255 break;
1256 default:
1257 rv = -2;
1258 }
1259 return (rv);
1260}
988
1261
989 if (error2)
990 goto next_error;
1262static int
1263t_cmsgcred_client(int fd)
1264{
1265 struct msghdr msghdr;
1266 struct iovec iov[1];
1267 void *cmsg_data;
1268 size_t cmsg_size;
1269 int rv;
991
1270
992 if ((cmptr = CMSG_NXTHDR(&msg, cmptr)) != NULL) {
993 logmsgx("#%u control data has extra header", i);
994 goto next_error;
995 }
1271 if (sync_recv() < 0)
1272 return (-2);
996
1273
997 continue;
998next_error:
999 error = -1;
1274 rv = -2;
1275
1276 cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
1277 cmsg_data = malloc(cmsg_size);
1278 if (cmsg_data == NULL) {
1279 logmsg("malloc");
1280 goto done;
1000 }
1281 }
1282 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
1283 SCM_CREDS, sizeof(struct cmsgcred));
1001
1284
1002 if (sock_type == SOCK_STREAM)
1003 if (close(fd2) < 0) {
1004 logmsg("close");
1005 return (-2);
1006 }
1007 return (error);
1285 if (socket_connect(fd) < 0)
1286 goto done;
1008
1287
1009failed:
1010 if (sock_type == SOCK_STREAM)
1011 if (close(fd2) < 0)
1012 logmsg("close");
1013 return (-2);
1288 if (message_sendn(fd, &msghdr) < 0)
1289 goto done;
1290
1291 rv = 0;
1292done:
1293 free(cmsg_data);
1294 return (rv);
1014}
1015
1016static int
1295}
1296
1297static int
1017t_cmsgcred(void)
1298t_cmsgcred_server(int fd1)
1018{
1299{
1019 int error, fd;
1300 struct msghdr msghdr;
1301 struct iovec iov[1];
1302 struct cmsghdr *cmsghdr;
1303 void *cmsg_data;
1304 size_t cmsg_size;
1305 u_int i;
1306 int fd2, rv;
1020
1307
1021 if ((fd = create_server_socket()) < 0)
1308 if (sync_send() < 0)
1022 return (-2);
1023
1309 return (-2);
1310
1024 if (sock_type == SOCK_STREAM)
1025 if (listen(fd, LISTENQ) < 0) {
1026 logmsg("listen");
1027 goto failed;
1028 }
1311 fd2 = -1;
1312 rv = -2;
1029
1313
1030 if ((client_pid = fork()) == (pid_t)-1) {
1031 logmsg("fork");
1032 goto failed;
1314 cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
1315 cmsg_data = malloc(cmsg_size);
1316 if (cmsg_data == NULL) {
1317 logmsg("malloc");
1318 goto done;
1033 }
1034
1319 }
1320
1035 if (client_pid == 0) {
1036 myname = "CLIENT";
1037 if (close_socket((const char *)NULL, fd) < 0)
1038 _exit(1);
1039 t_cmsgcred_client(2);
1040 }
1321 if (sock_type == SOCK_STREAM) {
1322 fd2 = socket_accept(fd1);
1323 if (fd2 < 0)
1324 goto done;
1325 } else
1326 fd2 = fd1;
1041
1327
1042 if ((error = t_cmsgcred_server(fd)) == -2) {
1043 (void)wait_client();
1044 goto failed;
1045 }
1328 rv = -1;
1329 for (i = 1; i <= ipc_msg.msg_num; ++i) {
1330 dbgmsg("message #%u", i);
1046
1331
1047 if (wait_client() < 0)
1048 goto failed;
1332 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1333 if (message_recv(fd2, &msghdr) < 0) {
1334 rv = -2;
1335 break;
1336 }
1049
1337
1050 if (close_socket(serv_sock_path, fd) < 0) {
1051 logmsgx("close_socket failed");
1052 return (-2);
1338 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1339 break;
1340
1341 cmsghdr = CMSG_FIRSTHDR(&msghdr);
1342 if (check_scm_creds_cmsgcred(cmsghdr) < 0)
1343 break;
1053 }
1344 }
1054 return (error);
1345 if (i > ipc_msg.msg_num)
1346 rv = 0;
1347done:
1348 free(cmsg_data);
1349 if (sock_type == SOCK_STREAM && fd2 >= 0)
1350 if (socket_close(fd2) < 0)
1351 rv = -2;
1352 return (rv);
1353}
1055
1354
1056failed:
1057 if (close_socket(serv_sock_path, fd) < 0)
1058 logmsgx("close_socket failed");
1059 return (-2);
1355static int
1356t_cmsgcred(void)
1357{
1358 return (t_generic(t_cmsgcred_client, t_cmsgcred_server));
1060}
1061
1359}
1360
1062/*
1063 * Send two messages with data to server and exit.
1064 */
1065static void
1066t_sockcred_client(int type)
1361static int
1362t_sockcred_client(int type, int fd)
1067{
1363{
1068 struct msghdr msg;
1364 struct msghdr msghdr;
1069 struct iovec iov[1];
1365 struct iovec iov[1];
1070 int fd;
1071 u_int i;
1366 int rv;
1072
1367
1073 assert(type == 0 || type == 1);
1368 if (sync_recv() < 0)
1369 return (-2);
1074
1370
1075 if ((fd = create_unbound_socket()) < 0)
1076 goto failed;
1371 rv = -2;
1077
1372
1078 if (connect_server(fd) < 0)
1079 goto failed_close;
1373 msghdr_init_client(&msghdr, iov, NULL, 0, 0, 0);
1080
1374
1081 if (type == 1)
1082 if (sync_recv(fd) < 0)
1083 goto failed_close;
1375 if (socket_connect(fd) < 0)
1376 goto done;
1084
1377
1085 iov[0].iov_base = ipc_message;
1086 iov[0].iov_len = IPC_MESSAGE_SIZE;
1378 if (type == 2)
1379 if (sync_recv() < 0)
1380 goto done;
1087
1381
1088 msg.msg_name = NULL;
1089 msg.msg_namelen = 0;
1090 msg.msg_iov = iov;
1091 msg.msg_iovlen = 1;
1092 msg.msg_control = NULL;
1093 msg.msg_controllen = 0;
1094 msg.msg_flags = 0;
1382 if (message_sendn(fd, &msghdr) < 0)
1383 goto done;
1095
1384
1096 for (i = 0; i < 2; ++i)
1097 if (sendmsg_timeout(fd, &msg, IPC_MESSAGE_SIZE) < 0)
1098 goto failed_close;
1099
1100 if (close_socket((const char *)NULL, fd) < 0)
1101 goto failed;
1102
1103 _exit(0);
1104
1105failed_close:
1106 (void)close_socket((const char *)NULL, fd);
1107
1108failed:
1109 _exit(1);
1385 rv = 0;
1386done:
1387 return (rv);
1110}
1111
1388}
1389
1112/*
1113 * Receive one message with data and control message with SCM_CREDS
1114 * type followed by struct sockcred{} and if n is not equal 1, then
1115 * receive another one message with data. fd1 is a listen socket for
1116 * stream sockets or simply socket for datagram sockets. If type is
1117 * 1, then set LOCAL_CREDS option for accepted stream socket.
1118 */
1119static int
1390static int
1120t_sockcred_server(int type, int fd1, u_int n)
1391t_sockcred_server(int type, int fd1)
1121{
1392{
1122 char buf[IPC_MESSAGE_SIZE];
1123 union {
1124 struct cmsghdr cm;
1125 char control[CMSG_SPACE(SOCKCREDSIZE(NGROUPS_MAX)) + EXTRA_CMSG_SPACE];
1126 } control_un;
1127 struct msghdr msg;
1393 struct msghdr msghdr;
1128 struct iovec iov[1];
1394 struct iovec iov[1];
1129 struct cmsghdr *cmptr;
1130 const struct sockcred *sockcred;
1131 int error, error2, fd2, optval;
1395 struct cmsghdr *cmsghdr;
1396 void *cmsg_data;
1397 size_t cmsg_size;
1132 u_int i;
1398 u_int i;
1399 int fd2, rv, val;
1133
1400
1134 assert(n == 1 || n == 2);
1135 assert(type == 0 || type == 1);
1401 fd2 = -1;
1402 rv = -2;
1136
1403
1137 if (sock_type == SOCK_STREAM) {
1138 if ((fd2 = accept_timeout(fd1)) < 0)
1139 return (-2);
1140 if (type == 1) {
1141 optval = 1;
1142 if (setsockopt(fd2, 0, LOCAL_CREDS, &optval, sizeof optval) < 0) {
1143 logmsg("setsockopt(LOCAL_CREDS) for accepted socket");
1144 if (errno == ENOPROTOOPT) {
1145 error = -1;
1146 goto done_close;
1147 }
1148 goto failed;
1149 }
1150 if (sync_send(fd2) < 0)
1151 goto failed;
1152 }
1153 } else
1154 fd2 = fd1;
1404 cmsg_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num));
1405 cmsg_data = malloc(cmsg_size);
1406 if (cmsg_data == NULL) {
1407 logmsg("malloc");
1408 goto done;
1409 }
1155
1410
1156 error = 0;
1157
1158 for (i = 0; i < n; ++i) {
1159 iov[0].iov_base = buf;
1160 iov[0].iov_len = sizeof buf;
1161
1162 msg.msg_name = NULL;
1163 msg.msg_namelen = 0;
1164 msg.msg_iov = iov;
1165 msg.msg_iovlen = 1;
1166 msg.msg_control = control_un.control;
1167 msg.msg_controllen = sizeof control_un.control;
1168 msg.msg_flags = 0;
1169
1170 if (recvmsg_timeout(fd2, &msg, sizeof buf) < 0)
1171 goto failed;
1172
1173 if (msg.msg_flags & MSG_CTRUNC) {
1174 logmsgx("control data was truncated, MSG_CTRUNC flag is on");
1175 goto next_error;
1411 if (type == 1) {
1412 dbgmsg("setting LOCAL_CREDS");
1413 val = 1;
1414 if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
1415 logmsg("setsockopt(LOCAL_CREDS)");
1416 goto done;
1176 }
1417 }
1418 }
1177
1419
1178 if (i != 0 && sock_type == SOCK_STREAM) {
1179 if (msg.msg_controllen != 0) {
1180 logmsgx("second message has control data, this is wrong for stream sockets");
1181 goto next_error;
1182 }
1183 dbgmsg(("#%u msg_controllen = %u", i,
1184 (u_int)msg.msg_controllen));
1185 continue;
1186 }
1420 if (sync_send() < 0)
1421 goto done;
1187
1422
1188 if (msg.msg_controllen < sizeof(struct cmsghdr)) {
1189 logmsgx("#%u msg_controllen %u < %lu (sizeof(struct cmsghdr))",
1190 i, (u_int)msg.msg_controllen, (u_long)sizeof(struct cmsghdr));
1191 goto next_error;
1192 }
1423 if (sock_type == SOCK_STREAM) {
1424 fd2 = socket_accept(fd1);
1425 if (fd2 < 0)
1426 goto done;
1427 } else
1428 fd2 = fd1;
1193
1429
1194 if ((cmptr = CMSG_FIRSTHDR(&msg)) == NULL) {
1195 logmsgx("CMSG_FIRSTHDR is NULL");
1196 goto next_error;
1430 if (type == 2) {
1431 dbgmsg("setting LOCAL_CREDS");
1432 val = 1;
1433 if (setsockopt(fd2, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
1434 logmsg("setsockopt(LOCAL_CREDS)");
1435 goto done;
1197 }
1436 }
1437 if (sync_send() < 0)
1438 goto done;
1439 }
1198
1440
1199 dbgmsg(("#%u msg_controllen = %u, cmsg_len = %u", i,
1200 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len));
1441 rv = -1;
1442 for (i = 1; i <= ipc_msg.msg_num; ++i) {
1443 dbgmsg("message #%u", i);
1201
1444
1202 if (cmptr->cmsg_level != SOL_SOCKET) {
1203 logmsgx("#%u cmsg_level %d != SOL_SOCKET", i,
1204 cmptr->cmsg_level);
1205 goto next_error;
1445 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1446 if (message_recv(fd2, &msghdr) < 0) {
1447 rv = -2;
1448 break;
1206 }
1207
1449 }
1450
1208 if (cmptr->cmsg_type != SCM_CREDS) {
1209 logmsgx("#%u cmsg_type %d != SCM_CREDS", i,
1210 cmptr->cmsg_type);
1211 goto next_error;
1212 }
1451 if (i > 1 && sock_type == SOCK_STREAM) {
1452 if (check_msghdr(&msghdr, 0) < 0)
1453 break;
1454 } else {
1455 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1456 break;
1213
1457
1214 if (cmptr->cmsg_len < CMSG_LEN(SOCKCREDSIZE(1))) {
1215 logmsgx("#%u cmsg_len %u != %lu (CMSG_LEN(SOCKCREDSIZE(1)))",
1216 i, (u_int)cmptr->cmsg_len, (u_long)CMSG_LEN(SOCKCREDSIZE(1)));
1217 goto next_error;
1458 cmsghdr = CMSG_FIRSTHDR(&msghdr);
1459 if (check_scm_creds_sockcred(cmsghdr) < 0)
1460 break;
1218 }
1461 }
1462 }
1463 if (i > ipc_msg.msg_num)
1464 rv = 0;
1465done:
1466 free(cmsg_data);
1467 if (sock_type == SOCK_STREAM && fd2 >= 0)
1468 if (socket_close(fd2) < 0)
1469 rv = -2;
1470 return (rv);
1471}
1219
1472
1220 sockcred = (const struct sockcred *)CMSG_DATA(cmptr);
1473static int
1474t_sockcred_1(void)
1475{
1476 u_int i;
1477 int fd, rv, rv_client;
1221
1478
1222 error2 = 0;
1223 if (sockcred->sc_uid != my_uid) {
1224 logmsgx("#%u sc_uid %lu != %lu (UID of current process)",
1225 i, (u_long)sockcred->sc_uid, (u_long)my_uid);
1226 error2 = 1;
1227 }
1228 if (sockcred->sc_euid != my_euid) {
1229 logmsgx("#%u sc_euid %lu != %lu (EUID of current process)",
1230 i, (u_long)sockcred->sc_euid, (u_long)my_euid);
1231 error2 = 1;
1232 }
1233 if (sockcred->sc_gid != my_gid) {
1234 logmsgx("#%u sc_gid %lu != %lu (GID of current process)",
1235 i, (u_long)sockcred->sc_gid, (u_long)my_gid);
1236 error2 = 1;
1237 }
1238 if (sockcred->sc_egid != my_egid) {
1239 logmsgx("#%u sc_egid %lu != %lu (EGID of current process)",
1240 i, (u_long)sockcred->sc_gid, (u_long)my_egid);
1241 error2 = 1;
1242 }
1243 if (sockcred->sc_ngroups > NGROUPS_MAX) {
1244 logmsgx("#%u sc_ngroups %d > %u (NGROUPS_MAX)",
1245 i, sockcred->sc_ngroups, NGROUPS_MAX);
1246 error2 = 1;
1247 } else if (sockcred->sc_ngroups < 0) {
1248 logmsgx("#%u sc_ngroups %d < 0",
1249 i, sockcred->sc_ngroups);
1250 error2 = 1;
1251 } else {
1252 dbgmsg(("#%u sc_ngroups = %d", i, sockcred->sc_ngroups));
1253 if (check_groups(sockcred->sc_groups, sockcred->sc_ngroups) < 0) {
1254 logmsgx("#%u sc_groups has wrong GIDs", i);
1255 error2 = 1;
1479 switch (client_fork()) {
1480 case 0:
1481 for (i = 1; i <= 2; ++i) {
1482 dbgmsg("client #%u", i);
1483 fd = socket_create();
1484 if (fd < 0)
1485 rv = -2;
1486 else {
1487 rv = t_sockcred_client(1, fd);
1488 if (socket_close(fd) < 0)
1489 rv = -2;
1256 }
1490 }
1491 if (rv != 0)
1492 break;
1257 }
1493 }
1258
1259 if (error2)
1260 goto next_error;
1261
1262 if ((cmptr = CMSG_NXTHDR(&msg, cmptr)) != NULL) {
1263 logmsgx("#%u control data has extra header, this is wrong",
1264 i);
1265 goto next_error;
1494 client_exit(rv);
1495 break;
1496 case 1:
1497 fd = socket_create();
1498 if (fd < 0)
1499 rv = -2;
1500 else {
1501 rv = t_sockcred_server(1, fd);
1502 if (rv == 0)
1503 rv = t_sockcred_server(3, fd);
1504 rv_client = client_wait();
1505 if (rv == 0 || (rv == -2 && rv_client != 0))
1506 rv = rv_client;
1507 if (socket_close(fd) < 0)
1508 rv = -2;
1266 }
1509 }
1267
1268 continue;
1269next_error:
1270 error = -1;
1510 break;
1511 default:
1512 rv = -2;
1271 }
1272
1513 }
1514
1273done_close:
1274 if (sock_type == SOCK_STREAM)
1275 if (close(fd2) < 0) {
1276 logmsg("close");
1277 return (-2);
1278 }
1279 return (error);
1515 return (rv);
1516}
1280
1517
1281failed:
1282 if (sock_type == SOCK_STREAM)
1283 if (close(fd2) < 0)
1284 logmsg("close");
1285 return (-2);
1518static int
1519t_sockcred_2_client(int fd)
1520{
1521 return (t_sockcred_client(2, fd));
1286}
1287
1288static int
1522}
1523
1524static int
1289t_sockcred(int type)
1525t_sockcred_2_server(int fd)
1290{
1526{
1291 int error, fd, optval;
1527 return (t_sockcred_server(2, fd));
1528}
1292
1529
1293 assert(type == 0 || type == 1);
1530static int
1531t_sockcred_2(void)
1532{
1533 return (t_generic(t_sockcred_2_client, t_sockcred_2_server));
1534}
1294
1535
1295 if ((fd = create_server_socket()) < 0)
1296 return (-2);
1536static int
1537t_cmsgcred_sockcred_server(int fd1)
1538{
1539 struct msghdr msghdr;
1540 struct iovec iov[1];
1541 struct cmsghdr *cmsghdr;
1542 void *cmsg_data, *cmsg1_data, *cmsg2_data;
1543 size_t cmsg_size, cmsg1_size, cmsg2_size;
1544 u_int i;
1545 int fd2, rv, val;
1297
1546
1298 if (sock_type == SOCK_STREAM)
1299 if (listen(fd, LISTENQ) < 0) {
1300 logmsg("listen");
1301 goto failed;
1302 }
1547 fd2 = -1;
1548 rv = -2;
1303
1549
1304 if (type == 0) {
1305 optval = 1;
1306 if (setsockopt(fd, 0, LOCAL_CREDS, &optval, sizeof optval) < 0) {
1307 logmsg("setsockopt(LOCAL_CREDS) for %s socket",
1308 sock_type == SOCK_STREAM ? "stream listening" : "datagram");
1309 if (errno == ENOPROTOOPT) {
1310 error = -1;
1311 goto done_close;
1312 }
1313 goto failed;
1314 }
1550 cmsg1_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num));
1551 cmsg2_size = CMSG_SPACE(sizeof(struct cmsgcred));
1552 cmsg1_data = malloc(cmsg1_size);
1553 cmsg2_data = malloc(cmsg2_size);
1554 if (cmsg1_data == NULL || cmsg2_data == NULL) {
1555 logmsg("malloc");
1556 goto done;
1315 }
1316
1557 }
1558
1317 if ((client_pid = fork()) == (pid_t)-1) {
1318 logmsg("fork");
1319 goto failed;
1559 dbgmsg("setting LOCAL_CREDS");
1560 val = 1;
1561 if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
1562 logmsg("setsockopt(LOCAL_CREDS)");
1563 goto done;
1320 }
1321
1564 }
1565
1322 if (client_pid == 0) {
1323 myname = "CLIENT";
1324 if (close_socket((const char *)NULL, fd) < 0)
1325 _exit(1);
1326 t_sockcred_client(type);
1327 }
1566 if (sync_send() < 0)
1567 goto done;
1328
1568
1329 if ((error = t_sockcred_server(type, fd, 2)) == -2) {
1330 (void)wait_client();
1331 goto failed;
1332 }
1569 if (sock_type == SOCK_STREAM) {
1570 fd2 = socket_accept(fd1);
1571 if (fd2 < 0)
1572 goto done;
1573 } else
1574 fd2 = fd1;
1333
1575
1334 if (wait_client() < 0)
1335 goto failed;
1576 cmsg_data = cmsg1_data;
1577 cmsg_size = cmsg1_size;
1578 rv = -1;
1579 for (i = 1; i <= ipc_msg.msg_num; ++i) {
1580 dbgmsg("message #%u", i);
1336
1581
1337done_close:
1338 if (close_socket(serv_sock_path, fd) < 0) {
1339 logmsgx("close_socket failed");
1340 return (-2);
1341 }
1342 return (error);
1582 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1583 if (message_recv(fd2, &msghdr) < 0) {
1584 rv = -2;
1585 break;
1586 }
1343
1587
1344failed:
1345 if (close_socket(serv_sock_path, fd) < 0)
1346 logmsgx("close_socket failed");
1347 return (-2);
1348}
1588 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1589 break;
1349
1590
1350static int
1351t_sockcred_stream1(void)
1352{
1353 return (t_sockcred(0));
1591 cmsghdr = CMSG_FIRSTHDR(&msghdr);
1592 if (i == 1 || sock_type == SOCK_DGRAM) {
1593 if (check_scm_creds_sockcred(cmsghdr) < 0)
1594 break;
1595 } else {
1596 if (check_scm_creds_cmsgcred(cmsghdr) < 0)
1597 break;
1598 }
1599
1600 cmsg_data = cmsg2_data;
1601 cmsg_size = cmsg2_size;
1602 }
1603 if (i > ipc_msg.msg_num)
1604 rv = 0;
1605done:
1606 free(cmsg1_data);
1607 free(cmsg2_data);
1608 if (sock_type == SOCK_STREAM && fd2 >= 0)
1609 if (socket_close(fd2) < 0)
1610 rv = -2;
1611 return (rv);
1354}
1355
1356static int
1612}
1613
1614static int
1357t_sockcred_stream2(void)
1615t_cmsgcred_sockcred(void)
1358{
1616{
1359 return (t_sockcred(1));
1617 return (t_generic(t_cmsgcred_client, t_cmsgcred_sockcred_server));
1360}
1361
1362static int
1618}
1619
1620static int
1363t_sockcred_dgram(void)
1621t_timeval_client(int fd)
1364{
1622{
1365 return (t_sockcred(0));
1623 struct msghdr msghdr;
1624 struct iovec iov[1];
1625 void *cmsg_data;
1626 size_t cmsg_size;
1627 int rv;
1628
1629 if (sync_recv() < 0)
1630 return (-2);
1631
1632 rv = -2;
1633
1634 cmsg_size = CMSG_SPACE(sizeof(struct timeval));
1635 cmsg_data = malloc(cmsg_size);
1636 if (cmsg_data == NULL) {
1637 logmsg("malloc");
1638 goto done;
1639 }
1640 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
1641 SCM_TIMESTAMP, sizeof(struct timeval));
1642
1643 if (socket_connect(fd) < 0)
1644 goto done;
1645
1646 if (message_sendn(fd, &msghdr) < 0)
1647 goto done;
1648
1649 rv = 0;
1650done:
1651 free(cmsg_data);
1652 return (rv);
1366}
1367
1368static int
1653}
1654
1655static int
1369t_cmsgcred_sockcred(void)
1656t_timeval_server(int fd1)
1370{
1657{
1371 int error, fd, optval;
1658 struct msghdr msghdr;
1659 struct iovec iov[1];
1660 struct cmsghdr *cmsghdr;
1661 void *cmsg_data;
1662 size_t cmsg_size;
1663 u_int i;
1664 int fd2, rv;
1372
1665
1373 if ((fd = create_server_socket()) < 0)
1666 if (sync_send() < 0)
1374 return (-2);
1375
1667 return (-2);
1668
1376 if (sock_type == SOCK_STREAM)
1377 if (listen(fd, LISTENQ) < 0) {
1378 logmsg("listen");
1379 goto failed;
1380 }
1669 fd2 = -1;
1670 rv = -2;
1381
1671
1382 optval = 1;
1383 if (setsockopt(fd, 0, LOCAL_CREDS, &optval, sizeof optval) < 0) {
1384 logmsg("setsockopt(LOCAL_CREDS) for %s socket",
1385 sock_type == SOCK_STREAM ? "stream listening" : "datagram");
1386 if (errno == ENOPROTOOPT) {
1387 error = -1;
1388 goto done_close;
1389 }
1390 goto failed;
1672 cmsg_size = CMSG_SPACE(sizeof(struct timeval));
1673 cmsg_data = malloc(cmsg_size);
1674 if (cmsg_data == NULL) {
1675 logmsg("malloc");
1676 goto done;
1391 }
1392
1677 }
1678
1393 if ((client_pid = fork()) == (pid_t)-1) {
1394 logmsg("fork");
1395 goto failed;
1396 }
1679 if (sock_type == SOCK_STREAM) {
1680 fd2 = socket_accept(fd1);
1681 if (fd2 < 0)
1682 goto done;
1683 } else
1684 fd2 = fd1;
1397
1685
1398 if (client_pid == 0) {
1399 myname = "CLIENT";
1400 if (close_socket((const char *)NULL, fd) < 0)
1401 _exit(1);
1402 t_cmsgcred_client(1);
1403 }
1686 rv = -1;
1687 for (i = 1; i <= ipc_msg.msg_num; ++i) {
1688 dbgmsg("message #%u", i);
1404
1689
1405 if ((error = t_sockcred_server(0, fd, 1)) == -2) {
1406 (void)wait_client();
1407 goto failed;
1408 }
1690 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1691 if (message_recv(fd2, &msghdr) < 0) {
1692 rv = -2;
1693 break;
1694 }
1409
1695
1410 if (wait_client() < 0)
1411 goto failed;
1696 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1697 break;
1412
1698
1413done_close:
1414 if (close_socket(serv_sock_path, fd) < 0) {
1415 logmsgx("close_socket failed");
1416 return (-2);
1699 cmsghdr = CMSG_FIRSTHDR(&msghdr);
1700 if (check_scm_timestamp(cmsghdr) < 0)
1701 break;
1417 }
1702 }
1418 return (error);
1703 if (i > ipc_msg.msg_num)
1704 rv = 0;
1705done:
1706 free(cmsg_data);
1707 if (sock_type == SOCK_STREAM && fd2 >= 0)
1708 if (socket_close(fd2) < 0)
1709 rv = -2;
1710 return (rv);
1711}
1419
1712
1420failed:
1421 if (close_socket(serv_sock_path, fd) < 0)
1422 logmsgx("close_socket failed");
1423 return (-2);
1713static int
1714t_timeval(void)
1715{
1716 return (t_generic(t_timeval_client, t_timeval_server));
1424}
1425
1717}
1718
1426/*
1427 * Send one message with data and control message with SCM_TIMESTAMP
1428 * type to server and exit.
1429 */
1430static void
1431t_timestamp_client(void)
1719static int
1720t_bintime_client(int fd)
1432{
1721{
1433 union {
1434 struct cmsghdr cm;
1435 char control[CMSG_SPACE(sizeof(struct timeval))];
1436 } control_un;
1437 struct msghdr msg;
1722 struct msghdr msghdr;
1438 struct iovec iov[1];
1723 struct iovec iov[1];
1439 struct cmsghdr *cmptr;
1440 int fd;
1724 void *cmsg_data;
1725 size_t cmsg_size;
1726 int rv;
1441
1727
1442 if ((fd = create_unbound_socket()) < 0)
1443 goto failed;
1728 if (sync_recv() < 0)
1729 return (-2);
1444
1730
1445 if (connect_server(fd) < 0)
1446 goto failed_close;
1731 rv = -2;
1447
1732
1448 iov[0].iov_base = ipc_message;
1449 iov[0].iov_len = IPC_MESSAGE_SIZE;
1733 cmsg_size = CMSG_SPACE(sizeof(struct bintime));
1734 cmsg_data = malloc(cmsg_size);
1735 if (cmsg_data == NULL) {
1736 logmsg("malloc");
1737 goto done;
1738 }
1739 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
1740 SCM_BINTIME, sizeof(struct bintime));
1450
1741
1451 msg.msg_name = NULL;
1452 msg.msg_namelen = 0;
1453 msg.msg_iov = iov;
1454 msg.msg_iovlen = 1;
1455 msg.msg_control = control_un.control;
1456 msg.msg_controllen = no_control_data ?
1457 sizeof(struct cmsghdr) :sizeof control_un.control;
1458 msg.msg_flags = 0;
1742 if (socket_connect(fd) < 0)
1743 goto done;
1459
1744
1460 cmptr = CMSG_FIRSTHDR(&msg);
1461 cmptr->cmsg_len = CMSG_LEN(no_control_data ?
1462 0 : sizeof(struct timeval));
1463 cmptr->cmsg_level = SOL_SOCKET;
1464 cmptr->cmsg_type = SCM_TIMESTAMP;
1745 if (message_sendn(fd, &msghdr) < 0)
1746 goto done;
1465
1747
1466 dbgmsg(("msg_controllen = %u, cmsg_len = %u",
1467 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len));
1468
1469 if (sendmsg_timeout(fd, &msg, IPC_MESSAGE_SIZE) < 0)
1470 goto failed_close;
1471
1472 if (close_socket((const char *)NULL, fd) < 0)
1473 goto failed;
1474
1475 _exit(0);
1476
1477failed_close:
1478 (void)close_socket((const char *)NULL, fd);
1479
1480failed:
1481 _exit(1);
1748 rv = 0;
1749done:
1750 free(cmsg_data);
1751 return (rv);
1482}
1483
1752}
1753
1484/*
1485 * Receive one message with data and control message with SCM_TIMESTAMP
1486 * type followed by struct timeval{} from client.
1487 */
1488static int
1754static int
1489t_timestamp_server(int fd1)
1755t_bintime_server(int fd1)
1490{
1756{
1491 union {
1492 struct cmsghdr cm;
1493 char control[CMSG_SPACE(sizeof(struct timeval)) + EXTRA_CMSG_SPACE];
1494 } control_un;
1495 char buf[IPC_MESSAGE_SIZE];
1496 int error, fd2;
1497 struct msghdr msg;
1757 struct msghdr msghdr;
1498 struct iovec iov[1];
1758 struct iovec iov[1];
1499 struct cmsghdr *cmptr;
1500 const struct timeval *timeval;
1759 struct cmsghdr *cmsghdr;
1760 void *cmsg_data;
1761 size_t cmsg_size;
1762 u_int i;
1763 int fd2, rv;
1501
1764
1765 if (sync_send() < 0)
1766 return (-2);
1767
1768 fd2 = -1;
1769 rv = -2;
1770
1771 cmsg_size = CMSG_SPACE(sizeof(struct bintime));
1772 cmsg_data = malloc(cmsg_size);
1773 if (cmsg_data == NULL) {
1774 logmsg("malloc");
1775 goto done;
1776 }
1777
1502 if (sock_type == SOCK_STREAM) {
1778 if (sock_type == SOCK_STREAM) {
1503 if ((fd2 = accept_timeout(fd1)) < 0)
1504 return (-2);
1779 fd2 = socket_accept(fd1);
1780 if (fd2 < 0)
1781 goto done;
1505 } else
1506 fd2 = fd1;
1507
1782 } else
1783 fd2 = fd1;
1784
1508 iov[0].iov_base = buf;
1509 iov[0].iov_len = sizeof buf;
1785 rv = -1;
1786 for (i = 1; i <= ipc_msg.msg_num; ++i) {
1787 dbgmsg("message #%u", i);
1510
1788
1511 msg.msg_name = NULL;
1512 msg.msg_namelen = 0;
1513 msg.msg_iov = iov;
1514 msg.msg_iovlen = 1;
1515 msg.msg_control = control_un.control;
1516 msg.msg_controllen = sizeof control_un.control;
1517 msg.msg_flags = 0;
1789 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1790 if (message_recv(fd2, &msghdr) < 0) {
1791 rv = -2;
1792 break;
1793 }
1518
1794
1519 if (recvmsg_timeout(fd2, &msg, sizeof buf) < 0)
1520 goto failed;
1795 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1796 break;
1521
1797
1522 error = -1;
1523
1524 if (msg.msg_flags & MSG_CTRUNC) {
1525 logmsgx("control data was truncated, MSG_CTRUNC flag is on");
1526 goto done;
1798 cmsghdr = CMSG_FIRSTHDR(&msghdr);
1799 if (check_scm_bintime(cmsghdr) < 0)
1800 break;
1527 }
1801 }
1802 if (i > ipc_msg.msg_num)
1803 rv = 0;
1804done:
1805 free(cmsg_data);
1806 if (sock_type == SOCK_STREAM && fd2 >= 0)
1807 if (socket_close(fd2) < 0)
1808 rv = -2;
1809 return (rv);
1810}
1528
1811
1529 if (msg.msg_controllen < sizeof(struct cmsghdr)) {
1530 logmsgx("msg_controllen %u < %lu (sizeof(struct cmsghdr))",
1531 (u_int)msg.msg_controllen, (u_long)sizeof(struct cmsghdr));
1532 goto done;
1533 }
1812static int
1813t_bintime(void)
1814{
1815 return (t_generic(t_bintime_client, t_bintime_server));
1816}
1534
1817
1535 if ((cmptr = CMSG_FIRSTHDR(&msg)) == NULL) {
1536 logmsgx("CMSG_FIRSTHDR is NULL");
1537 goto done;
1538 }
1818static int
1819t_cmsg_len_client(int fd)
1820{
1821 struct msghdr msghdr;
1822 struct iovec iov[1];
1823 struct cmsghdr *cmsghdr;
1824 void *cmsg_data;
1825 size_t size, cmsg_size;
1826 socklen_t socklen;
1827 int rv;
1539
1828
1540 dbgmsg(("msg_controllen = %u, cmsg_len = %u",
1541 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len));
1829 if (sync_recv() < 0)
1830 return (-2);
1542
1831
1543 if (cmptr->cmsg_level != SOL_SOCKET) {
1544 logmsgx("cmsg_level %d != SOL_SOCKET", cmptr->cmsg_level);
1832 rv = -2;
1833
1834 cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
1835 cmsg_data = malloc(cmsg_size);
1836 if (cmsg_data == NULL) {
1837 logmsg("malloc");
1545 goto done;
1546 }
1838 goto done;
1839 }
1840 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
1841 SCM_CREDS, sizeof(struct cmsgcred));
1842 cmsghdr = CMSG_FIRSTHDR(&msghdr);
1547
1843
1548 if (cmptr->cmsg_type != SCM_TIMESTAMP) {
1549 logmsgx("cmsg_type %d != SCM_TIMESTAMP", cmptr->cmsg_type);
1844 if (socket_connect(fd) < 0)
1550 goto done;
1845 goto done;
1846
1847 size = msghdr.msg_iov != NULL ? msghdr.msg_iov->iov_len : 0;
1848 rv = -1;
1849 for (socklen = 0; socklen < CMSG_LEN(0); ++socklen) {
1850 cmsghdr->cmsg_len = socklen;
1851 dbgmsg("send: data size %zu", size);
1852 dbgmsg("send: msghdr.msg_controllen %u",
1853 (u_int)msghdr.msg_controllen);
1854 dbgmsg("send: cmsghdr.cmsg_len %u",
1855 (u_int)cmsghdr->cmsg_len);
1856 if (sendmsg(fd, &msghdr, 0) < 0)
1857 continue;
1858 logmsgx("sent message with cmsghdr.cmsg_len %u < %u",
1859 (u_int)cmsghdr->cmsg_len, (u_int)CMSG_LEN(0));
1860 break;
1551 }
1861 }
1862 if (socklen == CMSG_LEN(0))
1863 rv = 0;
1552
1864
1553 if (cmptr->cmsg_len != CMSG_LEN(sizeof(struct timeval))) {
1554 logmsgx("cmsg_len %u != %lu (CMSG_LEN(sizeof(struct timeval))",
1555 (u_int)cmptr->cmsg_len, (u_long)CMSG_LEN(sizeof(struct timeval)));
1865 if (sync_send() < 0) {
1866 rv = -2;
1556 goto done;
1557 }
1867 goto done;
1868 }
1869done:
1870 free(cmsg_data);
1871 return (rv);
1872}
1558
1873
1559 timeval = (const struct timeval *)CMSG_DATA(cmptr);
1874static int
1875t_cmsg_len_server(int fd1)
1876{
1877 int fd2, rv;
1560
1878
1561 dbgmsg(("timeval tv_sec %jd, tv_usec %jd",
1562 (intmax_t)timeval->tv_sec, (intmax_t)timeval->tv_usec));
1879 if (sync_send() < 0)
1880 return (-2);
1563
1881
1564 if ((cmptr = CMSG_NXTHDR(&msg, cmptr)) != NULL) {
1565 logmsgx("control data has extra header");
1566 goto done;
1567 }
1882 rv = -2;
1568
1883
1569 error = 0;
1884 if (sock_type == SOCK_STREAM) {
1885 fd2 = socket_accept(fd1);
1886 if (fd2 < 0)
1887 goto done;
1888 } else
1889 fd2 = fd1;
1570
1890
1891 if (sync_recv() < 0)
1892 goto done;
1893
1894 rv = 0;
1571done:
1895done:
1572 if (sock_type == SOCK_STREAM)
1573 if (close(fd2) < 0) {
1574 logmsg("close");
1575 return (-2);
1576 }
1577 return (error);
1896 if (sock_type == SOCK_STREAM && fd2 >= 0)
1897 if (socket_close(fd2) < 0)
1898 rv = -2;
1899 return (rv);
1900}
1578
1901
1579failed:
1580 if (sock_type == SOCK_STREAM)
1581 if (close(fd2) < 0)
1582 logmsg("close");
1583 return (-2);
1902static int
1903t_cmsg_len(void)
1904{
1905 return (t_generic(t_cmsg_len_client, t_cmsg_len_server));
1584}
1585
1586static int
1906}
1907
1908static int
1587t_timestamp(void)
1909t_peercred_client(int fd)
1588{
1910{
1589 int error, fd;
1911 struct xucred xucred;
1912 socklen_t len;
1590
1913
1591 if ((fd = create_server_socket()) < 0)
1592 return (-2);
1914 if (sync_recv() < 0)
1915 return (-1);
1593
1916
1594 if (sock_type == SOCK_STREAM)
1595 if (listen(fd, LISTENQ) < 0) {
1596 logmsg("listen");
1597 goto failed;
1598 }
1917 if (socket_connect(fd) < 0)
1918 return (-1);
1599
1919
1600 if ((client_pid = fork()) == (pid_t)-1) {
1601 logmsg("fork");
1602 goto failed;
1920 len = sizeof(xucred);
1921 if (getsockopt(fd, 0, LOCAL_PEERCRED, &xucred, &len) < 0) {
1922 logmsg("getsockopt(LOCAL_PEERCRED)");
1923 return (-1);
1603 }
1604
1924 }
1925
1605 if (client_pid == 0) {
1606 myname = "CLIENT";
1607 if (close_socket((const char *)NULL, fd) < 0)
1608 _exit(1);
1609 t_timestamp_client();
1610 }
1926 if (check_xucred(&xucred, len) < 0)
1927 return (-1);
1611
1928
1612 if ((error = t_timestamp_server(fd)) == -2) {
1613 (void)wait_client();
1614 goto failed;
1615 }
1929 return (0);
1930}
1616
1931
1617 if (wait_client() < 0)
1618 goto failed;
1932static int
1933t_peercred_server(int fd1)
1934{
1935 struct xucred xucred;
1936 socklen_t len;
1937 int fd2, rv;
1619
1938
1620 if (close_socket(serv_sock_path, fd) < 0) {
1621 logmsgx("close_socket failed");
1939 if (sync_send() < 0)
1622 return (-2);
1940 return (-2);
1941
1942 fd2 = socket_accept(fd1);
1943 if (fd2 < 0)
1944 return (-2);
1945
1946 len = sizeof(xucred);
1947 if (getsockopt(fd2, 0, LOCAL_PEERCRED, &xucred, &len) < 0) {
1948 logmsg("getsockopt(LOCAL_PEERCRED)");
1949 rv = -2;
1950 goto done;
1623 }
1951 }
1624 return (error);
1625
1952
1626failed:
1627 if (close_socket(serv_sock_path, fd) < 0)
1628 logmsgx("close_socket failed");
1629 return (-2);
1953 if (check_xucred(&xucred, len) < 0) {
1954 rv = -1;
1955 goto done;
1956 }
1957
1958 rv = 0;
1959done:
1960 if (socket_close(fd2) < 0)
1961 rv = -2;
1962 return (rv);
1630}
1963}
1964
1965static int
1966t_peercred(void)
1967{
1968 return (t_generic(t_peercred_client, t_peercred_server));
1969}