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