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