1 /* $NetBSD: privsep.c,v 1.6 2006/09/09 16:22:10 manu 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/socket.h> 46 #include <sys/param.h> 47 48 #include "gcmalloc.h" 49 #include "vmbuf.h" 50 #include "misc.h" 51 #include "plog.h" 52 #include "var.h" 53 #include "libpfkey.h" 54 55 #include "crypto_openssl.h" 56 #include "isakmp_var.h" 57 #include "isakmp.h" 58 #ifdef ENABLE_HYBRID 59 #include "resolv.h" 60 #include "isakmp_xauth.h" 61 #include "isakmp_cfg.h" 62 #endif 63 #include "localconf.h" 64 #include "remoteconf.h" 65 #include "admin.h" 66 #include "sockmisc.h" 67 #include "privsep.h" 68 69 static int privsep_sock[2] = { -1, -1 }; 70 71 static int privsep_recv(int, struct privsep_com_msg **, size_t *); 72 static int privsep_send(int, struct privsep_com_msg *, size_t); 73 static int safety_check(struct privsep_com_msg *, int i); 74 static int port_check(int); 75 static int unsafe_env(char *const *); 76 static int unknown_name(int); 77 static int unsafe_path(char *, int); 78 79 static int 80 privsep_send(sock, buf, len) 81 int sock; 82 struct privsep_com_msg *buf; 83 size_t len; 84 { 85 if (buf == NULL) 86 return 0; 87 88 if (sendto(sock, (char *)buf, len, 0, NULL, 0) == -1) { 89 plog(LLV_ERROR, LOCATION, NULL, 90 "privsep_send failed: %s\n", 91 strerror(errno)); 92 return -1; 93 } 94 95 racoon_free((char *)buf); 96 97 return 0; 98 } 99 100 101 static int 102 privsep_recv(sock, bufp, lenp) 103 int sock; 104 struct privsep_com_msg **bufp; 105 size_t *lenp; 106 { 107 struct admin_com com; 108 struct admin_com *combuf; 109 size_t len; 110 111 *bufp = NULL; 112 *lenp = 0; 113 114 /* Get the header */ 115 while ((len = recvfrom(sock, (char *)&com, 116 sizeof(com), MSG_PEEK, NULL, NULL)) == -1) { 117 if (errno == EINTR) 118 continue; 119 120 plog(LLV_ERROR, LOCATION, NULL, 121 "privsep_recv failed: %s\n", 122 strerror(errno)); 123 return -1; 124 } 125 126 /* Check for short packets */ 127 if (len < sizeof(com)) { 128 plog(LLV_ERROR, LOCATION, NULL, 129 "corrupted privsep message (short header)\n"); 130 return -1; 131 } 132 133 /* Allocate buffer for the whole message */ 134 if ((combuf = (struct admin_com *)racoon_malloc(com.ac_len)) == NULL) { 135 plog(LLV_ERROR, LOCATION, NULL, 136 "failed to allocate memory: %s\n", strerror(errno)); 137 return -1; 138 } 139 140 /* Get the whole buffer */ 141 while ((len = recvfrom(sock, (char *)combuf, 142 com.ac_len, 0, NULL, NULL)) == -1) { 143 if (errno == EINTR) 144 continue; 145 plog(LLV_ERROR, LOCATION, NULL, 146 "failed to recv privsep command: %s\n", 147 strerror(errno)); 148 return -1; 149 } 150 151 /* We expect len to match */ 152 if (len != com.ac_len) { 153 plog(LLV_ERROR, LOCATION, NULL, 154 "corrupted privsep message (short packet)\n"); 155 return -1; 156 } 157 158 *bufp = (struct privsep_com_msg *)combuf; 159 *lenp = len; 160 161 return 0; 162 } 163 164 int 165 privsep_init(void) 166 { 167 int i; 168 pid_t child_pid; 169 170 /* If running as root, we don't use the privsep code path */ 171 if (lcconf->uid == 0) 172 return 0; 173 174 /* 175 * When running privsep, certificate and script paths 176 * are mandatory, as they enable us to check path safety 177 * in the privilegied instance 178 */ 179 if ((lcconf->pathinfo[LC_PATHTYPE_CERT] == NULL) || 180 (lcconf->pathinfo[LC_PATHTYPE_SCRIPT] == NULL)) { 181 plog(LLV_ERROR, LOCATION, NULL, "privilege separation " 182 "require path cert and path script in the config file\n"); 183 return -1; 184 } 185 186 if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, privsep_sock) != 0) { 187 plog(LLV_ERROR, LOCATION, NULL, 188 "Cannot allocate privsep_sock: %s\n", strerror(errno)); 189 return -1; 190 } 191 192 switch (child_pid = fork()) { 193 case -1: 194 plog(LLV_ERROR, LOCATION, NULL, "Cannot fork privsep: %s\n", 195 strerror(errno)); 196 return -1; 197 break; 198 199 case 0: /* Child: drop privileges */ 200 if (lcconf->chroot != NULL) { 201 if (chdir(lcconf->chroot) != 0) { 202 plog(LLV_ERROR, LOCATION, NULL, 203 "Cannot chdir(%s): %s\n", lcconf->chroot, 204 strerror(errno)); 205 return -1; 206 } 207 if (chroot(lcconf->chroot) != 0) { 208 plog(LLV_ERROR, LOCATION, NULL, 209 "Cannot chroot(%s): %s\n", lcconf->chroot, 210 strerror(errno)); 211 return -1; 212 } 213 } 214 215 if (setgid(lcconf->gid) != 0) { 216 plog(LLV_ERROR, LOCATION, NULL, 217 "Cannot setgid(%d): %s\n", lcconf->gid, 218 strerror(errno)); 219 return -1; 220 } 221 222 if (setegid(lcconf->gid) != 0) { 223 plog(LLV_ERROR, LOCATION, NULL, 224 "Cannot setegid(%d): %s\n", lcconf->gid, 225 strerror(errno)); 226 return -1; 227 } 228 229 if (setuid(lcconf->uid) != 0) { 230 plog(LLV_ERROR, LOCATION, NULL, 231 "Cannot setuid(%d): %s\n", lcconf->uid, 232 strerror(errno)); 233 return -1; 234 } 235 236 if (seteuid(lcconf->uid) != 0) { 237 plog(LLV_ERROR, LOCATION, NULL, 238 "Cannot seteuid(%d): %s\n", lcconf->uid, 239 strerror(errno)); 240 return -1; 241 } 242 243 return 0; 244 break; 245 246 default: /* Parent: privilegied process */ 247 break; 248 } 249 250 /* 251 * Close everything except the socketpair, 252 * and stdout if running in the forground. 253 */ 254 for (i = sysconf(_SC_OPEN_MAX); i > 0; i--) { 255 if (i == privsep_sock[0]) 256 continue; 257 if (i == privsep_sock[1]) 258 continue; 259 if ((f_foreground) && (i == 1)) 260 continue; 261 (void)close(i); 262 } 263 264 /* Above trickery closed the log file, reopen it */ 265 ploginit(); 266 267 plog(LLV_INFO, LOCATION, NULL, 268 "racoon privilegied process running with PID %d\n", getpid()); 269 270 #ifdef __NetBSD__ 271 setproctitle("[priv]"); 272 #endif 273 274 /* 275 * Don't catch any signal 276 * This duplicate session:signals[], which is static... 277 */ 278 signal(SIGHUP, SIG_DFL); 279 signal(SIGINT, SIG_DFL); 280 signal(SIGTERM, SIG_DFL); 281 signal(SIGUSR1, SIG_DFL); 282 signal(SIGUSR2, SIG_DFL); 283 signal(SIGCHLD, SIG_DFL); 284 285 while (1) { 286 size_t len; 287 struct privsep_com_msg *combuf; 288 struct privsep_com_msg *reply; 289 char *data; 290 size_t *buflen; 291 size_t totallen; 292 char *bufs[PRIVSEP_NBUF_MAX]; 293 int i; 294 295 if (privsep_recv(privsep_sock[0], &combuf, &len) != 0) 296 goto out; 297 298 /* Safety checks and gather the data */ 299 if (len < sizeof(*combuf)) { 300 plog(LLV_ERROR, LOCATION, NULL, 301 "corrupted privsep message (short buflen)\n"); 302 goto out; 303 } 304 305 data = (char *)(combuf + 1); 306 totallen = sizeof(*combuf); 307 for (i = 0; i < PRIVSEP_NBUF_MAX; i++) { 308 bufs[i] = (char *)data; 309 data += combuf->bufs.buflen[i]; 310 totallen += combuf->bufs.buflen[i]; 311 } 312 313 if (totallen > len) { 314 plog(LLV_ERROR, LOCATION, NULL, 315 "corrupted privsep message (bufs too big)\n"); 316 goto out; 317 } 318 319 /* Prepare the reply buffer */ 320 if ((reply = racoon_malloc(sizeof(*reply))) == NULL) { 321 plog(LLV_ERROR, LOCATION, NULL, 322 "Cannot allocate reply buffer: %s\n", 323 strerror(errno)); 324 goto out; 325 } 326 bzero(reply, sizeof(*reply)); 327 reply->hdr.ac_cmd = combuf->hdr.ac_cmd; 328 reply->hdr.ac_len = sizeof(*reply); 329 330 switch(combuf->hdr.ac_cmd) { 331 /* 332 * XXX Improvement: instead of returning the key, 333 * stuff eay_get_pkcs1privkey and eay_get_x509sign 334 * together and sign the hash in the privilegied 335 * instance? 336 * pro: the key remains inaccessible to unpriv 337 * con: a compromised unpriv racoon can still sign anything 338 */ 339 case PRIVSEP_EAY_GET_PKCS1PRIVKEY: { 340 vchar_t *privkey; 341 342 /* Make sure the string is NULL terminated */ 343 if (safety_check(combuf, 0) != 0) 344 break; 345 bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; 346 347 if (unsafe_path(bufs[0], LC_PATHTYPE_CERT) != 0) { 348 plog(LLV_ERROR, LOCATION, NULL, 349 "privsep_eay_get_pkcs1privkey: " 350 "unsafe cert \"%s\"\n", bufs[0]); 351 } 352 353 plog(LLV_DEBUG, LOCATION, NULL, 354 "eay_get_pkcs1privkey(\"%s\")\n", bufs[0]); 355 356 if ((privkey = eay_get_pkcs1privkey(bufs[0])) == NULL){ 357 reply->hdr.ac_errno = errno; 358 break; 359 } 360 361 reply->bufs.buflen[0] = privkey->l; 362 reply->hdr.ac_len = sizeof(*reply) + privkey->l; 363 reply = racoon_realloc(reply, reply->hdr.ac_len); 364 if (reply == NULL) { 365 plog(LLV_ERROR, LOCATION, NULL, 366 "Cannot allocate reply buffer: %s\n", 367 strerror(errno)); 368 goto out; 369 } 370 371 memcpy(reply + 1, privkey->v, privkey->l); 372 vfree(privkey); 373 break; 374 } 375 376 case PRIVSEP_SCRIPT_EXEC: { 377 char *script; 378 int name; 379 char **envp = NULL; 380 int envc = 0; 381 int count = 0; 382 int i; 383 384 /* 385 * First count the bufs, and make sure strings 386 * are NULL terminated. 387 * 388 * We expect: script, name, envp[], void 389 */ 390 if (safety_check(combuf, 0) != 0) 391 break; 392 bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; 393 count++; /* script */ 394 395 count++; /* name */ 396 397 for (; count < PRIVSEP_NBUF_MAX; count++) { 398 if (combuf->bufs.buflen[count] == 0) 399 break; 400 bufs[count] 401 [combuf->bufs.buflen[count] - 1] = '\0'; 402 envc++; 403 } 404 405 /* count a void buf and perform safety check */ 406 count++; 407 if (count >= PRIVSEP_NBUF_MAX) { 408 plog(LLV_ERROR, LOCATION, NULL, 409 "privsep_script_exec: too many args\n"); 410 goto out; 411 } 412 413 414 /* 415 * Allocate the arrays for envp 416 */ 417 envp = racoon_malloc((envc + 1) * sizeof(char *)); 418 if (envp == NULL) { 419 plog(LLV_ERROR, LOCATION, NULL, 420 "cannot allocate memory: %s\n", 421 strerror(errno)); 422 goto out; 423 } 424 bzero(envp, (envc + 1) * sizeof(char *)); 425 426 427 /* 428 * Populate script, name and envp 429 */ 430 count = 0; 431 script = bufs[count++]; 432 433 if (combuf->bufs.buflen[count] != sizeof(name)) { 434 plog(LLV_ERROR, LOCATION, NULL, 435 "privsep_script_exec: corrupted message\n"); 436 goto out; 437 } 438 memcpy((char *)&name, bufs[count++], sizeof(name)); 439 440 for (i = 0; combuf->bufs.buflen[count]; count++) 441 envp[i++] = bufs[count]; 442 443 count++; /* void */ 444 445 plog(LLV_DEBUG, LOCATION, NULL, 446 "script_exec(\"%s\", %d, %p)\n", 447 script, name, envp); 448 449 /* 450 * Check env for dangerous variables 451 * Check script path and name 452 * Perform fork and execve 453 */ 454 if ((unsafe_env(envp) == 0) && 455 (unknown_name(name) == 0) && 456 (unsafe_path(script, LC_PATHTYPE_SCRIPT) == 0)) 457 (void)script_exec(script, name, envp); 458 else 459 plog(LLV_ERROR, LOCATION, NULL, 460 "privsep_script_exec: " 461 "unsafe script \"%s\"\n", script); 462 463 racoon_free(envp); 464 break; 465 } 466 467 case PRIVSEP_GETPSK: { 468 vchar_t *psk; 469 int keylen; 470 471 /* Make sure the string is NULL terminated */ 472 if (safety_check(combuf, 0) != 0) 473 break; 474 bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; 475 476 if (combuf->bufs.buflen[1] != sizeof(keylen)) { 477 plog(LLV_ERROR, LOCATION, NULL, 478 "privsep_getpsk: corrupted message\n"); 479 goto out; 480 } 481 memcpy(&keylen, bufs[1], sizeof(keylen)); 482 483 plog(LLV_DEBUG, LOCATION, NULL, 484 "getpsk(\"%s\", %d)\n", bufs[0], keylen); 485 486 if ((psk = getpsk(bufs[0], keylen)) == NULL) { 487 reply->hdr.ac_errno = errno; 488 break; 489 } 490 491 reply->bufs.buflen[0] = psk->l; 492 reply->hdr.ac_len = sizeof(*reply) + psk->l; 493 reply = racoon_realloc(reply, reply->hdr.ac_len); 494 if (reply == NULL) { 495 plog(LLV_ERROR, LOCATION, NULL, 496 "Cannot allocate reply buffer: %s\n", 497 strerror(errno)); 498 goto out; 499 } 500 501 memcpy(reply + 1, psk->v, psk->l); 502 vfree(psk); 503 break; 504 } 505 506 #ifdef ENABLE_HYBRID 507 case PRIVSEP_ACCOUNTING_SYSTEM: { 508 int pool_size; 509 int port; 510 int inout; 511 struct sockaddr *raddr; 512 513 if (safety_check(combuf, 0) != 0) 514 break; 515 if (safety_check(combuf, 1) != 0) 516 break; 517 if (safety_check(combuf, 2) != 0) 518 break; 519 if (safety_check(combuf, 3) != 0) 520 break; 521 522 memcpy(&port, bufs[0], sizeof(port)); 523 raddr = (struct sockaddr *)bufs[1]; 524 525 bufs[2][combuf->bufs.buflen[2] - 1] = '\0'; 526 memcpy(&inout, bufs[3], sizeof(port)); 527 528 if (port_check(port) != 0) 529 break; 530 531 plog(LLV_DEBUG, LOCATION, NULL, 532 "accounting_system(%d, %s, %s)\n", 533 port, saddr2str(raddr), bufs[2]); 534 535 errno = 0; 536 if (isakmp_cfg_accounting_system(port, 537 raddr, bufs[2], inout) != 0) { 538 if (errno == 0) 539 reply->hdr.ac_errno = EINVAL; 540 else 541 reply->hdr.ac_errno = errno; 542 } 543 break; 544 } 545 case PRIVSEP_XAUTH_LOGIN_SYSTEM: { 546 if (safety_check(combuf, 0) != 0) 547 break; 548 bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; 549 550 if (safety_check(combuf, 1) != 0) 551 break; 552 bufs[1][combuf->bufs.buflen[1] - 1] = '\0'; 553 554 plog(LLV_DEBUG, LOCATION, NULL, 555 "xauth_login_system(\"%s\", <password>)\n", 556 bufs[0]); 557 558 errno = 0; 559 if (xauth_login_system(bufs[0], bufs[1]) != 0) { 560 if (errno == 0) 561 reply->hdr.ac_errno = EINVAL; 562 else 563 reply->hdr.ac_errno = errno; 564 } 565 break; 566 } 567 #ifdef HAVE_LIBPAM 568 case PRIVSEP_ACCOUNTING_PAM: { 569 int port; 570 int inout; 571 int pool_size; 572 573 if (safety_check(combuf, 0) != 0) 574 break; 575 if (safety_check(combuf, 1) != 0) 576 break; 577 if (safety_check(combuf, 2) != 0) 578 break; 579 580 memcpy(&port, bufs[0], sizeof(port)); 581 memcpy(&inout, bufs[1], sizeof(inout)); 582 memcpy(&pool_size, bufs[2], sizeof(pool_size)); 583 584 if (pool_size != isakmp_cfg_config.pool_size) 585 if (isakmp_cfg_resize_pool(pool_size) != 0) 586 break; 587 588 if (port_check(port) != 0) 589 break; 590 591 plog(LLV_DEBUG, LOCATION, NULL, 592 "isakmp_cfg_accounting_pam(%d, %d)\n", 593 port, inout); 594 595 errno = 0; 596 if (isakmp_cfg_accounting_pam(port, inout) != 0) { 597 if (errno == 0) 598 reply->hdr.ac_errno = EINVAL; 599 else 600 reply->hdr.ac_errno = errno; 601 } 602 break; 603 } 604 605 case PRIVSEP_XAUTH_LOGIN_PAM: { 606 int port; 607 int pool_size; 608 struct sockaddr *raddr; 609 610 if (safety_check(combuf, 0) != 0) 611 break; 612 if (safety_check(combuf, 1) != 0) 613 break; 614 if (safety_check(combuf, 2) != 0) 615 break; 616 if (safety_check(combuf, 3) != 0) 617 break; 618 if (safety_check(combuf, 4) != 0) 619 break; 620 621 memcpy(&port, bufs[0], sizeof(port)); 622 memcpy(&pool_size, bufs[1], sizeof(pool_size)); 623 raddr = (struct sockaddr *)bufs[2]; 624 625 bufs[3][combuf->bufs.buflen[3] - 1] = '\0'; 626 bufs[4][combuf->bufs.buflen[4] - 1] = '\0'; 627 628 if (pool_size != isakmp_cfg_config.pool_size) 629 if (isakmp_cfg_resize_pool(pool_size) != 0) 630 break; 631 632 if (port_check(port) != 0) 633 break; 634 635 plog(LLV_DEBUG, LOCATION, NULL, 636 "xauth_login_pam(%d, %s, \"%s\", <password>)\n", 637 port, saddr2str(raddr), bufs[3]); 638 639 errno = 0; 640 if (xauth_login_pam(port, 641 raddr, bufs[3], bufs[4]) != 0) { 642 if (errno == 0) 643 reply->hdr.ac_errno = EINVAL; 644 else 645 reply->hdr.ac_errno = errno; 646 } 647 break; 648 } 649 650 case PRIVSEP_CLEANUP_PAM: { 651 int port; 652 int pool_size; 653 654 if (safety_check(combuf, 0) != 0) 655 break; 656 if (safety_check(combuf, 1) != 0) 657 break; 658 659 memcpy(&port, bufs[0], sizeof(port)); 660 memcpy(&pool_size, bufs[1], sizeof(pool_size)); 661 662 if (pool_size != isakmp_cfg_config.pool_size) 663 if (isakmp_cfg_resize_pool(pool_size) != 0) 664 break; 665 666 if (port_check(port) != 0) 667 break; 668 669 plog(LLV_DEBUG, LOCATION, NULL, 670 "cleanup_pam(%d)\n", port); 671 672 cleanup_pam(port); 673 reply->hdr.ac_errno = 0; 674 675 break; 676 } 677 #endif /* HAVE_LIBPAM */ 678 #endif /* ENABLE_HYBRID */ 679 680 default: 681 plog(LLV_ERROR, LOCATION, NULL, 682 "unexpected privsep command %d\n", 683 combuf->hdr.ac_cmd); 684 goto out; 685 break; 686 } 687 688 /* This frees reply */ 689 if (privsep_send(privsep_sock[0], 690 reply, reply->hdr.ac_len) != 0) 691 goto out; 692 693 racoon_free(combuf); 694 } 695 696 out: 697 plog(LLV_INFO, LOCATION, NULL, "privsep exit\n"); 698 _exit(0); 699 } 700 701 702 vchar_t * 703 privsep_eay_get_pkcs1privkey(path) 704 char *path; 705 { 706 vchar_t *privkey; 707 struct privsep_com_msg *msg; 708 size_t len; 709 710 if (geteuid() == 0) 711 return eay_get_pkcs1privkey(path); 712 713 len = sizeof(*msg) + strlen(path) + 1; 714 if ((msg = racoon_malloc(len)) == NULL) { 715 plog(LLV_ERROR, LOCATION, NULL, 716 "Cannot allocate memory: %s\n", strerror(errno)); 717 return NULL; 718 } 719 bzero(msg, len); 720 msg->hdr.ac_cmd = PRIVSEP_EAY_GET_PKCS1PRIVKEY; 721 msg->hdr.ac_len = len; 722 msg->bufs.buflen[0] = len - sizeof(*msg); 723 memcpy(msg + 1, path, msg->bufs.buflen[0]); 724 725 if (privsep_send(privsep_sock[1], msg, len) != 0) 726 return NULL; 727 728 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 729 return NULL; 730 731 if (msg->hdr.ac_errno != 0) { 732 errno = msg->hdr.ac_errno; 733 goto out; 734 } 735 736 if ((privkey = vmalloc(len - sizeof(*msg))) == NULL) 737 goto out; 738 739 memcpy(privkey->v, msg + 1, privkey->l); 740 racoon_free(msg); 741 return privkey; 742 743 out: 744 racoon_free(msg); 745 return NULL; 746 } 747 748 /* 749 * No prigilege separation trick here, we just open PFKEY before 750 * dropping root privs and we remember it later. 751 */ 752 static int pfkey_socket = -1; 753 int 754 privsep_pfkey_open(void) 755 { 756 int ps; 757 758 if (pfkey_socket != -1) 759 return pfkey_socket; 760 761 ps = pfkey_open(); 762 if (ps != -1) 763 pfkey_socket = ps; 764 765 return ps; 766 } 767 768 /* 769 * Consequence of the above trickery: don't 770 * really close PFKEY as we never re-open it. 771 */ 772 void 773 privsep_pfkey_close(ps) 774 int ps; 775 { 776 return; 777 } 778 779 int 780 privsep_script_exec(script, name, envp) 781 char *script; 782 int name; 783 char *const envp[]; 784 { 785 int count = 0; 786 char *const *c; 787 char *data; 788 size_t len; 789 struct privsep_com_msg *msg; 790 791 if (geteuid() == 0) 792 return script_exec(script, name, envp); 793 794 if ((msg = racoon_malloc(sizeof(*msg))) == NULL) { 795 plog(LLV_ERROR, LOCATION, NULL, 796 "Cannot allocate memory: %s\n", strerror(errno)); 797 return -1; 798 } 799 800 bzero(msg, sizeof(*msg)); 801 msg->hdr.ac_cmd = PRIVSEP_SCRIPT_EXEC; 802 msg->hdr.ac_len = sizeof(*msg); 803 804 /* 805 * We send: 806 * script, name, envp[0], ... envp[N], void 807 */ 808 809 /* 810 * Safety check on the counts: PRIVSEP_NBUF_MAX max 811 */ 812 count = 0; 813 count++; /* script */ 814 count++; /* name */ 815 for (c = envp; *c; c++) /* envp */ 816 count++; 817 count++; /* void */ 818 819 if (count > PRIVSEP_NBUF_MAX) { 820 plog(LLV_ERROR, LOCATION, NULL, "Unexpected error: " 821 "privsep_script_exec count > PRIVSEP_NBUF_MAX\n"); 822 racoon_free(msg); 823 return -1; 824 } 825 826 827 /* 828 * Compute the length 829 */ 830 count = 0; 831 msg->bufs.buflen[count] = strlen(script) + 1; /* script */ 832 msg->hdr.ac_len += msg->bufs.buflen[count++]; 833 834 msg->bufs.buflen[count] = sizeof(name); /* name */ 835 msg->hdr.ac_len += msg->bufs.buflen[count++]; 836 837 for (c = envp; *c; c++) { /* envp */ 838 msg->bufs.buflen[count] = strlen(*c) + 1; 839 msg->hdr.ac_len += msg->bufs.buflen[count++]; 840 } 841 842 msg->bufs.buflen[count] = 0; /* void */ 843 msg->hdr.ac_len += msg->bufs.buflen[count++]; 844 845 if ((msg = racoon_realloc(msg, msg->hdr.ac_len)) == NULL) { 846 plog(LLV_ERROR, LOCATION, NULL, 847 "Cannot allocate memory: %s\n", strerror(errno)); 848 return -1; 849 } 850 851 /* 852 * Now copy the data 853 */ 854 data = (char *)(msg + 1); 855 count = 0; 856 857 memcpy(data, (char *)script, msg->bufs.buflen[count]); /* script */ 858 data += msg->bufs.buflen[count++]; 859 860 memcpy(data, (char *)&name, msg->bufs.buflen[count]); /* name */ 861 data += msg->bufs.buflen[count++]; 862 863 for (c = envp; *c; c++) { /* envp */ 864 memcpy(data, *c, msg->bufs.buflen[count]); 865 data += msg->bufs.buflen[count++]; 866 } 867 868 count++; /* void */ 869 870 /* 871 * And send it! 872 */ 873 if (privsep_send(privsep_sock[1], msg, msg->hdr.ac_len) != 0) 874 return -1; 875 876 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 877 return -1; 878 879 if (msg->hdr.ac_errno != 0) { 880 errno = msg->hdr.ac_errno; 881 racoon_free(msg); 882 return -1; 883 } 884 885 racoon_free(msg); 886 return 0; 887 } 888 889 vchar_t * 890 privsep_getpsk(str, keylen) 891 const char *str; 892 int keylen; 893 { 894 vchar_t *psk; 895 struct privsep_com_msg *msg; 896 size_t len; 897 int *keylenp; 898 char *data; 899 900 if (geteuid() == 0) 901 return getpsk(str, keylen); 902 903 len = sizeof(*msg) + strlen(str) + 1 + sizeof(keylen); 904 if ((msg = racoon_malloc(len)) == NULL) { 905 plog(LLV_ERROR, LOCATION, NULL, 906 "Cannot allocate memory: %s\n", strerror(errno)); 907 return NULL; 908 } 909 bzero(msg, len); 910 msg->hdr.ac_cmd = PRIVSEP_GETPSK; 911 msg->hdr.ac_len = len; 912 913 data = (char *)(msg + 1); 914 msg->bufs.buflen[0] = strlen(str) + 1; 915 memcpy(data, str, msg->bufs.buflen[0]); 916 917 data += msg->bufs.buflen[0]; 918 msg->bufs.buflen[1] = sizeof(keylen); 919 memcpy(data, &keylen, sizeof(keylen)); 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 ((psk = vmalloc(len - sizeof(*msg))) == NULL) 933 goto out; 934 935 memcpy(psk->v, msg + 1, psk->l); 936 racoon_free(msg); 937 return psk; 938 939 out: 940 racoon_free(msg); 941 return NULL; 942 } 943 944 #ifdef ENABLE_HYBRID 945 int 946 privsep_xauth_login_system(usr, pwd) 947 char *usr; 948 char *pwd; 949 { 950 struct privsep_com_msg *msg; 951 size_t len; 952 char *data; 953 954 if (geteuid() == 0) 955 return xauth_login_system(usr, pwd); 956 957 len = sizeof(*msg) + strlen(usr) + 1 + strlen(pwd) + 1; 958 if ((msg = racoon_malloc(len)) == NULL) { 959 plog(LLV_ERROR, LOCATION, NULL, 960 "Cannot allocate memory: %s\n", strerror(errno)); 961 return -1; 962 } 963 bzero(msg, len); 964 msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_SYSTEM; 965 msg->hdr.ac_len = len; 966 967 data = (char *)(msg + 1); 968 msg->bufs.buflen[0] = strlen(usr) + 1; 969 memcpy(data, usr, msg->bufs.buflen[0]); 970 data += msg->bufs.buflen[0]; 971 972 msg->bufs.buflen[1] = strlen(pwd) + 1; 973 memcpy(data, pwd, msg->bufs.buflen[1]); 974 975 if (privsep_send(privsep_sock[1], msg, len) != 0) 976 return -1; 977 978 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 979 return -1; 980 981 if (msg->hdr.ac_errno != 0) { 982 racoon_free(msg); 983 return -1; 984 } 985 986 racoon_free(msg); 987 return 0; 988 } 989 990 int 991 privsep_accounting_system(port, raddr, usr, inout) 992 int port; 993 struct sockaddr *raddr; 994 char *usr; 995 int inout; 996 { 997 struct privsep_com_msg *msg; 998 size_t len; 999 char *data; 1000 int result; 1001 1002 if (geteuid() == 0) 1003 return isakmp_cfg_accounting_system(port, raddr, 1004 usr, inout); 1005 1006 len = sizeof(*msg) 1007 + sizeof(port) 1008 + sysdep_sa_len(raddr) 1009 + strlen(usr) + 1 1010 + sizeof(inout); 1011 1012 if ((msg = racoon_malloc(len)) == NULL) { 1013 plog(LLV_ERROR, LOCATION, NULL, 1014 "Cannot allocate memory: %s\n", strerror(errno)); 1015 return -1; 1016 } 1017 bzero(msg, len); 1018 msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_SYSTEM; 1019 msg->hdr.ac_len = len; 1020 msg->bufs.buflen[0] = sizeof(port); 1021 msg->bufs.buflen[1] = sysdep_sa_len(raddr); 1022 msg->bufs.buflen[2] = strlen(usr) + 1; 1023 msg->bufs.buflen[3] = sizeof(inout); 1024 1025 data = (char *)(msg + 1); 1026 memcpy(data, &port, msg->bufs.buflen[0]); 1027 1028 data += msg->bufs.buflen[0]; 1029 memcpy(data, raddr, msg->bufs.buflen[1]); 1030 1031 data += msg->bufs.buflen[1]; 1032 memcpy(data, usr, msg->bufs.buflen[2]); 1033 1034 data += msg->bufs.buflen[2]; 1035 memcpy(data, &inout, msg->bufs.buflen[3]); 1036 1037 if (privsep_send(privsep_sock[1], msg, len) != 0) 1038 return -1; 1039 1040 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1041 return -1; 1042 1043 if (msg->hdr.ac_errno != 0) { 1044 errno = msg->hdr.ac_errno; 1045 goto out; 1046 } 1047 1048 racoon_free(msg); 1049 return 0; 1050 1051 out: 1052 racoon_free(msg); 1053 return -1; 1054 } 1055 1056 static int 1057 port_check(port) 1058 int port; 1059 { 1060 if ((port < 0) || (port >= isakmp_cfg_config.pool_size)) { 1061 plog(LLV_ERROR, LOCATION, NULL, 1062 "privsep: port %d outside of allowed range [0,%zu]\n", 1063 port, isakmp_cfg_config.pool_size - 1); 1064 return -1; 1065 } 1066 1067 return 0; 1068 } 1069 #endif 1070 1071 static int 1072 safety_check(msg, index) 1073 struct privsep_com_msg *msg; 1074 int index; 1075 { 1076 if (index >= PRIVSEP_NBUF_MAX) { 1077 plog(LLV_ERROR, LOCATION, NULL, 1078 "privsep: Corrupted message, too many buffers\n"); 1079 return -1; 1080 } 1081 1082 if (msg->bufs.buflen[index] == 0) { 1083 plog(LLV_ERROR, LOCATION, NULL, 1084 "privsep: Corrupted message, unexpected void buffer\n"); 1085 return -1; 1086 } 1087 1088 return 0; 1089 } 1090 1091 /* 1092 * Filter unsafe environement variables 1093 */ 1094 static int 1095 unsafe_env(envp) 1096 char *const *envp; 1097 { 1098 char *const *e; 1099 char *const *be; 1100 char *const bad_env[] = { "PATH=", "LD_LIBRARY_PATH=", "IFS=", NULL }; 1101 1102 for (e = envp; *e; e++) { 1103 for (be = bad_env; *be; be++) { 1104 if (strncmp(*e, *be, strlen(*be)) == 0) { 1105 goto found; 1106 } 1107 } 1108 } 1109 1110 return 0; 1111 found: 1112 plog(LLV_ERROR, LOCATION, NULL, 1113 "privsep_script_exec: unsafe environement variable\n"); 1114 return -1; 1115 } 1116 1117 /* 1118 * Check path safety 1119 */ 1120 static int 1121 unsafe_path(script, pathtype) 1122 char *script; 1123 int pathtype; 1124 { 1125 char *path; 1126 char rpath[MAXPATHLEN + 1]; 1127 size_t len; 1128 1129 if (script == NULL) 1130 return -1; 1131 1132 path = lcconf->pathinfo[pathtype]; 1133 1134 /* No path was given for scripts: skip the check */ 1135 if (path == NULL) 1136 return 0; 1137 1138 if (realpath(script, rpath) == NULL) { 1139 plog(LLV_ERROR, LOCATION, NULL, 1140 "script path \"%s\" is invalid\n", script); 1141 return -1; 1142 } 1143 1144 len = strlen(path); 1145 if (strncmp(path, rpath, len) != 0) 1146 return -1; 1147 1148 return 0; 1149 } 1150 1151 static int 1152 unknown_name(name) 1153 int name; 1154 { 1155 if ((name < 0) || (name > SCRIPT_MAX)) { 1156 plog(LLV_ERROR, LOCATION, NULL, 1157 "privsep_script_exec: unsafe name index\n"); 1158 return -1; 1159 } 1160 1161 return 0; 1162 } 1163 1164 #ifdef HAVE_LIBPAM 1165 int 1166 privsep_accounting_pam(port, inout) 1167 int port; 1168 int inout; 1169 { 1170 struct privsep_com_msg *msg; 1171 size_t len; 1172 int *port_data; 1173 int *inout_data; 1174 int *pool_size_data; 1175 int result; 1176 1177 if (geteuid() == 0) 1178 return isakmp_cfg_accounting_pam(port, inout); 1179 1180 len = sizeof(*msg) 1181 + sizeof(port) 1182 + sizeof(inout) 1183 + sizeof(isakmp_cfg_config.pool_size); 1184 1185 if ((msg = racoon_malloc(len)) == NULL) { 1186 plog(LLV_ERROR, LOCATION, NULL, 1187 "Cannot allocate memory: %s\n", strerror(errno)); 1188 return -1; 1189 } 1190 bzero(msg, len); 1191 msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_PAM; 1192 msg->hdr.ac_len = len; 1193 msg->bufs.buflen[0] = sizeof(port); 1194 msg->bufs.buflen[1] = sizeof(inout); 1195 msg->bufs.buflen[2] = sizeof(isakmp_cfg_config.pool_size); 1196 1197 port_data = (int *)(msg + 1); 1198 inout_data = (int *)(port_data + 1); 1199 pool_size_data = (int *)(inout_data + 1); 1200 1201 *port_data = port; 1202 *inout_data = inout; 1203 *pool_size_data = isakmp_cfg_config.pool_size; 1204 1205 if (privsep_send(privsep_sock[1], msg, len) != 0) 1206 return -1; 1207 1208 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1209 return -1; 1210 1211 if (msg->hdr.ac_errno != 0) { 1212 errno = msg->hdr.ac_errno; 1213 goto out; 1214 } 1215 1216 racoon_free(msg); 1217 return 0; 1218 1219 out: 1220 racoon_free(msg); 1221 return -1; 1222 } 1223 1224 int 1225 privsep_xauth_login_pam(port, raddr, usr, pwd) 1226 int port; 1227 struct sockaddr *raddr; 1228 char *usr; 1229 char *pwd; 1230 { 1231 struct privsep_com_msg *msg; 1232 size_t len; 1233 char *data; 1234 int result; 1235 1236 if (geteuid() == 0) 1237 return xauth_login_pam(port, raddr, usr, pwd); 1238 1239 len = sizeof(*msg) 1240 + sizeof(port) 1241 + sizeof(isakmp_cfg_config.pool_size) 1242 + sysdep_sa_len(raddr) 1243 + strlen(usr) + 1 1244 + strlen(pwd) + 1; 1245 1246 if ((msg = racoon_malloc(len)) == NULL) { 1247 plog(LLV_ERROR, LOCATION, NULL, 1248 "Cannot allocate memory: %s\n", strerror(errno)); 1249 return -1; 1250 } 1251 bzero(msg, len); 1252 msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_PAM; 1253 msg->hdr.ac_len = len; 1254 msg->bufs.buflen[0] = sizeof(port); 1255 msg->bufs.buflen[1] = sizeof(isakmp_cfg_config.pool_size); 1256 msg->bufs.buflen[2] = sysdep_sa_len(raddr); 1257 msg->bufs.buflen[3] = strlen(usr) + 1; 1258 msg->bufs.buflen[4] = strlen(pwd) + 1; 1259 1260 data = (char *)(msg + 1); 1261 memcpy(data, &port, msg->bufs.buflen[0]); 1262 1263 data += msg->bufs.buflen[0]; 1264 memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]); 1265 1266 data += msg->bufs.buflen[1]; 1267 memcpy(data, raddr, msg->bufs.buflen[2]); 1268 1269 data += msg->bufs.buflen[2]; 1270 memcpy(data, usr, msg->bufs.buflen[3]); 1271 1272 data += msg->bufs.buflen[3]; 1273 memcpy(data, pwd, msg->bufs.buflen[4]); 1274 1275 if (privsep_send(privsep_sock[1], msg, len) != 0) 1276 return -1; 1277 1278 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1279 return -1; 1280 1281 if (msg->hdr.ac_errno != 0) { 1282 errno = msg->hdr.ac_errno; 1283 goto out; 1284 } 1285 1286 racoon_free(msg); 1287 return 0; 1288 1289 out: 1290 racoon_free(msg); 1291 return -1; 1292 } 1293 1294 void 1295 privsep_cleanup_pam(port) 1296 int port; 1297 { 1298 struct privsep_com_msg *msg; 1299 size_t len; 1300 char *data; 1301 int result; 1302 1303 if (geteuid() == 0) 1304 return cleanup_pam(port); 1305 1306 len = sizeof(*msg) 1307 + sizeof(port) 1308 + sizeof(isakmp_cfg_config.pool_size); 1309 1310 if ((msg = racoon_malloc(len)) == NULL) { 1311 plog(LLV_ERROR, LOCATION, NULL, 1312 "Cannot allocate memory: %s\n", strerror(errno)); 1313 return; 1314 } 1315 bzero(msg, len); 1316 msg->hdr.ac_cmd = PRIVSEP_CLEANUP_PAM; 1317 msg->hdr.ac_len = len; 1318 msg->bufs.buflen[0] = sizeof(port); 1319 msg->bufs.buflen[1] = sizeof(isakmp_cfg_config.pool_size); 1320 1321 data = (char *)(msg + 1); 1322 memcpy(data, &port, msg->bufs.buflen[0]); 1323 1324 data += msg->bufs.buflen[0]; 1325 memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]); 1326 1327 if (privsep_send(privsep_sock[1], msg, len) != 0) 1328 return; 1329 1330 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) 1331 return; 1332 1333 if (msg->hdr.ac_errno != 0) 1334 errno = msg->hdr.ac_errno; 1335 1336 racoon_free(msg); 1337 return; 1338 } 1339 #endif 1340