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