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