1/*	$NetBSD: privsep.c,v 1.21 2011/03/06 08:28:10 tteras Exp $	*/
2
3/* Id: privsep.c,v 1.15 2005/08/08 11:23:44 vanhu Exp */
4
5/*
6 * Copyright (C) 2004 Emmanuel Dreyfus
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "config.h"
35
36#include <unistd.h>
37#include <string.h>
38#ifdef __NetBSD__
39#include <stdlib.h>	/* for setproctitle */
40#endif
41#include <errno.h>
42#include <signal.h>
43#include <pwd.h>
44
45#include <sys/types.h>
46#include <sys/socket.h>
47#include <sys/param.h>
48
49#include <netinet/in.h>
50
51#include "gcmalloc.h"
52#include "vmbuf.h"
53#include "misc.h"
54#include "plog.h"
55#include "var.h"
56
57#include "crypto_openssl.h"
58#include "isakmp_var.h"
59#include "isakmp.h"
60#ifdef ENABLE_HYBRID
61#include "resolv.h"
62#include "isakmp_xauth.h"
63#include "isakmp_cfg.h"
64#endif
65#include "localconf.h"
66#include "remoteconf.h"
67#include "admin.h"
68#include "sockmisc.h"
69#include "privsep.h"
70#include "session.h"
71
72static int privsep_sock[2] = { -1, -1 };
73
74static int privsep_recv(int, struct privsep_com_msg **, size_t *);
75static int privsep_send(int, struct privsep_com_msg *, size_t);
76static int safety_check(struct privsep_com_msg *, int i);
77static int port_check(int);
78static int unsafe_env(char *const *);
79static int unknown_name(int);
80static int unsafe_path(char *, int);
81static int rec_fd(int);
82static int send_fd(int, int);
83
84struct socket_args {
85	int domain;
86	int type;
87	int protocol;
88};
89
90struct sockopt_args {
91	int s;
92	int level;
93	int optname;
94	const void *optval;
95	socklen_t optlen;
96};
97
98struct bind_args {
99	int s;
100	const struct sockaddr *addr;
101	socklen_t addrlen;
102};
103
104static int
105privsep_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
126static int
127privsep_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
197static int
198privsep_do_exit(void *ctx, int fd)
199{
200	kill(getpid(), SIGTERM);
201	return 0;
202}
203
204int
205privsep_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
891out:
892	plog(LLV_INFO, LOCATION, NULL,
893	    "racoon privileged process %d terminated\n", getpid());
894	_exit(0);
895}
896
897
898vchar_t *
899privsep_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
939out:
940	racoon_free(msg);
941	return NULL;
942}
943
944int
945privsep_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
1054vchar_t *
1055privsep_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
1104out:
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 */
1114int
1115privsep_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
1167out:
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 */
1177int
1178privsep_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
1240out:
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 */
1250int
1251privsep_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
1322out:
1323	racoon_free(msg);
1324	return -1;
1325}
1326
1327#ifdef ENABLE_HYBRID
1328int
1329privsep_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
1374int
1375privsep_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
1436out:
1437	racoon_free(msg);
1438	return -1;
1439}
1440
1441static int
1442port_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
1456static int
1457safety_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 */
1479static int
1480unsafe_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;
1496found:
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 */
1505static int
1506unsafe_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
1536static int
1537unknown_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 */
1550static int
1551rec_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 */
1587static int
1588send_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
1630int
1631privsep_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
1685out:
1686	racoon_free(msg);
1687	return -1;
1688}
1689
1690int
1691privsep_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
1756out:
1757	racoon_free(msg);
1758	return -1;
1759}
1760
1761void
1762privsep_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