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