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