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