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} |
|