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