Home | History | Annotate | Download | only in racoon
      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
   1799