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