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