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