File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ipsec-tools / src / racoon / privsep.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:37:12 2014 UTC (10 years ago) by misho
Branches: ipsec-tools, MAIN
CVS tags: v0_8_2p2, v0_8_1p0, v0_8_1, HEAD
ipsec-tools 0.8.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>