1 /* $NetBSD: privsep.c,v 1.28 2025/03/08 16:39:08 christos Exp $ */ 2 3 /* Id: privsep.c,v 1.15 2005/08/08 11:23:44 vanhu Exp */ 4 5 /* 6 * Copyright (C) 2004 Emmanuel Dreyfus 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "config.h" 35 36 #include <unistd.h> 37 #include <string.h> 38 #ifdef __NetBSD__ 39 #include <stdlib.h> /* for setproctitle */ 40 #endif 41 #include <errno.h> 42 #include <signal.h> 43 #include <pwd.h> 44 45 #include <sys/types.h> 46 #include <sys/socket.h> 47 #include <sys/param.h> 48 49 #include <netinet/in.h> 50 51 #include "gcmalloc.h" 52 #include "vmbuf.h" 53 #include "misc.h" 54 #include "plog.h" 55 #include "var.h" 56 57 #include "crypto_openssl.h" 58 #include "isakmp_var.h" 59 #include "isakmp.h" 60 #ifdef ENABLE_HYBRID 61 #include "resolv.h" 62 #include "isakmp_xauth.h" 63 #include "isakmp_cfg.h" 64 #endif 65 #include "localconf.h" 66 #include "remoteconf.h" 67 #include "admin.h" 68 #include "sockmisc.h" 69 #include "privsep.h" 70 #include "session.h" 71 72 static int privsep_sock[2] = { -1, -1 }; 73 74 static int privsep_recv(int, struct privsep_com_msg **, size_t *); 75 static int privsep_send(int, struct privsep_com_msg *, size_t); 76 static int safety_check(struct privsep_com_msg *, int); 77 static int port_check(int); 78 static int unsafe_env(char *const *); 79 static int unknown_name(int); 80 static int unsafe_path(char *, int); 81 static int rec_fd(int); 82 static int send_fd(int, int); 83 84 struct socket_args { 85 int domain; 86 int type; 87 int protocol; 88 }; 89 90 struct sockopt_args { 91 int s; 92 int level; 93 int optname; 94 const void *optval; 95 socklen_t optlen; 96 }; 97 98 struct bind_args { 99 int s; 100 const struct sockaddr *addr; 101 socklen_t addrlen; 102 }; 103 104 static int 105 privsep_send(int sock, struct privsep_com_msg *buf, size_t len) 106 { 107 if (buf == NULL) 108 return 0; 109 110 if (sendto(sock, (char *)buf, len, 0, NULL, 0) == -1) { 111 plog(LLV_ERROR, LOCATION, NULL, 112 "privsep_send failed: %s\n", 113 strerror(errno)); 114 return -1; 115 } 116 117 racoon_free((char *)buf); 118 119 return 0; 120 } 121 122 123 static int 124 privsep_recv(int sock, struct privsep_com_msg **bufp, size_t *lenp) 125 { 126 struct admin_com com; 127 struct admin_com *combuf; 128 ssize_t len; 129 130 *bufp = NULL; 131 *lenp = 0; 132 133 /* Get the header */ 134 while ((len = recvfrom(sock, (char *)&com, 135 sizeof(com), MSG_PEEK, NULL, NULL)) == -1) { 136 if (errno == EINTR) 137 continue; 138 if (errno == ECONNRESET) 139 return -1; 140 141 plog(LLV_ERROR, LOCATION, NULL, 142 "privsep_recv failed: %s\n", 143 strerror(errno)); 144 return -1; 145 } 146 147 /* EOF, other side has closed. */ 148 if (len == 0) 149 return -1; 150 151 /* Check for short packets */ 152 if (len < sizeof(com)) { 153 plog(LLV_ERROR, LOCATION, NULL, 154 "corrupted privsep message (short header)\n"); 155 return -1; 156 } 157 158 /* Allocate buffer for the whole message */ 159 if ((combuf = (struct admin_com *)racoon_malloc(com.ac_len)) == NULL) { 160 plog(LLV_ERROR, LOCATION, NULL, 161 "failed to allocate memory: %s\n", strerror(errno)); 162 return -1; 163 } 164 165 /* Get the whole buffer */ 166 while ((len = recvfrom(sock, (char *)combuf, 167 com.ac_len, 0, NULL, NULL)) == -1) { 168 if (errno == EINTR) 169 continue; 170 if (errno == ECONNRESET) 171 return -1; 172 plog(LLV_ERROR, LOCATION, NULL, 173 "failed to recv privsep command: %s\n", 174 strerror(errno)); 175 return -1; 176 } 177 178 /* We expect len to match */ 179 if (len != com.ac_len) { 180 plog(LLV_ERROR, LOCATION, NULL, 181 "corrupted privsep message (short packet)\n"); 182 return -1; 183 } 184 185 *bufp = (struct privsep_com_msg *)combuf; 186 *lenp = len; 187 188 return 0; 189 } 190 191 /*ARGSUSED*/ 192 static int 193 privsep_do_exit(void *ctx __unused, int fd __unused) 194 { 195 kill(getpid(), SIGTERM); 196 return 0; 197 } 198 199 int 200 privsep_init(void) 201 { 202 long sc; 203 pid_t child_pid; 204 205 /* If running as root, we don't use the privsep code path */ 206 if (lcconf->uid == 0) 207 return 0; 208 209 /* 210 * When running privsep, certificate and script paths 211 * are mandatory, as they enable us to check path safety 212 * in the privileged instance 213 */ 214 if ((lcconf->pathinfo[LC_PATHTYPE_CERT] == NULL) || 215 (lcconf->pathinfo[LC_PATHTYPE_SCRIPT] == NULL)) { 216 plog(LLV_ERROR, LOCATION, NULL, "privilege separation " 217 "require path cert and path script in the config file\n"); 218 return -1; 219 } 220 221 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, privsep_sock) != 0) { 222 plog(LLV_ERROR, LOCATION, NULL, 223 "Cannot allocate privsep_sock: %s\n", strerror(errno)); 224 return -1; 225 } 226 227 switch (child_pid = fork()) { 228 case -1: 229 plog(LLV_ERROR, LOCATION, NULL, "Cannot fork privsep: %s\n", 230 strerror(errno)); 231 return -1; 232 233 case 0: /* Child: drop privileges */ 234 (void)close(privsep_sock[0]); 235 236 if (lcconf->chroot != NULL) { 237 if (chdir(lcconf->chroot) != 0) { 238 plog(LLV_ERROR, LOCATION, NULL, 239 "Cannot chdir(%s): %s\n", lcconf->chroot, 240 strerror(errno)); 241 return -1; 242 } 243 if (chroot(lcconf->chroot) != 0) { 244 plog(LLV_ERROR, LOCATION, NULL, 245 "Cannot chroot(%s): %s\n", lcconf->chroot, 246 strerror(errno)); 247 return -1; 248 } 249 } 250 251 if (setgid(lcconf->gid) != 0) { 252 plog(LLV_ERROR, LOCATION, NULL, 253 "Cannot setgid(%d): %s\n", lcconf->gid, 254 strerror(errno)); 255 return -1; 256 } 257 258 if (setegid(lcconf->gid) != 0) { 259 plog(LLV_ERROR, LOCATION, NULL, 260 "Cannot setegid(%d): %s\n", lcconf->gid, 261 strerror(errno)); 262 return -1; 263 } 264 265 if (setuid(lcconf->uid) != 0) { 266 plog(LLV_ERROR, LOCATION, NULL, 267 "Cannot setuid(%d): %s\n", lcconf->uid, 268 strerror(errno)); 269 return -1; 270 } 271 272 if (seteuid(lcconf->uid) != 0) { 273 plog(LLV_ERROR, LOCATION, NULL, 274 "Cannot seteuid(%d): %s\n", lcconf->uid, 275 strerror(errno)); 276 return -1; 277 } 278 monitor_fd(privsep_sock[1], privsep_do_exit, NULL, 0); 279 280 return 0; 281 282 default: /* Parent: privileged process */ 283 break; 284 } 285 286 /* 287 * Close everything except the socketpair, 288 * and stdout if running in the forground. 289 */ 290 for (sc = sysconf(_SC_OPEN_MAX); sc > 0; sc--) { 291 if (sc == privsep_sock[0]) 292 continue; 293 if ((f_foreground) && (sc == 1)) 294 continue; 295 (void)close((int)sc); 296 } 297 298 /* Above trickery closed the log file, reopen it */ 299 ploginit(); 300 301 plog(LLV_INFO, LOCATION, NULL, 302 "racoon privileged process running with PID %d\n", getpid()); 303 304 plog(LLV_INFO, LOCATION, NULL, 305 "racoon unprivileged process running with PID %d\n", child_pid); 306 307 #if defined(__NetBSD__) || defined(__FreeBSD__) 308 setproctitle("[priv]"); 309 #endif 310 311 /* 312 * Don't catch any signal 313 * This duplicate session:signals[], which is static... 314 */ 315 signal(SIGPIPE, SIG_IGN); 316 signal(SIGHUP, SIG_DFL); 317 signal(SIGINT, SIG_DFL); 318 signal(SIGTERM, SIG_DFL); 319 signal(SIGUSR1, SIG_DFL); 320 signal(SIGUSR2, SIG_DFL); 321 signal(SIGCHLD, SIG_DFL); 322 323 for (;;) { 324 size_t len; 325 struct privsep_com_msg *combuf; 326 struct privsep_com_msg *reply; 327 char *data; 328 size_t totallen; 329 char *bufs[PRIVSEP_NBUF_MAX]; 330 int i; 331 332 if (privsep_recv(privsep_sock[0], &combuf, &len) != 0) 333 goto out; 334 335 /* Safety checks and gather the data */ 336 if (len < sizeof(*combuf)) { 337 plog(LLV_ERROR, LOCATION, NULL, 338 "corrupted privsep message (short buflen)\n"); 339 goto out; 340 } 341 342 data = (char *)(combuf + 1); 343 totallen = sizeof(*combuf); 344 for (i = 0; i < PRIVSEP_NBUF_MAX; i++) { 345 bufs[i] = (char *)data; 346 data += combuf->bufs.buflen[i]; 347 totallen += combuf->bufs.buflen[i]; 348 } 349 350 if (totallen > len) { 351 plog(LLV_ERROR, LOCATION, NULL, 352 "corrupted privsep message (bufs too big)\n"); 353 goto out; 354 } 355 356 /* Prepare the reply buffer */ 357 if ((reply = racoon_malloc(sizeof(*reply))) == NULL) { 358 plog(LLV_ERROR, LOCATION, NULL, 359 "Cannot allocate reply buffer: %s\n", 360 strerror(errno)); 361 goto out; 362 } 363 bzero(reply, sizeof(*reply)); 364 reply->hdr.ac_cmd = combuf->hdr.ac_cmd; 365 reply->hdr.ac_len = sizeof(*reply); 366 367 switch(combuf->hdr.ac_cmd) { 368 /* 369 * XXX Improvement: instead of returning the key, 370 * stuff eay_get_pkcs1privkey and eay_get_x509sign 371 * together and sign the hash in the privileged 372 * instance? 373 * pro: the key remains inaccessible to unpriv 374 * con: a compromised unpriv racoon can still sign anything 375 */ 376 case PRIVSEP_EAY_GET_PKCS1PRIVKEY: { 377 vchar_t *privkey; 378 379 /* Make sure the string is NULL terminated */ 380 if (safety_check(combuf, 0) != 0) 381 break; 382 bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; 383 384 if (unsafe_path(bufs[0], LC_PATHTYPE_CERT) != 0) { 385 plog(LLV_ERROR, LOCATION, NULL, 386 "privsep_eay_get_pkcs1privkey: " 387 "unsafe cert \"%s\"\n", bufs[0]); 388 } 389 390 plog(LLV_DEBUG, LOCATION, NULL, 391 "eay_get_pkcs1privkey(\"%s\")\n", bufs[0]); 392 393 if ((privkey = eay_get_pkcs1privkey(bufs[0])) == NULL){ 394 reply->hdr.ac_errno = errno; 395 break; 396 } 397 398 reply->bufs.buflen[0] = privkey->l; 399 reply->hdr.ac_len = sizeof(*reply) + privkey->l; 400 reply = racoon_realloc(reply, reply->hdr.ac_len); 401 if (reply == NULL) { 402 plog(LLV_ERROR, LOCATION, NULL, 403 "Cannot allocate reply buffer: %s\n", 404 strerror(errno)); 405 goto out; 406 } 407 408 memcpy(reply + 1, privkey->v, privkey->l); 409 vfree(privkey); 410 break; 411 } 412 413 case PRIVSEP_SCRIPT_EXEC: { 414 char *script; 415 int name; 416 char **envp = NULL; 417 int envc = 0; 418 int count = 0; 419 int j; 420 421 /* 422 * First count the bufs, and make sure strings 423 * are NULL terminated. 424 * 425 * We expect: script, name, envp[], void 426 */ 427 if (safety_check(combuf, 0) != 0) 428 break; 429 bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; 430 count++; /* script */ 431 432 count++; /* name */ 433 434 for (; count < PRIVSEP_NBUF_MAX; count++) { 435 if (combuf->bufs.buflen[count] == 0) 436 break; 437 bufs[count] 438 [combuf->bufs.buflen[count] - 1] = '\0'; 439 envc++; 440 } 441 442 /* count a void buf and perform safety check */ 443 count++; 444 if (count >= PRIVSEP_NBUF_MAX) { 445 plog(LLV_ERROR, LOCATION, NULL, 446 "privsep_script_exec: too many args\n"); 447 goto out; 448 } 449 450 451 /* 452 * Allocate the arrays for envp 453 */ 454 envp = racoon_malloc((envc + 1) * sizeof(char *)); 455 if (envp == NULL) { 456 plog(LLV_ERROR, LOCATION, NULL, 457 "cannot allocate memory: %s\n", 458 strerror(errno)); 459 goto out; 460 } 461 bzero(envp, (envc + 1) * sizeof(char *)); 462 463 464 /* 465 * Populate script, name and envp 466 */ 467 count = 0; 468 script = bufs[count++]; 469 470 if (combuf->bufs.buflen[count] != sizeof(name)) { 471 plog(LLV_ERROR, LOCATION, NULL, 472 "privsep_script_exec: corrupted message\n"); 473 goto out; 474 } 475 memcpy((char *)&name, bufs[count++], sizeof(name)); 476 477 for (j = 0; combuf->bufs.buflen[count]; count++) 478 envp[j++] = bufs[count]; 479 480 count++; /* void */ 481 482 plog(LLV_DEBUG, LOCATION, NULL, 483 "script_exec(\"%s\", %d, %p)\n", 484 script, name, envp); 485 486 /* 487 * Check env for dangerous variables 488 * Check script path and name 489 * Perform fork and execve 490 */ 491 if ((unsafe_env(envp) == 0) && 492 (unknown_name(name) == 0) && 493 (unsafe_path(script, LC_PATHTYPE_SCRIPT) == 0)) 494 (void)script_exec(script, name, envp); 495 else 496 plog(LLV_ERROR, LOCATION, NULL, 497 "privsep_script_exec: " 498 "unsafe script \"%s\"\n", script); 499 500 racoon_free(envp); 501 break; 502 } 503 504 case PRIVSEP_GETPSK: { 505 vchar_t *psk; 506 int keylen; 507 508 /* Make sure the string is NULL terminated */ 509 if (safety_check(combuf, 0) != 0) 510 break; 511 bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; 512 513 if (combuf->bufs.buflen[1] != sizeof(keylen)) { 514 plog(LLV_ERROR, LOCATION, NULL, 515 "privsep_getpsk: corrupted message\n"); 516 goto out; 517 } 518 memcpy(&keylen, bufs[1], sizeof(keylen)); 519 520 plog(LLV_DEBUG, LOCATION, NULL, 521 "getpsk(\"%s\", %d)\n", bufs[0], keylen); 522 523 if ((psk = getpsk(bufs[0], keylen)) == NULL) { 524 reply->hdr.ac_errno = errno; 525 break; 526 } 527 528 reply->bufs.buflen[0] = psk->l; 529 reply->hdr.ac_len = sizeof(*reply) + psk->l; 530 reply = racoon_realloc(reply, reply->hdr.ac_len); 531 if (reply == NULL) { 532 plog(LLV_ERROR, LOCATION, NULL, 533 "Cannot allocate reply buffer: %s\n", 534 strerror(errno)); 535 goto out; 536 } 537 538 memcpy(reply + 1, psk->v, psk->l); 539 vfree(psk); 540 break; 541 } 542 543 case PRIVSEP_SOCKET: { 544 struct socket_args socket_args; 545 int s; 546 547 /* Make sure the string is NULL terminated */ 548 if (safety_check(combuf, 0) != 0) 549 break; 550 551 if (combuf->bufs.buflen[0] != 552 sizeof(struct socket_args)) { 553 plog(LLV_ERROR, LOCATION, NULL, 554 "privsep_socket: corrupted message\n"); 555 goto out; 556 } 557 memcpy(&socket_args, bufs[0], 558 sizeof(struct socket_args)); 559 560 if (socket_args.domain != PF_INET && 561 socket_args.domain != PF_INET6) { 562 plog(LLV_ERROR, LOCATION, NULL, 563 "privsep_socket: " 564 "unauthorized domain (%d)\n", 565 socket_args.domain); 566 goto out; 567 } 568 569 if ((s = socket(socket_args.domain, socket_args.type, 570 socket_args.protocol)) == -1) { 571 reply->hdr.ac_errno = errno; 572 break; 573 } 574 575 if (send_fd(privsep_sock[0], s) < 0) { 576 plog(LLV_ERROR, LOCATION, NULL, 577 "privsep_socket: send_fd failed\n"); 578 close(s); 579 goto out; 580 } 581 582 close(s); 583 break; 584 } 585 586 case PRIVSEP_BIND: { 587 struct bind_args bind_args; 588 int err, port = 0; 589 590 /* Make sure the string is NULL terminated */ 591 if (safety_check(combuf, 0) != 0) 592 break; 593 594 if (combuf->bufs.buflen[0] != 595 sizeof(struct bind_args)) { 596 plog(LLV_ERROR, LOCATION, NULL, 597 "privsep_bind: corrupted message\n"); 598 goto out; 599 } 600 memcpy(&bind_args, bufs[0], sizeof(struct bind_args)); 601 602 if (combuf->bufs.buflen[1] != bind_args.addrlen) { 603 plog(LLV_ERROR, LOCATION, NULL, 604 "privsep_bind: corrupted message\n"); 605 goto out; 606 } 607 bind_args.addr = (const struct sockaddr *)bufs[1]; 608 609 if ((bind_args.s = rec_fd(privsep_sock[0])) < 0) { 610 plog(LLV_ERROR, LOCATION, NULL, 611 "privsep_bind: rec_fd failed\n"); 612 goto out; 613 } 614 615 port = extract_port(bind_args.addr); 616 if (port != PORT_ISAKMP && port != PORT_ISAKMP_NATT && 617 port != lcconf->port_isakmp && 618 port != lcconf->port_isakmp_natt) { 619 plog(LLV_ERROR, LOCATION, NULL, 620 "privsep_bind: " 621 "unauthorized port (%d)\n", 622 port); 623 close(bind_args.s); 624 goto out; 625 } 626 627 err = bind(bind_args.s, bind_args.addr, 628 bind_args.addrlen); 629 630 if (err) 631 reply->hdr.ac_errno = errno; 632 633 close(bind_args.s); 634 break; 635 } 636 637 case PRIVSEP_SETSOCKOPTS: { 638 struct sockopt_args sockopt_args; 639 int err; 640 641 /* Make sure the string is NULL terminated */ 642 if (safety_check(combuf, 0) != 0) 643 break; 644 645 if (combuf->bufs.buflen[0] != 646 sizeof(struct sockopt_args)) { 647 plog(LLV_ERROR, LOCATION, NULL, 648 "privsep_setsockopt: " 649 "corrupted message\n"); 650 goto out; 651 } 652 memcpy(&sockopt_args, bufs[0], 653 sizeof(struct sockopt_args)); 654 655 if (combuf->bufs.buflen[1] != sockopt_args.optlen) { 656 plog(LLV_ERROR, LOCATION, NULL, 657 "privsep_setsockopt: corrupted message\n"); 658 goto out; 659 } 660 sockopt_args.optval = bufs[1]; 661 662 if (sockopt_args.optname != 663 (sockopt_args.level == 664 IPPROTO_IP ? IP_IPSEC_POLICY : 665 IPV6_IPSEC_POLICY)) { 666 plog(LLV_ERROR, LOCATION, NULL, 667 "privsep_setsockopt: " 668 "unauthorized option (%d)\n", 669 sockopt_args.optname); 670 goto out; 671 } 672 673 if ((sockopt_args.s = rec_fd(privsep_sock[0])) < 0) { 674 plog(LLV_ERROR, LOCATION, NULL, 675 "privsep_setsockopt: rec_fd failed\n"); 676 goto out; 677 } 678 679 err = setsockopt(sockopt_args.s, 680 sockopt_args.level, 681 sockopt_args.optname, 682 sockopt_args.optval, 683 sockopt_args.optlen); 684 if (err) 685 reply->hdr.ac_errno = errno; 686 687 close(sockopt_args.s); 688 break; 689 } 690 691 #ifdef ENABLE_HYBRID 692 case PRIVSEP_ACCOUNTING_SYSTEM: { 693 int port; 694 int inout; 695 struct sockaddr *raddr; 696 697 if (safety_check(combuf, 0) != 0) 698 break; 699 if (safety_check(combuf, 1) != 0) 700 break; 701 if (safety_check(combuf, 2) != 0) 702 break; 703 if (safety_check(combuf, 3) != 0) 704 break; 705 706 memcpy(&port, bufs[0], sizeof(port)); 707 raddr = (struct sockaddr *)bufs[1]; 708 709 bufs[2][combuf->bufs.buflen[2] - 1] = '\0'; 710 memcpy(&inout, bufs[3], sizeof(port)); 711 712 if (port_check(port) != 0) 713 break; 714 715 plog(LLV_DEBUG, LOCATION, NULL, 716 "accounting_system(%d, %s, %s)\n", 717 port, saddr2str(raddr), bufs[2]); 718 719 errno = 0; 720 if (isakmp_cfg_accounting_system(port, 721 raddr, bufs[2], inout) != 0) { 722 if (errno == 0) 723 reply->hdr.ac_errno = EINVAL; 724 else 725 reply->hdr.ac_errno = errno; 726 } 727 break; 728 } 729 case PRIVSEP_XAUTH_LOGIN_SYSTEM: { 730 if (safety_check(combuf, 0) != 0) 731 break; 732 bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; 733 734 if (safety_check(combuf, 1) != 0) 735 break; 736 bufs[1][combuf->bufs.buflen[1] - 1] = '\0'; 737 738 plog(LLV_DEBUG, LOCATION, NULL, 739 "xauth_login_system(\"%s\", <password>)\n", 740 bufs[0]); 741 742 errno = 0; 743 if (xauth_login_system(bufs[0], bufs[1]) != 0) { 744 if (errno == 0) 745 reply->hdr.ac_errno = EINVAL; 746 else 747 reply->hdr.ac_errno = errno; 748 } 749 break; 750 } 751 #ifdef HAVE_LIBPAM 752 case PRIVSEP_ACCOUNTING_PAM: { 753 int port; 754 int inout; 755 int pool_size; 756 757 if (safety_check(combuf, 0) != 0) 758 break; 759 if (safety_check(combuf, 1) != 0) 760 break; 761 if (safety_check(combuf, 2) != 0) 762 break; 763 764 memcpy(&port, bufs[0], sizeof(port)); 765 memcpy(&inout, bufs[1], sizeof(inout)); 766 memcpy(&pool_size, bufs[2], sizeof(pool_size)); 767 768 if (pool_size != isakmp_cfg_config.pool_size) 769 if (isakmp_cfg_resize_pool(pool_size) != 0) 770 break; 771 772 if (port_check(port) != 0) 773 break; 774 775 plog(LLV_DEBUG, LOCATION, NULL, 776 "isakmp_cfg_accounting_pam(%d, %d)\n", 777 port, inout); 778 779 errno = 0; 780 if (isakmp_cfg_accounting_pam(port, inout) != 0) { 781 if (errno == 0) 782 reply->hdr.ac_errno = EINVAL; 783 else 784 reply->hdr.ac_errno = errno; 785 } 786 break; 787 } 788 789 case PRIVSEP_XAUTH_LOGIN_PAM: { 790 int port; 791 int pool_size; 792 struct sockaddr *raddr; 793 794 if (safety_check(combuf, 0) != 0) 795 break; 796 if (safety_check(combuf, 1) != 0) 797 break; 798 if (safety_check(combuf, 2) != 0) 799 break; 800 if (safety_check(combuf, 3) != 0) 801 break; 802 if (safety_check(combuf, 4) != 0) 803 break; 804 805 memcpy(&port, bufs[0], sizeof(port)); 806 memcpy(&pool_size, bufs[1], sizeof(pool_size)); 807 raddr = (struct sockaddr *)bufs[2]; 808 809 bufs[3][combuf->bufs.buflen[3] - 1] = '\0'; 810 bufs[4][combuf->bufs.buflen[4] - 1] = '\0'; 811 812 if (pool_size != isakmp_cfg_config.pool_size) 813 if (isakmp_cfg_resize_pool(pool_size) != 0) 814 break; 815 816 if (port_check(port) != 0) 817 break; 818 819 plog(LLV_DEBUG, LOCATION, NULL, 820 "xauth_login_pam(%d, %s, \"%s\", <password>)\n", 821 port, saddr2str(raddr), bufs[3]); 822 823 errno = 0; 824 if (xauth_login_pam(port, 825 raddr, bufs[3], bufs[4]) != 0) { 826 if (errno == 0) 827 reply->hdr.ac_errno = EINVAL; 828 else 829 reply->hdr.ac_errno = errno; 830 } 831 break; 832 } 833 834 case PRIVSEP_CLEANUP_PAM: { 835 int port; 836 int pool_size; 837 838 if (safety_check(combuf, 0) != 0) 839 break; 840 if (safety_check(combuf, 1) != 0) 841 break; 842 843 memcpy(&port, bufs[0], sizeof(port)); 844 memcpy(&pool_size, bufs[1], sizeof(pool_size)); 845 846 if (pool_size != isakmp_cfg_config.pool_size) 847 if (isakmp_cfg_resize_pool(pool_size) != 0) 848 break; 849 850 if (port_check(port) != 0) 851 break; 852 853 plog(LLV_DEBUG, LOCATION, NULL, 854 "cleanup_pam(%d)\n", port); 855 856 cleanup_pam(port); 857 reply->hdr.ac_errno = 0; 858 859 break; 860 } 861 #endif /* HAVE_LIBPAM */ 862 #endif /* ENABLE_HYBRID */ 863 864 default: 865 plog(LLV_ERROR, LOCATION, NULL, 866 "unexpected privsep command %d\n", 867 combuf->hdr.ac_cmd); 868 goto out; 869 } 870 871 /* This frees reply */ 872 if (privsep_send(privsep_sock[0], 873 reply, reply->hdr.ac_len) != 0) { 874 racoon_free(reply); 875 goto out; 876 } 877 878 racoon_free(combuf); 879 } 880 881 out: 882 plog(LLV_INFO, LOCATION, NULL, 883 "racoon privileged process %d terminated\n", getpid()); 884 _exit(0); 885 } 886 887 888 vchar_t * 889 privsep_eay_get_pkcs1privkey(char *path) 890 { 891 vchar_t *privkey; 892 struct privsep_com_msg *msg; 893 size_t len; 894 895 if (geteuid() == 0) 896 return eay_get_pkcs1privkey(path); 897 898 len = sizeof(*msg) + strlen(path) + 1; 899 if ((msg = racoon_malloc(len)) == NULL) { 900 plog(LLV_ERROR, LOCATION, NULL, 901 "Cannot allocate memory: %s\n", strerror(errno)); 902 return NULL; 903 } 904 bzero(msg, len); 905 msg->hdr.ac_cmd = PRIVSEP_EAY_GET_PKCS1PRIVKEY; 906 msg->hdr.ac_len = len; 907 msg->bufs.buflen[0] = len - sizeof(*msg); 908 memcpy(msg + 1, path, msg->bufs.buflen[0]); 909 910 if (privsep_send(privsep_sock[1], msg, len) != 0) 911 goto out; 912 913 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 914 return NULL; 915 916 if (msg->hdr.ac_errno != 0) { 917 errno = msg->hdr.ac_errno; 918 goto out; 919 } 920 921 if ((privkey = vmalloc(len - sizeof(*msg))) == NULL) 922 goto out; 923 924 memcpy(privkey->v, msg + 1, privkey->l); 925 racoon_free(msg); 926 return privkey; 927 928 out: 929 racoon_free(msg); 930 return NULL; 931 } 932 933 int 934 privsep_script_exec(char *script, int name, char *const envp[]) 935 { 936 int count = 0; 937 char *const *c; 938 char *data; 939 size_t len; 940 struct privsep_com_msg *msg; 941 942 if (geteuid() == 0) 943 return script_exec(script, name, envp); 944 945 if ((msg = racoon_malloc(sizeof(*msg))) == NULL) { 946 plog(LLV_ERROR, LOCATION, NULL, 947 "Cannot allocate memory: %s\n", strerror(errno)); 948 return -1; 949 } 950 951 bzero(msg, sizeof(*msg)); 952 msg->hdr.ac_cmd = PRIVSEP_SCRIPT_EXEC; 953 msg->hdr.ac_len = sizeof(*msg); 954 955 /* 956 * We send: 957 * script, name, envp[0], ... envp[N], void 958 */ 959 960 /* 961 * Safety check on the counts: PRIVSEP_NBUF_MAX max 962 */ 963 count = 0; 964 count++; /* script */ 965 count++; /* name */ 966 for (c = envp; *c; c++) /* envp */ 967 count++; 968 count++; /* void */ 969 970 if (count > PRIVSEP_NBUF_MAX) { 971 plog(LLV_ERROR, LOCATION, NULL, "Unexpected error: " 972 "privsep_script_exec count > PRIVSEP_NBUF_MAX\n"); 973 racoon_free(msg); 974 return -1; 975 } 976 977 978 /* 979 * Compute the length 980 */ 981 count = 0; 982 msg->bufs.buflen[count] = strlen(script) + 1; /* script */ 983 msg->hdr.ac_len += msg->bufs.buflen[count++]; 984 985 msg->bufs.buflen[count] = sizeof(name); /* name */ 986 msg->hdr.ac_len += msg->bufs.buflen[count++]; 987 988 for (c = envp; *c; c++) { /* envp */ 989 msg->bufs.buflen[count] = strlen(*c) + 1; 990 msg->hdr.ac_len += msg->bufs.buflen[count++]; 991 } 992 993 msg->bufs.buflen[count] = 0; /* void */ 994 msg->hdr.ac_len += msg->bufs.buflen[count++]; 995 996 if ((msg = racoon_realloc(msg, msg->hdr.ac_len)) == NULL) { 997 plog(LLV_ERROR, LOCATION, NULL, 998 "Cannot allocate memory: %s\n", strerror(errno)); 999 return -1; 1000 } 1001 1002 /* 1003 * Now copy the data 1004 */ 1005 data = (char *)(msg + 1); 1006 count = 0; 1007 1008 memcpy(data, (char *)script, msg->bufs.buflen[count]); /* script */ 1009 data += msg->bufs.buflen[count++]; 1010 1011 memcpy(data, (char *)&name, msg->bufs.buflen[count]); /* name */ 1012 data += msg->bufs.buflen[count++]; 1013 1014 for (c = envp; *c; c++) { /* envp */ 1015 memcpy(data, *c, msg->bufs.buflen[count]); 1016 data += msg->bufs.buflen[count++]; 1017 } 1018 1019 count++; /* void */ 1020 1021 /* 1022 * And send it! 1023 */ 1024 if (privsep_send(privsep_sock[1], msg, msg->hdr.ac_len) != 0) 1025 goto out; 1026 1027 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1028 return -1; 1029 1030 if (msg->hdr.ac_errno != 0) { 1031 errno = msg->hdr.ac_errno; 1032 out: 1033 racoon_free(msg); 1034 return -1; 1035 } 1036 1037 racoon_free(msg); 1038 return 0; 1039 } 1040 1041 vchar_t * 1042 privsep_getpsk(const char *str, int keylen) 1043 { 1044 vchar_t *psk; 1045 struct privsep_com_msg *msg; 1046 size_t len; 1047 char *data; 1048 1049 if (geteuid() == 0) 1050 return getpsk(str, keylen); 1051 1052 len = sizeof(*msg) + strlen(str) + 1 + sizeof(keylen); 1053 if ((msg = racoon_malloc(len)) == NULL) { 1054 plog(LLV_ERROR, LOCATION, NULL, 1055 "Cannot allocate memory: %s\n", strerror(errno)); 1056 return NULL; 1057 } 1058 bzero(msg, len); 1059 msg->hdr.ac_cmd = PRIVSEP_GETPSK; 1060 msg->hdr.ac_len = len; 1061 1062 data = (char *)(msg + 1); 1063 msg->bufs.buflen[0] = strlen(str) + 1; 1064 memcpy(data, str, msg->bufs.buflen[0]); 1065 1066 data += msg->bufs.buflen[0]; 1067 msg->bufs.buflen[1] = sizeof(keylen); 1068 memcpy(data, &keylen, sizeof(keylen)); 1069 1070 if (privsep_send(privsep_sock[1], msg, len) != 0) 1071 goto out; 1072 1073 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1074 return NULL; 1075 1076 if (msg->hdr.ac_errno != 0) { 1077 errno = msg->hdr.ac_errno; 1078 goto out; 1079 } 1080 1081 if ((psk = vmalloc(len - sizeof(*msg))) == NULL) 1082 goto out; 1083 1084 memcpy(psk->v, msg + 1, psk->l); 1085 racoon_free(msg); 1086 return psk; 1087 1088 out: 1089 racoon_free(msg); 1090 return NULL; 1091 } 1092 1093 /* 1094 * Create a privileged socket. On BSD systems a socket obtains special 1095 * capabilities if it is created by root; setsockopt(IP_IPSEC_POLICY) will 1096 * succeed but will be ineffective if performed on an unprivileged socket. 1097 */ 1098 int 1099 privsep_socket(int domain, int type, int protocol) 1100 { 1101 struct privsep_com_msg *msg; 1102 size_t len; 1103 char *data; 1104 struct socket_args socket_args; 1105 int s; 1106 1107 if (geteuid() == 0) 1108 return socket(domain, type, protocol); 1109 1110 len = sizeof(*msg) + sizeof(socket_args); 1111 1112 if ((msg = racoon_malloc(len)) == NULL) { 1113 plog(LLV_ERROR, LOCATION, NULL, 1114 "Cannot allocate memory: %s\n", strerror(errno)); 1115 return -1; 1116 } 1117 bzero(msg, len); 1118 msg->hdr.ac_cmd = PRIVSEP_SOCKET; 1119 msg->hdr.ac_len = len; 1120 1121 socket_args.domain = domain; 1122 socket_args.type = type; 1123 socket_args.protocol = protocol; 1124 1125 data = (char *)(msg + 1); 1126 msg->bufs.buflen[0] = sizeof(socket_args); 1127 memcpy(data, &socket_args, msg->bufs.buflen[0]); 1128 1129 /* frees msg */ 1130 if (privsep_send(privsep_sock[1], msg, len) != 0) 1131 goto out; 1132 1133 /* Get the privileged socket descriptor from the privileged process. */ 1134 if ((s = rec_fd(privsep_sock[1])) == -1) 1135 return -1; 1136 1137 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1138 goto out; 1139 1140 if (msg->hdr.ac_errno != 0) { 1141 errno = msg->hdr.ac_errno; 1142 goto out; 1143 } 1144 1145 racoon_free(msg); 1146 return s; 1147 1148 out: 1149 racoon_free(msg); 1150 return -1; 1151 } 1152 1153 /* 1154 * Bind() a socket to a port. This works just like regular bind(), except that 1155 * if you want to bind to the designated isakmp ports and you don't have the 1156 * privilege to do so, it will ask a privileged process to do it. 1157 */ 1158 int 1159 privsep_bind(int s, const struct sockaddr *addr, socklen_t addrlen) 1160 { 1161 struct privsep_com_msg *msg; 1162 size_t len; 1163 char *data; 1164 struct bind_args bind_args; 1165 int err, saved_errno = 0; 1166 1167 err = bind(s, addr, addrlen); 1168 if ((err == 0) || (saved_errno = errno) != EACCES || geteuid() == 0) { 1169 if (saved_errno) 1170 plog(LLV_ERROR, LOCATION, NULL, 1171 "privsep_bind (%s) = %d\n", strerror(saved_errno), err); 1172 errno = saved_errno; 1173 return err; 1174 } 1175 1176 len = sizeof(*msg) + sizeof(bind_args) + addrlen; 1177 1178 if ((msg = racoon_malloc(len)) == NULL) { 1179 plog(LLV_ERROR, LOCATION, NULL, 1180 "Cannot allocate memory: %s\n", strerror(errno)); 1181 return -1; 1182 } 1183 bzero(msg, len); 1184 msg->hdr.ac_cmd = PRIVSEP_BIND; 1185 msg->hdr.ac_len = len; 1186 1187 bind_args.s = -1; 1188 bind_args.addr = NULL; 1189 bind_args.addrlen = addrlen; 1190 1191 data = (char *)(msg + 1); 1192 msg->bufs.buflen[0] = sizeof(bind_args); 1193 memcpy(data, &bind_args, msg->bufs.buflen[0]); 1194 1195 data += msg->bufs.buflen[0]; 1196 msg->bufs.buflen[1] = addrlen; 1197 memcpy(data, addr, addrlen); 1198 1199 /* frees msg */ 1200 if (privsep_send(privsep_sock[1], msg, len) != 0) 1201 goto out; 1202 1203 /* Send the socket descriptor to the privileged process. */ 1204 if (send_fd(privsep_sock[1], s) < 0) 1205 return -1; 1206 1207 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1208 goto out; 1209 1210 if (msg->hdr.ac_errno != 0) { 1211 errno = msg->hdr.ac_errno; 1212 goto out; 1213 } 1214 1215 racoon_free(msg); 1216 return 0; 1217 1218 out: 1219 racoon_free(msg); 1220 return -1; 1221 } 1222 1223 /* 1224 * Set socket options. This works just like regular setsockopt(), except that 1225 * if you want to change IP_IPSEC_POLICY or IPV6_IPSEC_POLICY and you don't 1226 * have the privilege to do so, it will ask a privileged process to do it. 1227 */ 1228 int 1229 privsep_setsockopt(int s, int level, int optname, const void *optval, 1230 socklen_t optlen) 1231 { 1232 struct privsep_com_msg *msg; 1233 size_t len; 1234 char *data; 1235 struct sockopt_args sockopt_args; 1236 int err, saved_errno = 0; 1237 1238 if ((err = setsockopt(s, level, optname, optval, optlen)) == 0 || 1239 (saved_errno = errno) != EACCES || 1240 geteuid() == 0) { 1241 if (saved_errno) 1242 plog(LLV_ERROR, LOCATION, NULL, 1243 "privsep_setsockopt (%s)\n", 1244 strerror(saved_errno)); 1245 1246 errno = saved_errno; 1247 return err; 1248 } 1249 1250 len = sizeof(*msg) + sizeof(sockopt_args) + optlen; 1251 1252 if ((msg = racoon_malloc(len)) == NULL) { 1253 plog(LLV_ERROR, LOCATION, NULL, 1254 "Cannot allocate memory: %s\n", strerror(errno)); 1255 return -1; 1256 } 1257 bzero(msg, len); 1258 msg->hdr.ac_cmd = PRIVSEP_SETSOCKOPTS; 1259 msg->hdr.ac_len = len; 1260 1261 sockopt_args.s = -1; 1262 sockopt_args.level = level; 1263 sockopt_args.optname = optname; 1264 sockopt_args.optval = NULL; 1265 sockopt_args.optlen = optlen; 1266 1267 data = (char *)(msg + 1); 1268 msg->bufs.buflen[0] = sizeof(sockopt_args); 1269 memcpy(data, &sockopt_args, msg->bufs.buflen[0]); 1270 1271 data += msg->bufs.buflen[0]; 1272 msg->bufs.buflen[1] = optlen; 1273 memcpy(data, optval, optlen); 1274 1275 /* frees msg */ 1276 if (privsep_send(privsep_sock[1], msg, len) != 0) 1277 goto out; 1278 1279 if (send_fd(privsep_sock[1], s) < 0) 1280 return -1; 1281 1282 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) { 1283 plog(LLV_ERROR, LOCATION, NULL, 1284 "privsep_recv failed\n"); 1285 goto out; 1286 } 1287 1288 if (msg->hdr.ac_errno != 0) { 1289 errno = msg->hdr.ac_errno; 1290 goto out; 1291 } 1292 1293 racoon_free(msg); 1294 return 0; 1295 1296 out: 1297 racoon_free(msg); 1298 return -1; 1299 } 1300 1301 #ifdef ENABLE_HYBRID 1302 int 1303 privsep_xauth_login_system(char *usr, char *pwd) 1304 { 1305 struct privsep_com_msg *msg; 1306 size_t len; 1307 char *data; 1308 1309 if (geteuid() == 0) 1310 return xauth_login_system(usr, pwd); 1311 1312 len = sizeof(*msg) + strlen(usr) + 1 + strlen(pwd) + 1; 1313 if ((msg = racoon_malloc(len)) == NULL) { 1314 plog(LLV_ERROR, LOCATION, NULL, 1315 "Cannot allocate memory: %s\n", strerror(errno)); 1316 return -1; 1317 } 1318 bzero(msg, len); 1319 msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_SYSTEM; 1320 msg->hdr.ac_len = len; 1321 1322 data = (char *)(msg + 1); 1323 msg->bufs.buflen[0] = strlen(usr) + 1; 1324 memcpy(data, usr, msg->bufs.buflen[0]); 1325 data += msg->bufs.buflen[0]; 1326 1327 msg->bufs.buflen[1] = strlen(pwd) + 1; 1328 memcpy(data, pwd, msg->bufs.buflen[1]); 1329 1330 /* frees msg */ 1331 if (privsep_send(privsep_sock[1], msg, len) != 0) 1332 goto out; 1333 1334 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1335 return -1; 1336 1337 if (msg->hdr.ac_errno != 0) { 1338 out: 1339 racoon_free(msg); 1340 return -1; 1341 } 1342 1343 racoon_free(msg); 1344 return 0; 1345 } 1346 1347 int 1348 privsep_accounting_system(int port, struct sockaddr *raddr, char *usr, 1349 int inout) 1350 { 1351 struct privsep_com_msg *msg; 1352 size_t len; 1353 char *data; 1354 1355 if (geteuid() == 0) 1356 return isakmp_cfg_accounting_system(port, raddr, 1357 usr, inout); 1358 1359 len = sizeof(*msg) 1360 + sizeof(port) 1361 + sysdep_sa_len(raddr) 1362 + strlen(usr) + 1 1363 + sizeof(inout); 1364 1365 if ((msg = racoon_malloc(len)) == NULL) { 1366 plog(LLV_ERROR, LOCATION, NULL, 1367 "Cannot allocate memory: %s\n", strerror(errno)); 1368 return -1; 1369 } 1370 bzero(msg, len); 1371 msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_SYSTEM; 1372 msg->hdr.ac_len = len; 1373 msg->bufs.buflen[0] = sizeof(port); 1374 msg->bufs.buflen[1] = sysdep_sa_len(raddr); 1375 msg->bufs.buflen[2] = strlen(usr) + 1; 1376 msg->bufs.buflen[3] = sizeof(inout); 1377 1378 data = (char *)(msg + 1); 1379 memcpy(data, &port, msg->bufs.buflen[0]); 1380 1381 data += msg->bufs.buflen[0]; 1382 memcpy(data, raddr, msg->bufs.buflen[1]); 1383 1384 data += msg->bufs.buflen[1]; 1385 memcpy(data, usr, msg->bufs.buflen[2]); 1386 1387 data += msg->bufs.buflen[2]; 1388 memcpy(data, &inout, msg->bufs.buflen[3]); 1389 1390 /* frees msg */ 1391 if (privsep_send(privsep_sock[1], msg, len) != 0) 1392 goto out; 1393 1394 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1395 return -1; 1396 1397 if (msg->hdr.ac_errno != 0) { 1398 errno = msg->hdr.ac_errno; 1399 goto out; 1400 } 1401 1402 racoon_free(msg); 1403 return 0; 1404 1405 out: 1406 racoon_free(msg); 1407 return -1; 1408 } 1409 1410 static int 1411 port_check(int port) 1412 { 1413 if ((port < 0) || (port >= isakmp_cfg_config.pool_size)) { 1414 plog(LLV_ERROR, LOCATION, NULL, 1415 "privsep: port %d outside of allowed range [0,%zu]\n", 1416 port, isakmp_cfg_config.pool_size - 1); 1417 return -1; 1418 } 1419 1420 return 0; 1421 } 1422 #endif 1423 1424 static int 1425 safety_check(struct privsep_com_msg *msg, int index) 1426 { 1427 if (index >= PRIVSEP_NBUF_MAX) { 1428 plog(LLV_ERROR, LOCATION, NULL, 1429 "privsep: Corrupted message, too many buffers\n"); 1430 return -1; 1431 } 1432 1433 if (msg->bufs.buflen[index] == 0) { 1434 plog(LLV_ERROR, LOCATION, NULL, 1435 "privsep: Corrupted message, unexpected void buffer\n"); 1436 return -1; 1437 } 1438 1439 return 0; 1440 } 1441 1442 /* 1443 * Filter unsafe environment variables 1444 */ 1445 static int 1446 unsafe_env(char *const *envp) 1447 { 1448 char *const *e; 1449 const char *const *be; 1450 const char *const bad_env[] = { "PATH=", "LD_LIBRARY_PATH=", "IFS=", NULL }; 1451 1452 for (e = envp; *e; e++) { 1453 for (be = bad_env; *be; be++) { 1454 if (strncmp(*e, *be, strlen(*be)) == 0) { 1455 goto found; 1456 } 1457 } 1458 } 1459 1460 return 0; 1461 found: 1462 plog(LLV_ERROR, LOCATION, NULL, 1463 "privsep_script_exec: unsafe environment variable\n"); 1464 return -1; 1465 } 1466 1467 /* 1468 * Check path safety 1469 */ 1470 static int 1471 unsafe_path(char *script, int pathtype) 1472 { 1473 char *path; 1474 char rpath[MAXPATHLEN + 1]; 1475 size_t len; 1476 1477 if (script == NULL) 1478 return -1; 1479 1480 path = lcconf->pathinfo[pathtype]; 1481 1482 /* No path was given for scripts: skip the check */ 1483 if (path == NULL) 1484 return 0; 1485 1486 if (realpath(script, rpath) == NULL) { 1487 plog(LLV_ERROR, LOCATION, NULL, 1488 "script path \"%s\" is invalid\n", script); 1489 return -1; 1490 } 1491 1492 len = strlen(path); 1493 if (strncmp(path, rpath, len) != 0) 1494 return -1; 1495 1496 return 0; 1497 } 1498 1499 static int 1500 unknown_name(int name) 1501 { 1502 if ((name < 0) || (name > SCRIPT_MAX)) { 1503 plog(LLV_ERROR, LOCATION, NULL, 1504 "privsep_script_exec: unsafe name index\n"); 1505 return -1; 1506 } 1507 1508 return 0; 1509 } 1510 1511 /* Receive a file descriptor through the argument socket */ 1512 static int 1513 rec_fd(int s) 1514 { 1515 struct msghdr msg; 1516 struct cmsghdr *cmsg; 1517 int *fdptr; 1518 char cmsbuf[1024]; 1519 struct iovec iov; 1520 char iobuf[1]; 1521 1522 iov.iov_base = iobuf; 1523 iov.iov_len = 1; 1524 1525 if (sizeof(cmsbuf) < CMSG_SPACE(sizeof(int))) { 1526 plog(LLV_ERROR, LOCATION, NULL, 1527 "send_fd: buffer size too small\n"); 1528 return -1; 1529 } 1530 bzero(&msg, sizeof(msg)); 1531 msg.msg_name = NULL; 1532 msg.msg_namelen = 0; 1533 msg.msg_iov = &iov; 1534 msg.msg_iovlen = 1; 1535 msg.msg_control = cmsbuf; 1536 msg.msg_controllen = CMSG_SPACE(sizeof(int)); 1537 1538 if (recvmsg(s, &msg, MSG_WAITALL) == -1) 1539 return -1; 1540 1541 cmsg = CMSG_FIRSTHDR(&msg); 1542 fdptr = (int *) CMSG_DATA(cmsg); 1543 return fdptr[0]; 1544 } 1545 1546 /* Send the file descriptor fd through the argument socket s */ 1547 static int 1548 send_fd(int s, int fd) 1549 { 1550 struct msghdr msg; 1551 struct cmsghdr *cmsg; 1552 char cmsbuf[1024]; 1553 struct iovec iov; 1554 int *fdptr; 1555 1556 iov.iov_base = __UNCONST(" "); 1557 iov.iov_len = 1; 1558 1559 if (sizeof(cmsbuf) < CMSG_SPACE(sizeof(fd))) { 1560 plog(LLV_ERROR, LOCATION, NULL, 1561 "send_fd: buffer size too small\n"); 1562 return -1; 1563 } 1564 bzero(&msg, sizeof(msg)); 1565 msg.msg_name = NULL; 1566 msg.msg_namelen = 0; 1567 msg.msg_iov = &iov; 1568 msg.msg_iovlen = 1; 1569 msg.msg_control = cmsbuf; 1570 msg.msg_controllen = CMSG_SPACE(sizeof(fd)); 1571 msg.msg_flags = 0; 1572 1573 cmsg = CMSG_FIRSTHDR(&msg); 1574 cmsg->cmsg_level = SOL_SOCKET; 1575 cmsg->cmsg_type = SCM_RIGHTS; 1576 cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); 1577 fdptr = (int *)CMSG_DATA(cmsg); 1578 fdptr[0] = fd; 1579 msg.msg_controllen = cmsg->cmsg_len; 1580 1581 if (sendmsg(s, &msg, 0) == -1) 1582 return -1; 1583 1584 return 0; 1585 } 1586 1587 #ifdef HAVE_LIBPAM 1588 int 1589 privsep_accounting_pam(int port, int inout) 1590 { 1591 struct privsep_com_msg *msg; 1592 size_t len; 1593 int *port_data; 1594 int *inout_data; 1595 int *pool_size_data; 1596 1597 if (geteuid() == 0) 1598 return isakmp_cfg_accounting_pam(port, inout); 1599 1600 len = sizeof(*msg) 1601 + sizeof(port) 1602 + sizeof(inout) 1603 + sizeof(isakmp_cfg_config.pool_size); 1604 1605 if ((msg = racoon_malloc(len)) == NULL) { 1606 plog(LLV_ERROR, LOCATION, NULL, 1607 "Cannot allocate memory: %s\n", strerror(errno)); 1608 return -1; 1609 } 1610 bzero(msg, len); 1611 msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_PAM; 1612 msg->hdr.ac_len = len; 1613 msg->bufs.buflen[0] = sizeof(port); 1614 msg->bufs.buflen[1] = sizeof(inout); 1615 msg->bufs.buflen[2] = sizeof(isakmp_cfg_config.pool_size); 1616 1617 port_data = (int *)(msg + 1); 1618 inout_data = (int *)(port_data + 1); 1619 pool_size_data = (int *)(inout_data + 1); 1620 1621 *port_data = port; 1622 *inout_data = inout; 1623 *pool_size_data = isakmp_cfg_config.pool_size; 1624 1625 /* frees msg */ 1626 if (privsep_send(privsep_sock[1], msg, len) != 0) 1627 goto out; 1628 1629 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1630 return -1; 1631 1632 if (msg->hdr.ac_errno != 0) { 1633 errno = msg->hdr.ac_errno; 1634 goto out; 1635 } 1636 1637 racoon_free(msg); 1638 return 0; 1639 1640 out: 1641 racoon_free(msg); 1642 return -1; 1643 } 1644 1645 int 1646 privsep_xauth_login_pam(int port, struct sockaddr *raddr, char *usr, char *pwd) 1647 { 1648 struct privsep_com_msg *msg; 1649 size_t len; 1650 char *data; 1651 1652 if (geteuid() == 0) 1653 return xauth_login_pam(port, raddr, usr, pwd); 1654 1655 len = sizeof(*msg) 1656 + sizeof(port) 1657 + sizeof(isakmp_cfg_config.pool_size) 1658 + sysdep_sa_len(raddr) 1659 + strlen(usr) + 1 1660 + strlen(pwd) + 1; 1661 1662 if ((msg = racoon_malloc(len)) == NULL) { 1663 plog(LLV_ERROR, LOCATION, NULL, 1664 "Cannot allocate memory: %s\n", strerror(errno)); 1665 return -1; 1666 } 1667 bzero(msg, len); 1668 msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_PAM; 1669 msg->hdr.ac_len = len; 1670 msg->bufs.buflen[0] = sizeof(port); 1671 msg->bufs.buflen[1] = sizeof(isakmp_cfg_config.pool_size); 1672 msg->bufs.buflen[2] = sysdep_sa_len(raddr); 1673 msg->bufs.buflen[3] = strlen(usr) + 1; 1674 msg->bufs.buflen[4] = strlen(pwd) + 1; 1675 1676 data = (char *)(msg + 1); 1677 memcpy(data, &port, msg->bufs.buflen[0]); 1678 1679 data += msg->bufs.buflen[0]; 1680 memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]); 1681 1682 data += msg->bufs.buflen[1]; 1683 memcpy(data, raddr, msg->bufs.buflen[2]); 1684 1685 data += msg->bufs.buflen[2]; 1686 memcpy(data, usr, msg->bufs.buflen[3]); 1687 1688 data += msg->bufs.buflen[3]; 1689 memcpy(data, pwd, msg->bufs.buflen[4]); 1690 1691 /* frees msg */ 1692 if (privsep_send(privsep_sock[1], msg, len) != 0) 1693 goto out; 1694 1695 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1696 return -1; 1697 1698 if (msg->hdr.ac_errno != 0) { 1699 errno = msg->hdr.ac_errno; 1700 goto out; 1701 } 1702 1703 racoon_free(msg); 1704 return 0; 1705 1706 out: 1707 racoon_free(msg); 1708 return -1; 1709 } 1710 1711 void 1712 privsep_cleanup_pam(int port) 1713 { 1714 struct privsep_com_msg *msg; 1715 size_t len; 1716 char *data; 1717 1718 if (geteuid() == 0) { 1719 cleanup_pam(port); 1720 return; 1721 } 1722 1723 len = sizeof(*msg) 1724 + sizeof(port) 1725 + sizeof(isakmp_cfg_config.pool_size); 1726 1727 if ((msg = racoon_malloc(len)) == NULL) { 1728 plog(LLV_ERROR, LOCATION, NULL, 1729 "Cannot allocate memory: %s\n", strerror(errno)); 1730 return; 1731 } 1732 bzero(msg, len); 1733 msg->hdr.ac_cmd = PRIVSEP_CLEANUP_PAM; 1734 msg->hdr.ac_len = len; 1735 msg->bufs.buflen[0] = sizeof(port); 1736 msg->bufs.buflen[1] = sizeof(isakmp_cfg_config.pool_size); 1737 1738 data = (char *)(msg + 1); 1739 memcpy(data, &port, msg->bufs.buflen[0]); 1740 1741 data += msg->bufs.buflen[0]; 1742 memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]); 1743 1744 /* frees msg */ 1745 if (privsep_send(privsep_sock[1], msg, len) != 0) 1746 goto out; 1747 1748 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1749 return; 1750 1751 if (msg->hdr.ac_errno != 0) 1752 errno = msg->hdr.ac_errno; 1753 1754 out: 1755 racoon_free(msg); 1756 return; 1757 } 1758 #endif 1759