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