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