1 /* $NetBSD: privsep.c,v 1.24 2018/05/19 19:23:15 maxv 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 return NULL; 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 return -1; 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 racoon_free(msg); 1045 return -1; 1046 } 1047 1048 racoon_free(msg); 1049 return 0; 1050 } 1051 1052 vchar_t * 1053 privsep_getpsk(str, keylen) 1054 const char *str; 1055 int keylen; 1056 { 1057 vchar_t *psk; 1058 struct privsep_com_msg *msg; 1059 size_t len; 1060 char *data; 1061 1062 if (geteuid() == 0) 1063 return getpsk(str, keylen); 1064 1065 len = sizeof(*msg) + strlen(str) + 1 + sizeof(keylen); 1066 if ((msg = racoon_malloc(len)) == NULL) { 1067 plog(LLV_ERROR, LOCATION, NULL, 1068 "Cannot allocate memory: %s\n", strerror(errno)); 1069 return NULL; 1070 } 1071 bzero(msg, len); 1072 msg->hdr.ac_cmd = PRIVSEP_GETPSK; 1073 msg->hdr.ac_len = len; 1074 1075 data = (char *)(msg + 1); 1076 msg->bufs.buflen[0] = strlen(str) + 1; 1077 memcpy(data, str, msg->bufs.buflen[0]); 1078 1079 data += msg->bufs.buflen[0]; 1080 msg->bufs.buflen[1] = sizeof(keylen); 1081 memcpy(data, &keylen, sizeof(keylen)); 1082 1083 if (privsep_send(privsep_sock[1], msg, len) != 0) 1084 return NULL; 1085 1086 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1087 return NULL; 1088 1089 if (msg->hdr.ac_errno != 0) { 1090 errno = msg->hdr.ac_errno; 1091 goto out; 1092 } 1093 1094 if ((psk = vmalloc(len - sizeof(*msg))) == NULL) 1095 goto out; 1096 1097 memcpy(psk->v, msg + 1, psk->l); 1098 racoon_free(msg); 1099 return psk; 1100 1101 out: 1102 racoon_free(msg); 1103 return NULL; 1104 } 1105 1106 /* 1107 * Create a privileged socket. On BSD systems a socket obtains special 1108 * capabilities if it is created by root; setsockopt(IP_IPSEC_POLICY) will 1109 * succeed but will be ineffective if performed on an unprivileged socket. 1110 */ 1111 int 1112 privsep_socket(domain, type, protocol) 1113 int domain; 1114 int type; 1115 int protocol; 1116 { 1117 struct privsep_com_msg *msg; 1118 size_t len; 1119 char *data; 1120 struct socket_args socket_args; 1121 int s; 1122 1123 if (geteuid() == 0) 1124 return socket(domain, type, protocol); 1125 1126 len = sizeof(*msg) + sizeof(socket_args); 1127 1128 if ((msg = racoon_malloc(len)) == NULL) { 1129 plog(LLV_ERROR, LOCATION, NULL, 1130 "Cannot allocate memory: %s\n", strerror(errno)); 1131 return -1; 1132 } 1133 bzero(msg, len); 1134 msg->hdr.ac_cmd = PRIVSEP_SOCKET; 1135 msg->hdr.ac_len = len; 1136 1137 socket_args.domain = domain; 1138 socket_args.type = type; 1139 socket_args.protocol = protocol; 1140 1141 data = (char *)(msg + 1); 1142 msg->bufs.buflen[0] = sizeof(socket_args); 1143 memcpy(data, &socket_args, msg->bufs.buflen[0]); 1144 1145 /* frees msg */ 1146 if (privsep_send(privsep_sock[1], msg, len) != 0) 1147 goto out; 1148 1149 /* Get the privileged socket descriptor from the privileged process. */ 1150 if ((s = rec_fd(privsep_sock[1])) == -1) 1151 return -1; 1152 1153 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1154 goto out; 1155 1156 if (msg->hdr.ac_errno != 0) { 1157 errno = msg->hdr.ac_errno; 1158 goto out; 1159 } 1160 1161 racoon_free(msg); 1162 return s; 1163 1164 out: 1165 racoon_free(msg); 1166 return -1; 1167 } 1168 1169 /* 1170 * Bind() a socket to a port. This works just like regular bind(), except that 1171 * if you want to bind to the designated isakmp ports and you don't have the 1172 * privilege to do so, it will ask a privileged process to do it. 1173 */ 1174 int 1175 privsep_bind(s, addr, addrlen) 1176 int s; 1177 const struct sockaddr *addr; 1178 socklen_t addrlen; 1179 { 1180 struct privsep_com_msg *msg; 1181 size_t len; 1182 char *data; 1183 struct bind_args bind_args; 1184 int err, saved_errno = 0; 1185 1186 err = bind(s, addr, addrlen); 1187 if ((err == 0) || (saved_errno = errno) != EACCES || geteuid() == 0) { 1188 if (saved_errno) 1189 plog(LLV_ERROR, LOCATION, NULL, 1190 "privsep_bind (%s) = %d\n", strerror(saved_errno), err); 1191 errno = saved_errno; 1192 return err; 1193 } 1194 1195 len = sizeof(*msg) + sizeof(bind_args) + addrlen; 1196 1197 if ((msg = racoon_malloc(len)) == NULL) { 1198 plog(LLV_ERROR, LOCATION, NULL, 1199 "Cannot allocate memory: %s\n", strerror(errno)); 1200 return -1; 1201 } 1202 bzero(msg, len); 1203 msg->hdr.ac_cmd = PRIVSEP_BIND; 1204 msg->hdr.ac_len = len; 1205 1206 bind_args.s = -1; 1207 bind_args.addr = NULL; 1208 bind_args.addrlen = addrlen; 1209 1210 data = (char *)(msg + 1); 1211 msg->bufs.buflen[0] = sizeof(bind_args); 1212 memcpy(data, &bind_args, msg->bufs.buflen[0]); 1213 1214 data += msg->bufs.buflen[0]; 1215 msg->bufs.buflen[1] = addrlen; 1216 memcpy(data, addr, addrlen); 1217 1218 /* frees msg */ 1219 if (privsep_send(privsep_sock[1], msg, len) != 0) 1220 goto out; 1221 1222 /* Send the socket descriptor to the privileged process. */ 1223 if (send_fd(privsep_sock[1], s) < 0) 1224 return -1; 1225 1226 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1227 goto out; 1228 1229 if (msg->hdr.ac_errno != 0) { 1230 errno = msg->hdr.ac_errno; 1231 goto out; 1232 } 1233 1234 racoon_free(msg); 1235 return 0; 1236 1237 out: 1238 racoon_free(msg); 1239 return -1; 1240 } 1241 1242 /* 1243 * Set socket options. This works just like regular setsockopt(), except that 1244 * if you want to change IP_IPSEC_POLICY or IPV6_IPSEC_POLICY and you don't 1245 * have the privilege to do so, it will ask a privileged process to do it. 1246 */ 1247 int 1248 privsep_setsockopt(s, level, optname, optval, optlen) 1249 int s; 1250 int level; 1251 int optname; 1252 const void *optval; 1253 socklen_t optlen; 1254 { 1255 struct privsep_com_msg *msg; 1256 size_t len; 1257 char *data; 1258 struct sockopt_args sockopt_args; 1259 int err, saved_errno = 0; 1260 1261 if ((err = setsockopt(s, level, optname, optval, optlen)) == 0 || 1262 (saved_errno = errno) != EACCES || 1263 geteuid() == 0) { 1264 if (saved_errno) 1265 plog(LLV_ERROR, LOCATION, NULL, 1266 "privsep_setsockopt (%s)\n", 1267 strerror(saved_errno)); 1268 1269 errno = saved_errno; 1270 return err; 1271 } 1272 1273 len = sizeof(*msg) + sizeof(sockopt_args) + optlen; 1274 1275 if ((msg = racoon_malloc(len)) == NULL) { 1276 plog(LLV_ERROR, LOCATION, NULL, 1277 "Cannot allocate memory: %s\n", strerror(errno)); 1278 return -1; 1279 } 1280 bzero(msg, len); 1281 msg->hdr.ac_cmd = PRIVSEP_SETSOCKOPTS; 1282 msg->hdr.ac_len = len; 1283 1284 sockopt_args.s = -1; 1285 sockopt_args.level = level; 1286 sockopt_args.optname = optname; 1287 sockopt_args.optval = NULL; 1288 sockopt_args.optlen = optlen; 1289 1290 data = (char *)(msg + 1); 1291 msg->bufs.buflen[0] = sizeof(sockopt_args); 1292 memcpy(data, &sockopt_args, msg->bufs.buflen[0]); 1293 1294 data += msg->bufs.buflen[0]; 1295 msg->bufs.buflen[1] = optlen; 1296 memcpy(data, optval, optlen); 1297 1298 /* frees msg */ 1299 if (privsep_send(privsep_sock[1], msg, len) != 0) 1300 goto out; 1301 1302 if (send_fd(privsep_sock[1], s) < 0) 1303 return -1; 1304 1305 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) { 1306 plog(LLV_ERROR, LOCATION, NULL, 1307 "privsep_recv failed\n"); 1308 goto out; 1309 } 1310 1311 if (msg->hdr.ac_errno != 0) { 1312 errno = msg->hdr.ac_errno; 1313 goto out; 1314 } 1315 1316 racoon_free(msg); 1317 return 0; 1318 1319 out: 1320 racoon_free(msg); 1321 return -1; 1322 } 1323 1324 #ifdef ENABLE_HYBRID 1325 int 1326 privsep_xauth_login_system(usr, pwd) 1327 char *usr; 1328 char *pwd; 1329 { 1330 struct privsep_com_msg *msg; 1331 size_t len; 1332 char *data; 1333 1334 if (geteuid() == 0) 1335 return xauth_login_system(usr, pwd); 1336 1337 len = sizeof(*msg) + strlen(usr) + 1 + strlen(pwd) + 1; 1338 if ((msg = racoon_malloc(len)) == NULL) { 1339 plog(LLV_ERROR, LOCATION, NULL, 1340 "Cannot allocate memory: %s\n", strerror(errno)); 1341 return -1; 1342 } 1343 bzero(msg, len); 1344 msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_SYSTEM; 1345 msg->hdr.ac_len = len; 1346 1347 data = (char *)(msg + 1); 1348 msg->bufs.buflen[0] = strlen(usr) + 1; 1349 memcpy(data, usr, msg->bufs.buflen[0]); 1350 data += msg->bufs.buflen[0]; 1351 1352 msg->bufs.buflen[1] = strlen(pwd) + 1; 1353 memcpy(data, pwd, msg->bufs.buflen[1]); 1354 1355 /* frees msg */ 1356 if (privsep_send(privsep_sock[1], msg, len) != 0) 1357 return -1; 1358 1359 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1360 return -1; 1361 1362 if (msg->hdr.ac_errno != 0) { 1363 racoon_free(msg); 1364 return -1; 1365 } 1366 1367 racoon_free(msg); 1368 return 0; 1369 } 1370 1371 int 1372 privsep_accounting_system(port, raddr, usr, inout) 1373 int port; 1374 struct sockaddr *raddr; 1375 char *usr; 1376 int inout; 1377 { 1378 struct privsep_com_msg *msg; 1379 size_t len; 1380 char *data; 1381 1382 if (geteuid() == 0) 1383 return isakmp_cfg_accounting_system(port, raddr, 1384 usr, inout); 1385 1386 len = sizeof(*msg) 1387 + sizeof(port) 1388 + sysdep_sa_len(raddr) 1389 + strlen(usr) + 1 1390 + sizeof(inout); 1391 1392 if ((msg = racoon_malloc(len)) == NULL) { 1393 plog(LLV_ERROR, LOCATION, NULL, 1394 "Cannot allocate memory: %s\n", strerror(errno)); 1395 return -1; 1396 } 1397 bzero(msg, len); 1398 msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_SYSTEM; 1399 msg->hdr.ac_len = len; 1400 msg->bufs.buflen[0] = sizeof(port); 1401 msg->bufs.buflen[1] = sysdep_sa_len(raddr); 1402 msg->bufs.buflen[2] = strlen(usr) + 1; 1403 msg->bufs.buflen[3] = sizeof(inout); 1404 1405 data = (char *)(msg + 1); 1406 memcpy(data, &port, msg->bufs.buflen[0]); 1407 1408 data += msg->bufs.buflen[0]; 1409 memcpy(data, raddr, msg->bufs.buflen[1]); 1410 1411 data += msg->bufs.buflen[1]; 1412 memcpy(data, usr, msg->bufs.buflen[2]); 1413 1414 data += msg->bufs.buflen[2]; 1415 memcpy(data, &inout, msg->bufs.buflen[3]); 1416 1417 /* frees msg */ 1418 if (privsep_send(privsep_sock[1], msg, len) != 0) 1419 return -1; 1420 1421 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1422 return -1; 1423 1424 if (msg->hdr.ac_errno != 0) { 1425 errno = msg->hdr.ac_errno; 1426 goto out; 1427 } 1428 1429 racoon_free(msg); 1430 return 0; 1431 1432 out: 1433 racoon_free(msg); 1434 return -1; 1435 } 1436 1437 static int 1438 port_check(port) 1439 int port; 1440 { 1441 if ((port < 0) || (port >= isakmp_cfg_config.pool_size)) { 1442 plog(LLV_ERROR, LOCATION, NULL, 1443 "privsep: port %d outside of allowed range [0,%zu]\n", 1444 port, isakmp_cfg_config.pool_size - 1); 1445 return -1; 1446 } 1447 1448 return 0; 1449 } 1450 #endif 1451 1452 static int 1453 safety_check(msg, index) 1454 struct privsep_com_msg *msg; 1455 int index; 1456 { 1457 if (index >= PRIVSEP_NBUF_MAX) { 1458 plog(LLV_ERROR, LOCATION, NULL, 1459 "privsep: Corrupted message, too many buffers\n"); 1460 return -1; 1461 } 1462 1463 if (msg->bufs.buflen[index] == 0) { 1464 plog(LLV_ERROR, LOCATION, NULL, 1465 "privsep: Corrupted message, unexpected void buffer\n"); 1466 return -1; 1467 } 1468 1469 return 0; 1470 } 1471 1472 /* 1473 * Filter unsafe environment variables 1474 */ 1475 static int 1476 unsafe_env(envp) 1477 char *const *envp; 1478 { 1479 char *const *e; 1480 char *const *be; 1481 char *const bad_env[] = { "PATH=", "LD_LIBRARY_PATH=", "IFS=", NULL }; 1482 1483 for (e = envp; *e; e++) { 1484 for (be = bad_env; *be; be++) { 1485 if (strncmp(*e, *be, strlen(*be)) == 0) { 1486 goto found; 1487 } 1488 } 1489 } 1490 1491 return 0; 1492 found: 1493 plog(LLV_ERROR, LOCATION, NULL, 1494 "privsep_script_exec: unsafe environment variable\n"); 1495 return -1; 1496 } 1497 1498 /* 1499 * Check path safety 1500 */ 1501 static int 1502 unsafe_path(script, pathtype) 1503 char *script; 1504 int pathtype; 1505 { 1506 char *path; 1507 char rpath[MAXPATHLEN + 1]; 1508 size_t len; 1509 1510 if (script == NULL) 1511 return -1; 1512 1513 path = lcconf->pathinfo[pathtype]; 1514 1515 /* No path was given for scripts: skip the check */ 1516 if (path == NULL) 1517 return 0; 1518 1519 if (realpath(script, rpath) == NULL) { 1520 plog(LLV_ERROR, LOCATION, NULL, 1521 "script path \"%s\" is invalid\n", script); 1522 return -1; 1523 } 1524 1525 len = strlen(path); 1526 if (strncmp(path, rpath, len) != 0) 1527 return -1; 1528 1529 return 0; 1530 } 1531 1532 static int 1533 unknown_name(name) 1534 int name; 1535 { 1536 if ((name < 0) || (name > SCRIPT_MAX)) { 1537 plog(LLV_ERROR, LOCATION, NULL, 1538 "privsep_script_exec: unsafe name index\n"); 1539 return -1; 1540 } 1541 1542 return 0; 1543 } 1544 1545 /* Receive a file descriptor through the argument socket */ 1546 static int 1547 rec_fd(s) 1548 int s; 1549 { 1550 struct msghdr msg; 1551 struct cmsghdr *cmsg; 1552 int *fdptr; 1553 int fd; 1554 char cmsbuf[1024]; 1555 struct iovec iov; 1556 char iobuf[1]; 1557 1558 iov.iov_base = iobuf; 1559 iov.iov_len = 1; 1560 1561 if (sizeof(cmsbuf) < CMSG_SPACE(sizeof(fd))) { 1562 plog(LLV_ERROR, LOCATION, NULL, 1563 "send_fd: buffer size too small\n"); 1564 return -1; 1565 } 1566 bzero(&msg, sizeof(msg)); 1567 msg.msg_name = NULL; 1568 msg.msg_namelen = 0; 1569 msg.msg_iov = &iov; 1570 msg.msg_iovlen = 1; 1571 msg.msg_control = cmsbuf; 1572 msg.msg_controllen = CMSG_SPACE(sizeof(fd)); 1573 1574 if (recvmsg(s, &msg, MSG_WAITALL) == -1) 1575 return -1; 1576 1577 cmsg = CMSG_FIRSTHDR(&msg); 1578 fdptr = (int *) CMSG_DATA(cmsg); 1579 return fdptr[0]; 1580 } 1581 1582 /* Send the file descriptor fd through the argument socket s */ 1583 static int 1584 send_fd(s, fd) 1585 int s; 1586 int fd; 1587 { 1588 struct msghdr msg; 1589 struct cmsghdr *cmsg; 1590 char cmsbuf[1024]; 1591 struct iovec iov; 1592 int *fdptr; 1593 1594 iov.iov_base = " "; 1595 iov.iov_len = 1; 1596 1597 if (sizeof(cmsbuf) < CMSG_SPACE(sizeof(fd))) { 1598 plog(LLV_ERROR, LOCATION, NULL, 1599 "send_fd: buffer size too small\n"); 1600 return -1; 1601 } 1602 bzero(&msg, sizeof(msg)); 1603 msg.msg_name = NULL; 1604 msg.msg_namelen = 0; 1605 msg.msg_iov = &iov; 1606 msg.msg_iovlen = 1; 1607 msg.msg_control = cmsbuf; 1608 msg.msg_controllen = CMSG_SPACE(sizeof(fd)); 1609 msg.msg_flags = 0; 1610 1611 cmsg = CMSG_FIRSTHDR(&msg); 1612 cmsg->cmsg_level = SOL_SOCKET; 1613 cmsg->cmsg_type = SCM_RIGHTS; 1614 cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); 1615 fdptr = (int *)CMSG_DATA(cmsg); 1616 fdptr[0] = fd; 1617 msg.msg_controllen = cmsg->cmsg_len; 1618 1619 if (sendmsg(s, &msg, 0) == -1) 1620 return -1; 1621 1622 return 0; 1623 } 1624 1625 #ifdef HAVE_LIBPAM 1626 int 1627 privsep_accounting_pam(port, inout) 1628 int port; 1629 int inout; 1630 { 1631 struct privsep_com_msg *msg; 1632 size_t len; 1633 int *port_data; 1634 int *inout_data; 1635 int *pool_size_data; 1636 1637 if (geteuid() == 0) 1638 return isakmp_cfg_accounting_pam(port, inout); 1639 1640 len = sizeof(*msg) 1641 + sizeof(port) 1642 + sizeof(inout) 1643 + sizeof(isakmp_cfg_config.pool_size); 1644 1645 if ((msg = racoon_malloc(len)) == NULL) { 1646 plog(LLV_ERROR, LOCATION, NULL, 1647 "Cannot allocate memory: %s\n", strerror(errno)); 1648 return -1; 1649 } 1650 bzero(msg, len); 1651 msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_PAM; 1652 msg->hdr.ac_len = len; 1653 msg->bufs.buflen[0] = sizeof(port); 1654 msg->bufs.buflen[1] = sizeof(inout); 1655 msg->bufs.buflen[2] = sizeof(isakmp_cfg_config.pool_size); 1656 1657 port_data = (int *)(msg + 1); 1658 inout_data = (int *)(port_data + 1); 1659 pool_size_data = (int *)(inout_data + 1); 1660 1661 *port_data = port; 1662 *inout_data = inout; 1663 *pool_size_data = isakmp_cfg_config.pool_size; 1664 1665 /* frees msg */ 1666 if (privsep_send(privsep_sock[1], msg, len) != 0) 1667 return -1; 1668 1669 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1670 return -1; 1671 1672 if (msg->hdr.ac_errno != 0) { 1673 errno = msg->hdr.ac_errno; 1674 goto out; 1675 } 1676 1677 racoon_free(msg); 1678 return 0; 1679 1680 out: 1681 racoon_free(msg); 1682 return -1; 1683 } 1684 1685 int 1686 privsep_xauth_login_pam(port, raddr, usr, pwd) 1687 int port; 1688 struct sockaddr *raddr; 1689 char *usr; 1690 char *pwd; 1691 { 1692 struct privsep_com_msg *msg; 1693 size_t len; 1694 char *data; 1695 1696 if (geteuid() == 0) 1697 return xauth_login_pam(port, raddr, usr, pwd); 1698 1699 len = sizeof(*msg) 1700 + sizeof(port) 1701 + sizeof(isakmp_cfg_config.pool_size) 1702 + sysdep_sa_len(raddr) 1703 + strlen(usr) + 1 1704 + strlen(pwd) + 1; 1705 1706 if ((msg = racoon_malloc(len)) == NULL) { 1707 plog(LLV_ERROR, LOCATION, NULL, 1708 "Cannot allocate memory: %s\n", strerror(errno)); 1709 return -1; 1710 } 1711 bzero(msg, len); 1712 msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_PAM; 1713 msg->hdr.ac_len = len; 1714 msg->bufs.buflen[0] = sizeof(port); 1715 msg->bufs.buflen[1] = sizeof(isakmp_cfg_config.pool_size); 1716 msg->bufs.buflen[2] = sysdep_sa_len(raddr); 1717 msg->bufs.buflen[3] = strlen(usr) + 1; 1718 msg->bufs.buflen[4] = strlen(pwd) + 1; 1719 1720 data = (char *)(msg + 1); 1721 memcpy(data, &port, msg->bufs.buflen[0]); 1722 1723 data += msg->bufs.buflen[0]; 1724 memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]); 1725 1726 data += msg->bufs.buflen[1]; 1727 memcpy(data, raddr, msg->bufs.buflen[2]); 1728 1729 data += msg->bufs.buflen[2]; 1730 memcpy(data, usr, msg->bufs.buflen[3]); 1731 1732 data += msg->bufs.buflen[3]; 1733 memcpy(data, pwd, msg->bufs.buflen[4]); 1734 1735 /* frees msg */ 1736 if (privsep_send(privsep_sock[1], msg, len) != 0) 1737 return -1; 1738 1739 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1740 return -1; 1741 1742 if (msg->hdr.ac_errno != 0) { 1743 errno = msg->hdr.ac_errno; 1744 goto out; 1745 } 1746 1747 racoon_free(msg); 1748 return 0; 1749 1750 out: 1751 racoon_free(msg); 1752 return -1; 1753 } 1754 1755 void 1756 privsep_cleanup_pam(port) 1757 int port; 1758 { 1759 struct privsep_com_msg *msg; 1760 size_t len; 1761 char *data; 1762 1763 if (geteuid() == 0) 1764 return cleanup_pam(port); 1765 1766 len = sizeof(*msg) 1767 + sizeof(port) 1768 + sizeof(isakmp_cfg_config.pool_size); 1769 1770 if ((msg = racoon_malloc(len)) == NULL) { 1771 plog(LLV_ERROR, LOCATION, NULL, 1772 "Cannot allocate memory: %s\n", strerror(errno)); 1773 return; 1774 } 1775 bzero(msg, len); 1776 msg->hdr.ac_cmd = PRIVSEP_CLEANUP_PAM; 1777 msg->hdr.ac_len = len; 1778 msg->bufs.buflen[0] = sizeof(port); 1779 msg->bufs.buflen[1] = sizeof(isakmp_cfg_config.pool_size); 1780 1781 data = (char *)(msg + 1); 1782 memcpy(data, &port, msg->bufs.buflen[0]); 1783 1784 data += msg->bufs.buflen[0]; 1785 memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]); 1786 1787 /* frees msg */ 1788 if (privsep_send(privsep_sock[1], msg, len) != 0) 1789 return; 1790 1791 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1792 return; 1793 1794 if (msg->hdr.ac_errno != 0) 1795 errno = msg->hdr.ac_errno; 1796 1797 racoon_free(msg); 1798 return; 1799 } 1800 #endif 1801