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