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