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
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
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 #include <sys/socket.h>
29 #include <sys/un.h>
30 #include <err.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <inttypes.h>
34 #include <stdarg.h>
35 #include <stdbool.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <sys/wait.h>
41 
42 #include "uc_common.h"
43 
44 #ifndef LISTENQ
45 # define LISTENQ	1
46 #endif
47 
48 #ifndef	TIMEOUT
49 # define TIMEOUT	2
50 #endif
51 
52 #define	SYNC_SERVER	0
53 #define	SYNC_CLIENT	1
54 #define	SYNC_RECV	0
55 #define	SYNC_SEND	1
56 
57 #define	LOGMSG_SIZE	128
58 
59 void
uc_output(const char * format,...)60 uc_output(const char *format, ...)
61 {
62 	char buf[LOGMSG_SIZE];
63 	va_list ap;
64 
65 	va_start(ap, format);
66 	if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
67 		err(EXIT_FAILURE, "output: vsnprintf failed");
68 	write(STDOUT_FILENO, buf, strlen(buf));
69 	va_end(ap);
70 }
71 
72 void
uc_logmsg(const char * format,...)73 uc_logmsg(const char *format, ...)
74 {
75 	char buf[LOGMSG_SIZE];
76 	va_list ap;
77 	int errno_save;
78 
79 	errno_save = errno;
80 	va_start(ap, format);
81 	if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
82 		err(EXIT_FAILURE, "logmsg: vsnprintf failed");
83 	if (errno_save == 0)
84 		uc_output("%s: %s\n", uc_cfg.proc_name, buf);
85 	else
86 		uc_output("%s: %s: %s\n", uc_cfg.proc_name, buf,
87 		    strerror(errno_save));
88 	va_end(ap);
89 	errno = errno_save;
90 }
91 
92 void
uc_vlogmsgx(const char * format,va_list ap)93 uc_vlogmsgx(const char *format, va_list ap)
94 {
95 	char buf[LOGMSG_SIZE];
96 
97 	if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
98 		err(EXIT_FAILURE, "uc_logmsgx: vsnprintf failed");
99 	uc_output("%s: %s\n", uc_cfg.proc_name, buf);
100 }
101 
102 void
uc_logmsgx(const char * format,...)103 uc_logmsgx(const char *format, ...)
104 {
105 	va_list ap;
106 
107 	va_start(ap, format);
108 	uc_vlogmsgx(format, ap);
109 	va_end(ap);
110 }
111 
112 void
uc_dbgmsg(const char * format,...)113 uc_dbgmsg(const char *format, ...)
114 {
115 	va_list ap;
116 
117 	if (uc_cfg.debug) {
118 		va_start(ap, format);
119 		uc_vlogmsgx(format, ap);
120 		va_end(ap);
121 	}
122 }
123 
124 int
uc_socket_create(void)125 uc_socket_create(void)
126 {
127 	struct timeval tv;
128 	int fd;
129 
130 	fd = socket(PF_LOCAL, uc_cfg.sock_type, 0);
131 	if (fd < 0) {
132 		uc_logmsg("socket_create: socket(PF_LOCAL, %s, 0)", uc_cfg.sock_type_str);
133 		return (-1);
134 	}
135 	if (uc_cfg.server_flag)
136 		uc_cfg.serv_sock_fd = fd;
137 
138 	tv.tv_sec = TIMEOUT;
139 	tv.tv_usec = 0;
140 	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 ||
141 	    setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
142 		uc_logmsg("socket_create: setsockopt(SO_RCVTIMEO/SO_SNDTIMEO)");
143 		goto failed;
144 	}
145 
146 	if (uc_cfg.server_flag) {
147 		if (bind(fd, (struct sockaddr *)&uc_cfg.serv_addr_sun,
148 		    uc_cfg.serv_addr_sun.sun_len) < 0) {
149 			uc_logmsg("socket_create: bind(%s)",
150 			    uc_cfg.serv_addr_sun.sun_path);
151 			goto failed;
152 		}
153 		if (uc_cfg.sock_type == SOCK_STREAM) {
154 			int val;
155 
156 			if (listen(fd, LISTENQ) < 0) {
157 				uc_logmsg("socket_create: listen");
158 				goto failed;
159 			}
160 			val = fcntl(fd, F_GETFL, 0);
161 			if (val < 0) {
162 				uc_logmsg("socket_create: fcntl(F_GETFL)");
163 				goto failed;
164 			}
165 			if (fcntl(fd, F_SETFL, val | O_NONBLOCK) < 0) {
166 				uc_logmsg("socket_create: fcntl(F_SETFL)");
167 				goto failed;
168 			}
169 		}
170 	}
171 
172 	return (fd);
173 
174 failed:
175 	if (close(fd) < 0)
176 		uc_logmsg("socket_create: close");
177 	if (uc_cfg.server_flag)
178 		if (unlink(uc_cfg.serv_addr_sun.sun_path) < 0)
179 			uc_logmsg("socket_close: unlink(%s)",
180 			    uc_cfg.serv_addr_sun.sun_path);
181 	return (-1);
182 }
183 
184 int
uc_socket_close(int fd)185 uc_socket_close(int fd)
186 {
187 	int rv;
188 
189 	rv = 0;
190 	if (close(fd) < 0) {
191 		uc_logmsg("socket_close: close");
192 		rv = -1;
193 	}
194 	if (uc_cfg.server_flag && fd == uc_cfg.serv_sock_fd)
195 		if (unlink(uc_cfg.serv_addr_sun.sun_path) < 0) {
196 			uc_logmsg("socket_close: unlink(%s)",
197 			    uc_cfg.serv_addr_sun.sun_path);
198 			rv = -1;
199 		}
200 	return (rv);
201 }
202 
203 int
uc_socket_connect(int fd)204 uc_socket_connect(int fd)
205 {
206 	uc_dbgmsg("connect");
207 
208 	if (connect(fd, (struct sockaddr *)&uc_cfg.serv_addr_sun,
209 	    uc_cfg.serv_addr_sun.sun_len) < 0) {
210 		uc_logmsg("socket_connect: connect(%s)", uc_cfg.serv_addr_sun.sun_path);
211 		return (-1);
212 	}
213 	return (0);
214 }
215 
216 int
uc_sync_recv(void)217 uc_sync_recv(void)
218 {
219 	ssize_t ssize;
220 	int fd;
221 	char buf;
222 
223 	uc_dbgmsg("sync: wait");
224 
225 	fd = uc_cfg.sync_fd[uc_cfg.server_flag ? SYNC_SERVER : SYNC_CLIENT][SYNC_RECV];
226 
227 	ssize = read(fd, &buf, 1);
228 	if (ssize < 0) {
229 		uc_logmsg("sync_recv: read");
230 		return (-1);
231 	}
232 	if (ssize < 1) {
233 		uc_logmsgx("sync_recv: read %zd of 1 byte", ssize);
234 		return (-1);
235 	}
236 
237 	uc_dbgmsg("sync: received");
238 
239 	return (0);
240 }
241 
242 int
uc_sync_send(void)243 uc_sync_send(void)
244 {
245 	ssize_t ssize;
246 	int fd;
247 
248 	uc_dbgmsg("sync: send");
249 
250 	fd = uc_cfg.sync_fd[uc_cfg.server_flag ? SYNC_CLIENT : SYNC_SERVER][SYNC_SEND];
251 
252 	ssize = write(fd, "", 1);
253 	if (ssize < 0) {
254 		uc_logmsg("uc_sync_send: write");
255 		return (-1);
256 	}
257 	if (ssize < 1) {
258 		uc_logmsgx("uc_sync_send: sent %zd of 1 byte", ssize);
259 		return (-1);
260 	}
261 
262 	return (0);
263 }
264 
265 int
uc_message_send(int fd,const struct msghdr * msghdr)266 uc_message_send(int fd, const struct msghdr *msghdr)
267 {
268 	const struct cmsghdr *cmsghdr;
269 	size_t size;
270 	ssize_t ssize;
271 
272 	size = msghdr->msg_iov != 0 ? msghdr->msg_iov->iov_len : 0;
273 	uc_dbgmsg("send: data size %zu", size);
274 	uc_dbgmsg("send: msghdr.msg_controllen %u",
275 	    (u_int)msghdr->msg_controllen);
276 	cmsghdr = CMSG_FIRSTHDR(msghdr);
277 	if (cmsghdr != NULL)
278 		uc_dbgmsg("send: cmsghdr.cmsg_len %u",
279 		    (u_int)cmsghdr->cmsg_len);
280 
281 	ssize = sendmsg(fd, msghdr, 0);
282 	if (ssize < 0) {
283 		uc_logmsg("message_send: sendmsg");
284 		return (-1);
285 	}
286 	if ((size_t)ssize != size) {
287 		uc_logmsgx("message_send: sendmsg: sent %zd of %zu bytes",
288 		    ssize, size);
289 		return (-1);
290 	}
291 
292 	if (!uc_cfg.send_data_flag)
293 		if (uc_sync_send() < 0)
294 			return (-1);
295 
296 	return (0);
297 }
298 
299 int
uc_message_sendn(int fd,struct msghdr * msghdr)300 uc_message_sendn(int fd, struct msghdr *msghdr)
301 {
302 	u_int i;
303 
304 	for (i = 1; i <= uc_cfg.ipc_msg.msg_num; ++i) {
305 		uc_dbgmsg("message #%u", i);
306 		if (uc_message_send(fd, msghdr) < 0)
307 			return (-1);
308 	}
309 	return (0);
310 }
311 
312 int
uc_message_recv(int fd,struct msghdr * msghdr)313 uc_message_recv(int fd, struct msghdr *msghdr)
314 {
315 	const struct cmsghdr *cmsghdr;
316 	size_t size;
317 	ssize_t ssize;
318 
319 	if (!uc_cfg.send_data_flag)
320 		if (uc_sync_recv() < 0)
321 			return (-1);
322 
323 	size = msghdr->msg_iov != NULL ? msghdr->msg_iov->iov_len : 0;
324 	ssize = recvmsg(fd, msghdr, MSG_WAITALL);
325 	if (ssize < 0) {
326 		uc_logmsg("message_recv: recvmsg");
327 		return (-1);
328 	}
329 	if ((size_t)ssize != size) {
330 		uc_logmsgx("message_recv: recvmsg: received %zd of %zu bytes",
331 		    ssize, size);
332 		return (-1);
333 	}
334 
335 	uc_dbgmsg("recv: data size %zd", ssize);
336 	uc_dbgmsg("recv: msghdr.msg_controllen %u",
337 	    (u_int)msghdr->msg_controllen);
338 	cmsghdr = CMSG_FIRSTHDR(msghdr);
339 	if (cmsghdr != NULL)
340 		uc_dbgmsg("recv: cmsghdr.cmsg_len %u",
341 		    (u_int)cmsghdr->cmsg_len);
342 
343 	if (memcmp(uc_cfg.ipc_msg.buf_recv, uc_cfg.ipc_msg.buf_send, size) != 0) {
344 		uc_logmsgx("message_recv: received message has wrong content");
345 		return (-1);
346 	}
347 
348 	return (0);
349 }
350 
351 int
uc_socket_accept(int listenfd)352 uc_socket_accept(int listenfd)
353 {
354 	fd_set rset;
355 	struct timeval tv;
356 	int fd, rv, val;
357 
358 	uc_dbgmsg("accept");
359 
360 	FD_ZERO(&rset);
361 	FD_SET(listenfd, &rset);
362 	tv.tv_sec = TIMEOUT;
363 	tv.tv_usec = 0;
364 	rv = select(listenfd + 1, &rset, (fd_set *)NULL, (fd_set *)NULL, &tv);
365 	if (rv < 0) {
366 		uc_logmsg("socket_accept: select");
367 		return (-1);
368 	}
369 	if (rv == 0) {
370 		uc_logmsgx("socket_accept: select timeout");
371 		return (-1);
372 	}
373 
374 	fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL);
375 	if (fd < 0) {
376 		uc_logmsg("socket_accept: accept");
377 		return (-1);
378 	}
379 
380 	val = fcntl(fd, F_GETFL, 0);
381 	if (val < 0) {
382 		uc_logmsg("socket_accept: fcntl(F_GETFL)");
383 		goto failed;
384 	}
385 	if (fcntl(fd, F_SETFL, val & ~O_NONBLOCK) < 0) {
386 		uc_logmsg("socket_accept: fcntl(F_SETFL)");
387 		goto failed;
388 	}
389 
390 	return (fd);
391 
392 failed:
393 	if (close(fd) < 0)
394 		uc_logmsg("socket_accept: close");
395 	return (-1);
396 }
397 
398 int
uc_check_msghdr(const struct msghdr * msghdr,size_t size)399 uc_check_msghdr(const struct msghdr *msghdr, size_t size)
400 {
401 	if (msghdr->msg_flags & MSG_TRUNC) {
402 		uc_logmsgx("msghdr.msg_flags has MSG_TRUNC");
403 		return (-1);
404 	}
405 	if (msghdr->msg_flags & MSG_CTRUNC) {
406 		uc_logmsgx("msghdr.msg_flags has MSG_CTRUNC");
407 		return (-1);
408 	}
409 	if (msghdr->msg_controllen < size) {
410 		uc_logmsgx("msghdr.msg_controllen %u < %zu",
411 		    (u_int)msghdr->msg_controllen, size);
412 		return (-1);
413 	}
414 	if (msghdr->msg_controllen > 0 && size == 0) {
415 		uc_logmsgx("msghdr.msg_controllen %u > 0",
416 		    (u_int)msghdr->msg_controllen);
417 		return (-1);
418 	}
419 	return (0);
420 }
421 
422 int
uc_check_cmsghdr(const struct cmsghdr * cmsghdr,int type,size_t size)423 uc_check_cmsghdr(const struct cmsghdr *cmsghdr, int type, size_t size)
424 {
425 	if (cmsghdr == NULL) {
426 		uc_logmsgx("cmsghdr is NULL");
427 		return (-1);
428 	}
429 	if (cmsghdr->cmsg_level != SOL_SOCKET) {
430 		uc_logmsgx("cmsghdr.cmsg_level %d != SOL_SOCKET",
431 		    cmsghdr->cmsg_level);
432 		return (-1);
433 	}
434 	if (cmsghdr->cmsg_type != type) {
435 		uc_logmsgx("cmsghdr.cmsg_type %d != %d",
436 		    cmsghdr->cmsg_type, type);
437 		return (-1);
438 	}
439 	if (cmsghdr->cmsg_len != CMSG_LEN(size)) {
440 		uc_logmsgx("cmsghdr.cmsg_len %u != %zu",
441 		    (u_int)cmsghdr->cmsg_len, CMSG_LEN(size));
442 		return (-1);
443 	}
444 	return (0);
445 }
446 
447 static void
uc_msghdr_init_generic(struct msghdr * msghdr,struct iovec * iov,void * cmsg_data)448 uc_msghdr_init_generic(struct msghdr *msghdr, struct iovec *iov, void *cmsg_data)
449 {
450 	msghdr->msg_name = NULL;
451 	msghdr->msg_namelen = 0;
452 	if (uc_cfg.send_data_flag) {
453 		iov->iov_base = uc_cfg.server_flag ?
454 		    uc_cfg.ipc_msg.buf_recv : uc_cfg.ipc_msg.buf_send;
455 		iov->iov_len = uc_cfg.ipc_msg.buf_size;
456 		msghdr->msg_iov = iov;
457 		msghdr->msg_iovlen = 1;
458 	} else {
459 		msghdr->msg_iov = NULL;
460 		msghdr->msg_iovlen = 0;
461 	}
462 	msghdr->msg_control = cmsg_data;
463 	msghdr->msg_flags = 0;
464 }
465 
466 void
uc_msghdr_init_server(struct msghdr * msghdr,struct iovec * iov,void * cmsg_data,size_t cmsg_size)467 uc_msghdr_init_server(struct msghdr *msghdr, struct iovec *iov,
468     void *cmsg_data, size_t cmsg_size)
469 {
470 	uc_msghdr_init_generic(msghdr, iov, cmsg_data);
471 	msghdr->msg_controllen = cmsg_size;
472 	uc_dbgmsg("init: data size %zu", msghdr->msg_iov != NULL ?
473 	    msghdr->msg_iov->iov_len : (size_t)0);
474 	uc_dbgmsg("init: msghdr.msg_controllen %u",
475 	    (u_int)msghdr->msg_controllen);
476 }
477 
478 void
uc_msghdr_init_client(struct msghdr * msghdr,struct iovec * iov,void * cmsg_data,size_t cmsg_size,int type,size_t arr_size)479 uc_msghdr_init_client(struct msghdr *msghdr, struct iovec *iov,
480     void *cmsg_data, size_t cmsg_size, int type, size_t arr_size)
481 {
482 	struct cmsghdr *cmsghdr;
483 
484 	uc_msghdr_init_generic(msghdr, iov, cmsg_data);
485 	if (cmsg_data != NULL) {
486 		if (uc_cfg.send_array_flag)
487 			uc_dbgmsg("sending an array");
488 		else
489 			uc_dbgmsg("sending a scalar");
490 		msghdr->msg_controllen = uc_cfg.send_array_flag ?
491 		    cmsg_size : CMSG_SPACE(0);
492 		cmsghdr = CMSG_FIRSTHDR(msghdr);
493 		cmsghdr->cmsg_level = SOL_SOCKET;
494 		cmsghdr->cmsg_type = type;
495 		cmsghdr->cmsg_len = CMSG_LEN(uc_cfg.send_array_flag ? arr_size : 0);
496 	} else
497 		msghdr->msg_controllen = 0;
498 }
499 
500 int
uc_client_fork(void)501 uc_client_fork(void)
502 {
503 	int fd1, fd2;
504 
505 	if (pipe(uc_cfg.sync_fd[SYNC_SERVER]) < 0 ||
506 	    pipe(uc_cfg.sync_fd[SYNC_CLIENT]) < 0) {
507 		uc_logmsg("client_fork: pipe");
508 		return (-1);
509 	}
510 	uc_cfg.client_pid = fork();
511 	if (uc_cfg.client_pid == (pid_t)-1) {
512 		uc_logmsg("client_fork: fork");
513 		return (-1);
514 	}
515 	if (uc_cfg.client_pid == 0) {
516 		uc_cfg.proc_name = "CLIENT";
517 		uc_cfg.server_flag = false;
518 		fd1 = uc_cfg.sync_fd[SYNC_SERVER][SYNC_RECV];
519 		fd2 = uc_cfg.sync_fd[SYNC_CLIENT][SYNC_SEND];
520 	} else {
521 		fd1 = uc_cfg.sync_fd[SYNC_SERVER][SYNC_SEND];
522 		fd2 = uc_cfg.sync_fd[SYNC_CLIENT][SYNC_RECV];
523 	}
524 	if (close(fd1) < 0 || close(fd2) < 0) {
525 		uc_logmsg("client_fork: close");
526 		return (-1);
527 	}
528 	return (uc_cfg.client_pid != 0);
529 }
530 
531 void
uc_client_exit(int rv)532 uc_client_exit(int rv)
533 {
534 	if (close(uc_cfg.sync_fd[SYNC_SERVER][SYNC_SEND]) < 0 ||
535 	    close(uc_cfg.sync_fd[SYNC_CLIENT][SYNC_RECV]) < 0) {
536 		uc_logmsg("client_exit: close");
537 		rv = -1;
538 	}
539 	rv = rv == 0 ? EXIT_SUCCESS : -rv;
540 	uc_dbgmsg("exit: code %d", rv);
541 	_exit(rv);
542 }
543 
544 int
uc_client_wait(void)545 uc_client_wait(void)
546 {
547 	int status;
548 	pid_t pid;
549 
550 	uc_dbgmsg("waiting for client");
551 
552 	if (close(uc_cfg.sync_fd[SYNC_SERVER][SYNC_RECV]) < 0 ||
553 	    close(uc_cfg.sync_fd[SYNC_CLIENT][SYNC_SEND]) < 0) {
554 		uc_logmsg("client_wait: close");
555 		return (-1);
556 	}
557 
558 	pid = waitpid(uc_cfg.client_pid, &status, 0);
559 	if (pid == (pid_t)-1) {
560 		uc_logmsg("client_wait: waitpid");
561 		return (-1);
562 	}
563 
564 	if (WIFEXITED(status)) {
565 		if (WEXITSTATUS(status) != EXIT_SUCCESS) {
566 			uc_logmsgx("client exit status is %d",
567 			    WEXITSTATUS(status));
568 			return (-WEXITSTATUS(status));
569 		}
570 	} else {
571 		if (WIFSIGNALED(status))
572 			uc_logmsgx("abnormal termination of client, signal %d%s",
573 			    WTERMSIG(status), WCOREDUMP(status) ?
574 			    " (core file generated)" : "");
575 		else
576 			uc_logmsgx("termination of client, unknown status");
577 		return (-1);
578 	}
579 
580 	return (0);
581 }
582 
583 int
uc_check_groups(const char * gid_arr_str,const gid_t * gid_arr,const char * gid_num_str,int gid_num,bool all_gids)584 uc_check_groups(const char *gid_arr_str, const gid_t *gid_arr,
585     const char *gid_num_str, int gid_num, bool all_gids)
586 {
587 	int i;
588 
589 	for (i = 0; i < gid_num; ++i)
590 		uc_dbgmsg("%s[%d] %lu", gid_arr_str, i, (u_long)gid_arr[i]);
591 
592 	if (all_gids) {
593 		if (gid_num != uc_cfg.proc_cred.gid_num) {
594 			uc_logmsgx("%s %d != %d", gid_num_str, gid_num,
595 			    uc_cfg.proc_cred.gid_num);
596 			return (-1);
597 		}
598 	} else {
599 		if (gid_num > uc_cfg.proc_cred.gid_num) {
600 			uc_logmsgx("%s %d > %d", gid_num_str, gid_num,
601 			    uc_cfg.proc_cred.gid_num);
602 			return (-1);
603 		}
604 	}
605 	if (memcmp(gid_arr, uc_cfg.proc_cred.gid_arr,
606 	    gid_num * sizeof(*gid_arr)) != 0) {
607 		uc_logmsgx("%s content is wrong", gid_arr_str);
608 		for (i = 0; i < gid_num; ++i)
609 			if (gid_arr[i] != uc_cfg.proc_cred.gid_arr[i]) {
610 				uc_logmsgx("%s[%d] %lu != %lu",
611 				    gid_arr_str, i, (u_long)gid_arr[i],
612 				    (u_long)uc_cfg.proc_cred.gid_arr[i]);
613 				break;
614 			}
615 		return (-1);
616 	}
617 	return (0);
618 }
619 
620 int
uc_check_scm_creds_cmsgcred(struct cmsghdr * cmsghdr)621 uc_check_scm_creds_cmsgcred(struct cmsghdr *cmsghdr)
622 {
623 	const struct cmsgcred *cmcred;
624 	int rc;
625 
626 	if (uc_check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(struct cmsgcred)) < 0)
627 		return (-1);
628 
629 	cmcred = (struct cmsgcred *)CMSG_DATA(cmsghdr);
630 
631 	uc_dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmcred->cmcred_pid);
632 	uc_dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmcred->cmcred_uid);
633 	uc_dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmcred->cmcred_euid);
634 	uc_dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmcred->cmcred_gid);
635 	uc_dbgmsg("cmsgcred.cmcred_ngroups %d", cmcred->cmcred_ngroups);
636 
637 	rc = 0;
638 
639 	if (cmcred->cmcred_pid != uc_cfg.client_pid) {
640 		uc_logmsgx("cmsgcred.cmcred_pid %ld != %ld",
641 		    (long)cmcred->cmcred_pid, (long)uc_cfg.client_pid);
642 		rc = -1;
643 	}
644 	if (cmcred->cmcred_uid != uc_cfg.proc_cred.uid) {
645 		uc_logmsgx("cmsgcred.cmcred_uid %lu != %lu",
646 		    (u_long)cmcred->cmcred_uid, (u_long)uc_cfg.proc_cred.uid);
647 		rc = -1;
648 	}
649 	if (cmcred->cmcred_euid != uc_cfg.proc_cred.euid) {
650 		uc_logmsgx("cmsgcred.cmcred_euid %lu != %lu",
651 		    (u_long)cmcred->cmcred_euid, (u_long)uc_cfg.proc_cred.euid);
652 		rc = -1;
653 	}
654 	if (cmcred->cmcred_gid != uc_cfg.proc_cred.gid) {
655 		uc_logmsgx("cmsgcred.cmcred_gid %lu != %lu",
656 		    (u_long)cmcred->cmcred_gid, (u_long)uc_cfg.proc_cred.gid);
657 		rc = -1;
658 	}
659 	if (cmcred->cmcred_ngroups == 0) {
660 		uc_logmsgx("cmsgcred.cmcred_ngroups == 0");
661 		rc = -1;
662 	}
663 	if (cmcred->cmcred_ngroups < 0) {
664 		uc_logmsgx("cmsgcred.cmcred_ngroups %d < 0",
665 		    cmcred->cmcred_ngroups);
666 		rc = -1;
667 	}
668 	if (cmcred->cmcred_ngroups > CMGROUP_MAX) {
669 		uc_logmsgx("cmsgcred.cmcred_ngroups %d > %d",
670 		    cmcred->cmcred_ngroups, CMGROUP_MAX);
671 		rc = -1;
672 	}
673 	if (cmcred->cmcred_groups[0] != uc_cfg.proc_cred.egid) {
674 		uc_logmsgx("cmsgcred.cmcred_groups[0] %lu != %lu (EGID)",
675 		    (u_long)cmcred->cmcred_groups[0], (u_long)uc_cfg.proc_cred.egid);
676 		rc = -1;
677 	}
678 	if (uc_check_groups("cmsgcred.cmcred_groups", cmcred->cmcred_groups,
679 	    "cmsgcred.cmcred_ngroups", cmcred->cmcred_ngroups, false) < 0)
680 		rc = -1;
681 	return (rc);
682 }
683 
684 int
uc_check_scm_creds_sockcred(struct cmsghdr * cmsghdr)685 uc_check_scm_creds_sockcred(struct cmsghdr *cmsghdr)
686 {
687 	const struct sockcred *sc;
688 	int rc;
689 
690 	if (uc_check_cmsghdr(cmsghdr, SCM_CREDS,
691 	    SOCKCREDSIZE(uc_cfg.proc_cred.gid_num)) < 0)
692 		return (-1);
693 
694 	sc = (struct sockcred *)CMSG_DATA(cmsghdr);
695 
696 	rc = 0;
697 
698 	uc_dbgmsg("sockcred.sc_uid %lu", (u_long)sc->sc_uid);
699 	uc_dbgmsg("sockcred.sc_euid %lu", (u_long)sc->sc_euid);
700 	uc_dbgmsg("sockcred.sc_gid %lu", (u_long)sc->sc_gid);
701 	uc_dbgmsg("sockcred.sc_egid %lu", (u_long)sc->sc_egid);
702 	uc_dbgmsg("sockcred.sc_ngroups %d", sc->sc_ngroups);
703 
704 	if (sc->sc_uid != uc_cfg.proc_cred.uid) {
705 		uc_logmsgx("sockcred.sc_uid %lu != %lu",
706 		    (u_long)sc->sc_uid, (u_long)uc_cfg.proc_cred.uid);
707 		rc = -1;
708 	}
709 	if (sc->sc_euid != uc_cfg.proc_cred.euid) {
710 		uc_logmsgx("sockcred.sc_euid %lu != %lu",
711 		    (u_long)sc->sc_euid, (u_long)uc_cfg.proc_cred.euid);
712 		rc = -1;
713 	}
714 	if (sc->sc_gid != uc_cfg.proc_cred.gid) {
715 		uc_logmsgx("sockcred.sc_gid %lu != %lu",
716 		    (u_long)sc->sc_gid, (u_long)uc_cfg.proc_cred.gid);
717 		rc = -1;
718 	}
719 	if (sc->sc_egid != uc_cfg.proc_cred.egid) {
720 		uc_logmsgx("sockcred.sc_egid %lu != %lu",
721 		    (u_long)sc->sc_egid, (u_long)uc_cfg.proc_cred.egid);
722 		rc = -1;
723 	}
724 	if (sc->sc_ngroups == 0) {
725 		uc_logmsgx("sockcred.sc_ngroups == 0");
726 		rc = -1;
727 	}
728 	if (sc->sc_ngroups < 0) {
729 		uc_logmsgx("sockcred.sc_ngroups %d < 0",
730 		    sc->sc_ngroups);
731 		rc = -1;
732 	}
733 	if (sc->sc_ngroups != uc_cfg.proc_cred.gid_num) {
734 		uc_logmsgx("sockcred.sc_ngroups %d != %u",
735 		    sc->sc_ngroups, uc_cfg.proc_cred.gid_num);
736 		rc = -1;
737 	}
738 	if (uc_check_groups("sockcred.sc_groups", sc->sc_groups,
739 	    "sockcred.sc_ngroups", sc->sc_ngroups, true) < 0)
740 		rc = -1;
741 	return (rc);
742 }
743