Annotation of embedaddon/ipsec-tools/src/racoon/privsep.c, revision 1.1
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
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>