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