xref: /illumos-gate/usr/src/cmd/sckmd/sparc/sun4u/sckmd.c (revision 7a17cfad)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
525cf1a30Sjl  * Common Development and Distribution License (the "License").
625cf1a30Sjl  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*7a17cfadSDan McDonald  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * sckmd - Starcat Key Management Daemon
287c478bd9Sstevel@tonic-gate  *
297c478bd9Sstevel@tonic-gate  * The sckmd is a daemon that runs on a domain and is responsible for
307c478bd9Sstevel@tonic-gate  * establishing security associations (SAs) for secure communication
317c478bd9Sstevel@tonic-gate  * with the System Controller (SC). All SAs are created on the SC
327c478bd9Sstevel@tonic-gate  * and propogated to the sckmd through the sckm driver running on
337c478bd9Sstevel@tonic-gate  * the domain. The sckmd then passes the SA to the key engine via the
347c478bd9Sstevel@tonic-gate  * PF_KEY interface.
357c478bd9Sstevel@tonic-gate  */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <stdlib.h>
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate #include <stdarg.h>
407c478bd9Sstevel@tonic-gate #include <unistd.h>
417c478bd9Sstevel@tonic-gate #include <fcntl.h>
427c478bd9Sstevel@tonic-gate #include <string.h>
437c478bd9Sstevel@tonic-gate #include <errno.h>
447c478bd9Sstevel@tonic-gate #include <syslog.h>
457c478bd9Sstevel@tonic-gate #include <sys/types.h>
467c478bd9Sstevel@tonic-gate #include <sys/stat.h>
477c478bd9Sstevel@tonic-gate #include <sys/times.h>
487c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
497c478bd9Sstevel@tonic-gate #include <sys/socket.h>
507c478bd9Sstevel@tonic-gate #include <net/pfkeyv2.h>
517c478bd9Sstevel@tonic-gate #include <netinet/in.h>
527c478bd9Sstevel@tonic-gate #include <ipsec_util.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #include <sys/sckm_io.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #ifdef SCKMD_DEBUG
587c478bd9Sstevel@tonic-gate #define	OPT_STR	"ds"
597c478bd9Sstevel@tonic-gate #else /* SCKMD_DEBUG */
607c478bd9Sstevel@tonic-gate #define	OPT_STR	""
617c478bd9Sstevel@tonic-gate #endif /* SCKMD_DEBUG */
627c478bd9Sstevel@tonic-gate 
6325cf1a30Sjl #define	KM_DEV	"/dev/kmdrv"
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate #define	SCKMD_MAX_MSG_SIZE	1024
667c478bd9Sstevel@tonic-gate #define	SCKMD_ERR_MSG_SIZE	512
677c478bd9Sstevel@tonic-gate #define	SCKMD_MSG_HDR_SIZE	sizeof (struct sadb_msg)
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate #define	SCKMD_CURR_PFKEY_VER	PF_KEY_V2
707c478bd9Sstevel@tonic-gate #define	SCKMD_PFKEY_TIMEOUT	3000	/* 3 seconds */
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate static pid_t mypid;
747c478bd9Sstevel@tonic-gate static int standalone;
757c478bd9Sstevel@tonic-gate static int debug;
767c478bd9Sstevel@tonic-gate static int keysock;
777c478bd9Sstevel@tonic-gate static uint32_t seq = 0;
787c478bd9Sstevel@tonic-gate static uint64_t msg_buf[SCKMD_MAX_MSG_SIZE];
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static int process_sckm_req(int fd, sckm_ioctl_getreq_t *msg);
827c478bd9Sstevel@tonic-gate static int send_sckm_status(int fd, sckm_ioctl_status_t *msg);
837c478bd9Sstevel@tonic-gate static int get_pfkey_reply(uint32_t req_seq, uint8_t req_type, int *err);
847c478bd9Sstevel@tonic-gate static struct sadb_msg *read_pfkey_msg(void);
857c478bd9Sstevel@tonic-gate static int convert_pfkey_msg(struct sadb_msg *msg);
867c478bd9Sstevel@tonic-gate static void sckmd_log(int priority, char *fmt, ...);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate  * main:
917c478bd9Sstevel@tonic-gate  *
927c478bd9Sstevel@tonic-gate  * Initialize sckmd and enter an infinite loop. The loop waits for
937c478bd9Sstevel@tonic-gate  * sckm messages from the sckm driver and dispatches each message
947c478bd9Sstevel@tonic-gate  * to be processed synchronously.
957c478bd9Sstevel@tonic-gate  */
967c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)977c478bd9Sstevel@tonic-gate main(int argc, char **argv)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate 	int			opt;
1007c478bd9Sstevel@tonic-gate 	int			fd;
1017c478bd9Sstevel@tonic-gate 	sckm_ioctl_getreq_t	msg;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	/*
1057c478bd9Sstevel@tonic-gate 	 * Set defaults
1067c478bd9Sstevel@tonic-gate 	 */
1077c478bd9Sstevel@tonic-gate 	standalone = 0;
1087c478bd9Sstevel@tonic-gate 	debug = 0;
1097c478bd9Sstevel@tonic-gate 	mypid = getpid();
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	openlog("sckmd", LOG_CONS | LOG_NDELAY, LOG_DAEMON);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	/*
1147c478bd9Sstevel@tonic-gate 	 * Check command line options
1157c478bd9Sstevel@tonic-gate 	 */
1167c478bd9Sstevel@tonic-gate 	opterr = 0;	/* disable getopt error messages */
1177c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, OPT_STR)) != EOF) {
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 		switch (opt) {
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 		case 'd':
1227c478bd9Sstevel@tonic-gate 			debug++;
1237c478bd9Sstevel@tonic-gate 			break;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 		case 's':
1267c478bd9Sstevel@tonic-gate 			standalone++;
1277c478bd9Sstevel@tonic-gate 			break;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 		default:
1307c478bd9Sstevel@tonic-gate 			sckmd_log(LOG_ERR, "unknown command line option\n");
1317c478bd9Sstevel@tonic-gate 			exit(1);
1327c478bd9Sstevel@tonic-gate 		}
1337c478bd9Sstevel@tonic-gate 	}
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	sckmd_log(LOG_DEBUG, "starting sckmd...\n");
1367c478bd9Sstevel@tonic-gate 
137*7a17cfadSDan McDonald 	/*
138*7a17cfadSDan McDonald 	 * IPsec must get loaded in-kernel.  The easiest way to do this is
139*7a17cfadSDan McDonald 	 * to open (then close) a PF_KEY socket.
140*7a17cfadSDan McDonald 	 */
141*7a17cfadSDan McDonald 	if ((keysock = socket(PF_KEY, SOCK_RAW, SCKMD_CURR_PFKEY_VER)) == -1) {
142*7a17cfadSDan McDonald 		sckmd_log(LOG_DEBUG, "PF_KEY open for IPsec load failed: %s\n",
143*7a17cfadSDan McDonald 		    strerror(errno));
144*7a17cfadSDan McDonald 		exit(1);
145*7a17cfadSDan McDonald 	}
146*7a17cfadSDan McDonald 	(void) close(keysock);
147*7a17cfadSDan McDonald 	sckmd_log(LOG_ERR, "PF_KEY socket for IPsec load succeeded.\n");
148*7a17cfadSDan McDonald 
1497c478bd9Sstevel@tonic-gate 	/* must be root */
1507c478bd9Sstevel@tonic-gate 	if (geteuid() != 0) {
1517c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_ERR, "must run as root\n");
1527c478bd9Sstevel@tonic-gate 		exit(1);
1537c478bd9Sstevel@tonic-gate 	}
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	if (standalone == 0) {
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 		int	i;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 		for (i = 0; i < NOFILE; i++) {
1607c478bd9Sstevel@tonic-gate 			(void) close(i);
1617c478bd9Sstevel@tonic-gate 		}
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 		(void) chdir("/");
1647c478bd9Sstevel@tonic-gate 		(void) umask(0);
1657c478bd9Sstevel@tonic-gate 		if (fork() != 0) {
1667c478bd9Sstevel@tonic-gate 			exit(0);
1677c478bd9Sstevel@tonic-gate 		}
1687c478bd9Sstevel@tonic-gate 		(void) setpgrp();
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 		/* reinitialize syslog after closing all fds */
1717c478bd9Sstevel@tonic-gate 		openlog("sckmd", LOG_CONS | LOG_NDELAY, LOG_DAEMON);
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	/* open driver */
17525cf1a30Sjl 	if ((fd = open(KM_DEV, O_RDONLY)) == -1) {
17625cf1a30Sjl 		sckmd_log(LOG_ERR, "error initializing km driver: %s\n",
1777c478bd9Sstevel@tonic-gate 		    strerror(errno));
1787c478bd9Sstevel@tonic-gate 		exit(1);
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	/*
1827c478bd9Sstevel@tonic-gate 	 * Main processing loop
1837c478bd9Sstevel@tonic-gate 	 */
1847c478bd9Sstevel@tonic-gate 	for (;;) {
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 		/* initialize the ioctl request */
1877c478bd9Sstevel@tonic-gate 		(void) memset(&msg, 0, sizeof (sckm_ioctl_getreq_t));
1887c478bd9Sstevel@tonic-gate 		msg.buf = (caddr_t)msg_buf;
1897c478bd9Sstevel@tonic-gate 		(void) memset(&msg_buf, 0, SCKMD_MAX_MSG_SIZE);
1907c478bd9Sstevel@tonic-gate 		msg.buf_len = SCKMD_MAX_MSG_SIZE;
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 		/* wait for the next message */
1937c478bd9Sstevel@tonic-gate 		if (ioctl(fd, SCKM_IOCTL_GETREQ, &msg) == -1) {
1947c478bd9Sstevel@tonic-gate 			sckmd_log(LOG_ERR, "failed to receive sckm message: "
1957c478bd9Sstevel@tonic-gate 			    "%s\n", strerror(errno));
1967c478bd9Sstevel@tonic-gate 			continue;
1977c478bd9Sstevel@tonic-gate 		}
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 		/* pass the message to pf_key */
2007c478bd9Sstevel@tonic-gate 		if (process_sckm_req(fd, &msg) == -1) {
2017c478bd9Sstevel@tonic-gate 			sckmd_log(LOG_DEBUG, "error processing sckm message\n");
2027c478bd9Sstevel@tonic-gate 			continue;
2037c478bd9Sstevel@tonic-gate 		}
2047c478bd9Sstevel@tonic-gate 	}
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
2077c478bd9Sstevel@tonic-gate 	return (0);
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate /*
2127c478bd9Sstevel@tonic-gate  * process_sckm_req:
2137c478bd9Sstevel@tonic-gate  *
2147c478bd9Sstevel@tonic-gate  * Process a sckm request message. If the message is valid, pass the
2157c478bd9Sstevel@tonic-gate  * included SADB message to PF_KEY and return status to the sckm driver.
2167c478bd9Sstevel@tonic-gate  * The function only fails if it is unable to return a status message
2177c478bd9Sstevel@tonic-gate  * to the driver.
2187c478bd9Sstevel@tonic-gate  */
2197c478bd9Sstevel@tonic-gate static int
process_sckm_req(int fd,sckm_ioctl_getreq_t * msg)2207c478bd9Sstevel@tonic-gate process_sckm_req(int fd, sckm_ioctl_getreq_t *msg)
2217c478bd9Sstevel@tonic-gate {
2227c478bd9Sstevel@tonic-gate 	sckm_ioctl_status_t	reply;
2237c478bd9Sstevel@tonic-gate 	struct sadb_msg		*pfkey_msg;
2247c478bd9Sstevel@tonic-gate 	unsigned int		msg_ver;
2257c478bd9Sstevel@tonic-gate 	unsigned int		msg_type;
2267c478bd9Sstevel@tonic-gate 	unsigned int		msg_len;
2277c478bd9Sstevel@tonic-gate 	int			err;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	if (msg == NULL) {
2317c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_ERR, "invalid message\n");
2327c478bd9Sstevel@tonic-gate 		return (-1);
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	/* initialize a reply message */
2367c478bd9Sstevel@tonic-gate 	(void) memset(&reply, 0, sizeof (sckm_ioctl_status_t));
2377c478bd9Sstevel@tonic-gate 	reply.transid = msg->transid;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	/* currently, we only support sadb messages */
2407c478bd9Sstevel@tonic-gate 	if (msg->type != SCKM_IOCTL_REQ_SADB) {
2417c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_ERR, "unsupported message type (%d)\n",
2427c478bd9Sstevel@tonic-gate 		    msg->type);
2437c478bd9Sstevel@tonic-gate 		reply.status = SCKM_IOCTL_STAT_ERR_REQ;
2447c478bd9Sstevel@tonic-gate 		return (send_sckm_status(fd, &reply));
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	/* check that we have at least the sadb header */
2487c478bd9Sstevel@tonic-gate 	if (msg->buf_len < sizeof (struct sadb_msg)) {
2497c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_ERR, "incomplete sadb message received\n");
2507c478bd9Sstevel@tonic-gate 		reply.status = SCKM_IOCTL_STAT_ERR_REQ;
2517c478bd9Sstevel@tonic-gate 		return (send_sckm_status(fd, &reply));
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	/* LINTED Pointer Cast Alignment Warning */
2557c478bd9Sstevel@tonic-gate 	pfkey_msg = (struct sadb_msg *)msg->buf;
2567c478bd9Sstevel@tonic-gate 	msg_ver = pfkey_msg->sadb_msg_version;
2577c478bd9Sstevel@tonic-gate 	msg_len = SADB_64TO8(pfkey_msg->sadb_msg_len);
2587c478bd9Sstevel@tonic-gate 	msg_type = pfkey_msg->sadb_msg_type;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	/* check for an unsupported PF_KEY version */
2617c478bd9Sstevel@tonic-gate 	if ((msg_ver > SCKMD_CURR_PFKEY_VER) || (msg_ver < PF_KEY_V2)) {
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_ERR, "unsupported PF_KEY version (%d)\n",
2647c478bd9Sstevel@tonic-gate 		    msg_ver);
2657c478bd9Sstevel@tonic-gate 		reply.status = SCKM_IOCTL_STAT_ERR_VERSION;
2667c478bd9Sstevel@tonic-gate 		reply.sadb_msg_version = SCKMD_CURR_PFKEY_VER;
2677c478bd9Sstevel@tonic-gate 		return (send_sckm_status(fd, &reply));
2687c478bd9Sstevel@tonic-gate 	}
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	/* convert the PF_KEY message if necessary */
2717c478bd9Sstevel@tonic-gate 	if (msg_ver != SCKMD_CURR_PFKEY_VER) {
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 		if (convert_pfkey_msg(pfkey_msg) == -1) {
2747c478bd9Sstevel@tonic-gate 			reply.status = SCKM_IOCTL_STAT_ERR_VERSION;
2757c478bd9Sstevel@tonic-gate 			reply.sadb_msg_version = SCKMD_CURR_PFKEY_VER;
2767c478bd9Sstevel@tonic-gate 			return (send_sckm_status(fd, &reply));
2777c478bd9Sstevel@tonic-gate 		}
2787c478bd9Sstevel@tonic-gate 	}
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	/*
2817c478bd9Sstevel@tonic-gate 	 * Process the PF_KEY message
2827c478bd9Sstevel@tonic-gate 	 */
2837c478bd9Sstevel@tonic-gate 	pfkey_msg->sadb_msg_seq = ++seq;
2847c478bd9Sstevel@tonic-gate 	pfkey_msg->sadb_msg_pid = mypid;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	switch (msg_type) {
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	case SADB_UPDATE:
2897c478bd9Sstevel@tonic-gate 	case SADB_ADD:
2907c478bd9Sstevel@tonic-gate 	case SADB_DELETE:
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 		/*
2937c478bd9Sstevel@tonic-gate 		 * Only update, add, and delete are supported. Pass the
2947c478bd9Sstevel@tonic-gate 		 * message directly to PF_KEY.
2957c478bd9Sstevel@tonic-gate 		 */
2967c478bd9Sstevel@tonic-gate 		break;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	default:
2997c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_ERR, "received unsupported operation "
3007c478bd9Sstevel@tonic-gate 		    "from client (%d)\n", msg_type);
3017c478bd9Sstevel@tonic-gate 		reply.status = SCKM_IOCTL_STAT_ERR_SADB_TYPE;
3027c478bd9Sstevel@tonic-gate 		return (send_sckm_status(fd, &reply));
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	/* initialize global key socket */
3067c478bd9Sstevel@tonic-gate 	if ((keysock = socket(PF_KEY, SOCK_RAW, SCKMD_CURR_PFKEY_VER)) == -1) {
3077c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_ERR, "error initializing PF_KEY socket: %s\n",
3087c478bd9Sstevel@tonic-gate 		    strerror(errno));
3097c478bd9Sstevel@tonic-gate 		reply.status = SCKM_IOCTL_STAT_ERR_OTHER;
3107c478bd9Sstevel@tonic-gate 		return (send_sckm_status(fd, &reply));
3117c478bd9Sstevel@tonic-gate 	}
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	/* send the PF_KEY message */
3147c478bd9Sstevel@tonic-gate 	if (write(keysock, pfkey_msg, msg_len) != msg_len) {
3157c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_ERR, "PF_KEY write failed\n");
3167c478bd9Sstevel@tonic-gate 		reply.status = SCKM_IOCTL_STAT_ERR_OTHER;
3177c478bd9Sstevel@tonic-gate 		close(keysock);
3187c478bd9Sstevel@tonic-gate 		return (send_sckm_status(fd, &reply));
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/* wait for key engine reply */
3227c478bd9Sstevel@tonic-gate 	if (get_pfkey_reply(pfkey_msg->sadb_msg_seq, msg_type, &err) == -1) {
3237c478bd9Sstevel@tonic-gate 		reply.status = err;
3247c478bd9Sstevel@tonic-gate 		if (err == SCKM_IOCTL_STAT_ERR_PFKEY) {
3257c478bd9Sstevel@tonic-gate 			reply.sadb_msg_errno = errno;
3267c478bd9Sstevel@tonic-gate 		}
3277c478bd9Sstevel@tonic-gate 	} else {
3287c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_DEBUG, "PF_KEY operation succeeded\n");
3297c478bd9Sstevel@tonic-gate 		reply.status = SCKM_IOCTL_STAT_SUCCESS;
3307c478bd9Sstevel@tonic-gate 	}
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	close(keysock);
3337c478bd9Sstevel@tonic-gate 	return (send_sckm_status(fd, &reply));
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate /*
3387c478bd9Sstevel@tonic-gate  * send_sckm_status:
3397c478bd9Sstevel@tonic-gate  *
3407c478bd9Sstevel@tonic-gate  * Send a sckm status message to the sckm driver
3417c478bd9Sstevel@tonic-gate  */
3427c478bd9Sstevel@tonic-gate static int
send_sckm_status(int fd,sckm_ioctl_status_t * msg)3437c478bd9Sstevel@tonic-gate send_sckm_status(int fd, sckm_ioctl_status_t *msg)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SCKM_IOCTL_STATUS, msg) == -1) {
3467c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_ERR, "error sending sckm status message: %s\n",
3477c478bd9Sstevel@tonic-gate 		    strerror(errno));
3487c478bd9Sstevel@tonic-gate 		return (-1);
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	return (0);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate /*
3567c478bd9Sstevel@tonic-gate  * get_pfkey_reply:
3577c478bd9Sstevel@tonic-gate  *
3587c478bd9Sstevel@tonic-gate  * Wait for a reply from PF_KEY. Get the reply from the socket using
3597c478bd9Sstevel@tonic-gate  * the global file desciptor 'keysock'. If PF_KEY returns an error,
3607c478bd9Sstevel@tonic-gate  * the global errno is set to the error returned in the reply message.
3617c478bd9Sstevel@tonic-gate  * If an error occurs, the parameter 'err' is set to one of the error
3627c478bd9Sstevel@tonic-gate  * codes prefixed by SCKM_IOCTL_STAT_ERR to indicate the overall status
3637c478bd9Sstevel@tonic-gate  * of the operation.
3647c478bd9Sstevel@tonic-gate  */
3657c478bd9Sstevel@tonic-gate static int
get_pfkey_reply(uint32_t req_seq,uint8_t req_type,int * err)3667c478bd9Sstevel@tonic-gate get_pfkey_reply(uint32_t req_seq, uint8_t req_type, int *err)
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate 	int		timeout;
3697c478bd9Sstevel@tonic-gate 	int		pollstatus;
3707c478bd9Sstevel@tonic-gate 	clock_t		before;
3717c478bd9Sstevel@tonic-gate 	clock_t		after;
3727c478bd9Sstevel@tonic-gate 	double		diff;
3737c478bd9Sstevel@tonic-gate 	struct tms	unused;
3747c478bd9Sstevel@tonic-gate 	struct pollfd	pfd;
3757c478bd9Sstevel@tonic-gate 	struct sadb_msg *msg;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	static char *pfkey_msg_type[] = {
3787c478bd9Sstevel@tonic-gate 		"RESERVED",
3797c478bd9Sstevel@tonic-gate 		"GETSPI",
3807c478bd9Sstevel@tonic-gate 		"UPDATE",
3817c478bd9Sstevel@tonic-gate 		"ADD",
3827c478bd9Sstevel@tonic-gate 		"DELETE",
3837c478bd9Sstevel@tonic-gate 		"GET",
3847c478bd9Sstevel@tonic-gate 		"ACQUIRE",
3857c478bd9Sstevel@tonic-gate 		"REGISTER",
3867c478bd9Sstevel@tonic-gate 		"EXPIRE",
3877c478bd9Sstevel@tonic-gate 		"FLUSH",
3887c478bd9Sstevel@tonic-gate 		"DUMP",
3897c478bd9Sstevel@tonic-gate 		"X_PROMISC",
3907c478bd9Sstevel@tonic-gate 		"X_INVERSE_ACQUIRE",
3917c478bd9Sstevel@tonic-gate 	};
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	sckmd_log(LOG_DEBUG, "waiting for key engine reply\n");
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	timeout = SCKMD_PFKEY_TIMEOUT;
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	pfd.fd = keysock;
3997c478bd9Sstevel@tonic-gate 	pfd.events = POLLIN;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	while (timeout > 0) {
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 		before = times(&unused);
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 		pfd.revents = 0;
4067c478bd9Sstevel@tonic-gate 		pollstatus = poll(&pfd, 1, timeout);
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 		/* check for a timeout */
4097c478bd9Sstevel@tonic-gate 		if (pollstatus == 0) {
4107c478bd9Sstevel@tonic-gate 			sckmd_log(LOG_NOTICE, "timed out waiting for PF_KEY "
4117c478bd9Sstevel@tonic-gate 			    "reply\n");
4127c478bd9Sstevel@tonic-gate 			*err = SCKM_IOCTL_STAT_ERR_TIMEOUT;
4137c478bd9Sstevel@tonic-gate 			return (-1);
4147c478bd9Sstevel@tonic-gate 		}
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 		/* read in the next PF_KEY message */
4177c478bd9Sstevel@tonic-gate 		msg = read_pfkey_msg();
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 		if (msg == NULL) {
4207c478bd9Sstevel@tonic-gate 			*err = SCKM_IOCTL_STAT_ERR_OTHER;
4217c478bd9Sstevel@tonic-gate 			return (-1);
4227c478bd9Sstevel@tonic-gate 		}
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 		/* check if the message is intended for us */
4257c478bd9Sstevel@tonic-gate 		if (msg->sadb_msg_seq == req_seq &&
4267c478bd9Sstevel@tonic-gate 		    msg->sadb_msg_pid == mypid) {
4277c478bd9Sstevel@tonic-gate 			break;
4287c478bd9Sstevel@tonic-gate 		}
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 		after = times(&unused);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 		diff = (double)(after - before)/(double)CLK_TCK;
4337c478bd9Sstevel@tonic-gate 		timeout -= (int)(diff * 1000);
4347c478bd9Sstevel@tonic-gate 	}
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	/* check for a timeout */
4377c478bd9Sstevel@tonic-gate 	if (timeout <= 0) {
4387c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_NOTICE, "timed out waiting for PF_KEY "
4397c478bd9Sstevel@tonic-gate 		    "reply\n");
4407c478bd9Sstevel@tonic-gate 		*err = SCKM_IOCTL_STAT_ERR_TIMEOUT;
4417c478bd9Sstevel@tonic-gate 		return (-1);
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	/* did we get what we were expecting? */
4457c478bd9Sstevel@tonic-gate 	if (msg->sadb_msg_type != req_type) {
4467c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_ERR, "unexpected message type from PF_KEY: %d\n",
4477c478bd9Sstevel@tonic-gate 		    msg->sadb_msg_type);
4487c478bd9Sstevel@tonic-gate 		*err = SCKM_IOCTL_STAT_ERR_OTHER;
4497c478bd9Sstevel@tonic-gate 		return (-1);
4507c478bd9Sstevel@tonic-gate 	}
4517c478bd9Sstevel@tonic-gate 
4528c74a1f9Sraghuram 	/*
4538c74a1f9Sraghuram 	 * Check for errors in SADB message, but ignore the
4548c74a1f9Sraghuram 	 * ESRCH error for DELETE operation. This can happen if the SP
4558c74a1f9Sraghuram 	 * sends a DELETE request first before sending the ADD
4568c74a1f9Sraghuram 	 * request, just to make sure the keys are installed without a failure.
4578c74a1f9Sraghuram 	 */
4588c74a1f9Sraghuram 	if ((msg->sadb_msg_errno != 0) && !((msg->sadb_msg_errno == ESRCH) &&
4598c74a1f9Sraghuram 	    (msg->sadb_msg_type == SADB_DELETE))) {
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 		char	   unknown_type_str[16];
4627c478bd9Sstevel@tonic-gate 		int	   unknown_type = 0;
4637c478bd9Sstevel@tonic-gate 		int	   arr_sz;
4647c478bd9Sstevel@tonic-gate 		const char *diagnostic_str;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		arr_sz  = sizeof (pfkey_msg_type) / sizeof (*pfkey_msg_type);
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 		/* generate unknown type string, if necessary */
4697c478bd9Sstevel@tonic-gate 		if (msg->sadb_msg_type >= arr_sz) {
4707c478bd9Sstevel@tonic-gate 			(void) snprintf(unknown_type_str,
4717c478bd9Sstevel@tonic-gate 			    sizeof (unknown_type_str), "UNKNOWN-%d",
4727c478bd9Sstevel@tonic-gate 			    msg->sadb_msg_type);
4737c478bd9Sstevel@tonic-gate 			unknown_type = 1;
4747c478bd9Sstevel@tonic-gate 		}
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 		/* use libipsecutil to lookup the SADB diagnostic string */
4777c478bd9Sstevel@tonic-gate 		diagnostic_str = keysock_diag(msg->sadb_x_msg_diagnostic);
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_ERR, "PF_KEY error: type=%s, errno=%d: %s, "
4807c478bd9Sstevel@tonic-gate 		    "diagnostic code=%d: %s\n",
4817c478bd9Sstevel@tonic-gate 		    (unknown_type) ? unknown_type_str :
4827c478bd9Sstevel@tonic-gate 		    pfkey_msg_type[msg->sadb_msg_type],
4837c478bd9Sstevel@tonic-gate 		    msg->sadb_msg_errno, strerror(msg->sadb_msg_errno),
4847c478bd9Sstevel@tonic-gate 		    msg->sadb_x_msg_diagnostic, diagnostic_str);
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 		*err = SCKM_IOCTL_STAT_ERR_PFKEY;
4877c478bd9Sstevel@tonic-gate 		errno = msg->sadb_msg_errno;
4887c478bd9Sstevel@tonic-gate 		return (-1);
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	return (0);
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate /*
4967c478bd9Sstevel@tonic-gate  * read_pfkey_msg:
4977c478bd9Sstevel@tonic-gate  *
4987c478bd9Sstevel@tonic-gate  * Get a PF_KEY message from the socket using the global file descriptor
4997c478bd9Sstevel@tonic-gate  * 'keysock'. Data is stored in the global buffer 'msg_buf'. The function
5007c478bd9Sstevel@tonic-gate  * returns a pointer to the next PF_KEY message. Note that this is not
5017c478bd9Sstevel@tonic-gate  * necessarily at the start of 'msg_buf'. NULL is returned for errors.
5027c478bd9Sstevel@tonic-gate  */
5037c478bd9Sstevel@tonic-gate static struct sadb_msg *
read_pfkey_msg(void)5047c478bd9Sstevel@tonic-gate read_pfkey_msg(void)
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 	static uint64_t	*offset;
5077c478bd9Sstevel@tonic-gate 	static int	len;
5087c478bd9Sstevel@tonic-gate 	struct sadb_msg	*retval;
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	/* Assume offset and len are initialized to NULL and 0 */
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if ((offset == NULL) || (offset - len == msg_buf)) {
5147c478bd9Sstevel@tonic-gate 		/* read a new block from the socket. */
5157c478bd9Sstevel@tonic-gate 		len = read(keysock, &msg_buf, sizeof (msg_buf));
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 		if (len == -1) {
5187c478bd9Sstevel@tonic-gate 			sckmd_log(LOG_ERR, "PF_KEY read: %s\n",
5197c478bd9Sstevel@tonic-gate 			    strerror(errno));
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 			offset = NULL;
5227c478bd9Sstevel@tonic-gate 			return (NULL);
5237c478bd9Sstevel@tonic-gate 		}
5247c478bd9Sstevel@tonic-gate 		offset = msg_buf;
5257c478bd9Sstevel@tonic-gate 		len = SADB_8TO64(len);
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	retval = (struct sadb_msg *)offset;
5297c478bd9Sstevel@tonic-gate 	offset += retval->sadb_msg_len;
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	if (offset > msg_buf + len) {
5327c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_ERR, "PF_KEY read: message corruption, "
5337c478bd9Sstevel@tonic-gate 		    "message length %d exceeds boundary %d\n",
5347c478bd9Sstevel@tonic-gate 		    SADB_64TO8(retval->sadb_msg_len),
5357c478bd9Sstevel@tonic-gate 		    SADB_64TO8((msg_buf + len) - (uint64_t *)retval));
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 		offset = NULL;
5387c478bd9Sstevel@tonic-gate 		return (NULL);
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	return (retval);
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate /*
5467c478bd9Sstevel@tonic-gate  * convert_pfkey_msg:
5477c478bd9Sstevel@tonic-gate  *
5487c478bd9Sstevel@tonic-gate  * Convert a lower version PF_KEY message to the current version
5497c478bd9Sstevel@tonic-gate  * being used by sckmd.
5507c478bd9Sstevel@tonic-gate  *
5517c478bd9Sstevel@tonic-gate  * Currently, there is only one implemented version of PF_KEY (v2).
5527c478bd9Sstevel@tonic-gate  * If future versions are added to the PF_KEY specification (RFC 2367),
5537c478bd9Sstevel@tonic-gate  * this function should be updated to provide backwards compatibility
5547c478bd9Sstevel@tonic-gate  * with version 2 and above.
5557c478bd9Sstevel@tonic-gate  */
5567c478bd9Sstevel@tonic-gate static int
convert_pfkey_msg(struct sadb_msg * msg)5577c478bd9Sstevel@tonic-gate convert_pfkey_msg(struct sadb_msg *msg)
5587c478bd9Sstevel@tonic-gate {
5597c478bd9Sstevel@tonic-gate 	sckmd_log(LOG_DEBUG, "PF_KEY conversion necessary...\n");
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	switch (msg->sadb_msg_version) {
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	case PF_KEY_V2:
5647c478bd9Sstevel@tonic-gate 		/*
5657c478bd9Sstevel@tonic-gate 		 * Current supported version:
5667c478bd9Sstevel@tonic-gate 		 * No conversion required
5677c478bd9Sstevel@tonic-gate 		 */
5687c478bd9Sstevel@tonic-gate 		break;
5697c478bd9Sstevel@tonic-gate 	default:
5707c478bd9Sstevel@tonic-gate 		sckmd_log(LOG_ERR, "No conversion possible for "
5717c478bd9Sstevel@tonic-gate 		    "PF_KEY version %d\n", msg->sadb_msg_version);
5727c478bd9Sstevel@tonic-gate 		return (-1);
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	return (0);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate /*
5807c478bd9Sstevel@tonic-gate  * sckmd_log:
5817c478bd9Sstevel@tonic-gate  *
5827c478bd9Sstevel@tonic-gate  * Log a message using the syslog facility. If sckmd is running in
5837c478bd9Sstevel@tonic-gate  * standalone mode (global flag 'standalone' set), messages are also
5847c478bd9Sstevel@tonic-gate  * sent to stderr.
5857c478bd9Sstevel@tonic-gate  */
5867c478bd9Sstevel@tonic-gate static void
sckmd_log(int priority,char * fmt,...)5877c478bd9Sstevel@tonic-gate sckmd_log(int priority, char *fmt, ...)
5887c478bd9Sstevel@tonic-gate {
5897c478bd9Sstevel@tonic-gate 	va_list	vap;
5907c478bd9Sstevel@tonic-gate 	char	err[SCKMD_ERR_MSG_SIZE];
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	/* if this is a debug message, check if debugging is enabled */
5947c478bd9Sstevel@tonic-gate 	if ((priority == LOG_DEBUG) && (debug == 0)) {
5957c478bd9Sstevel@tonic-gate 		return;
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	va_start(vap, fmt);
5997c478bd9Sstevel@tonic-gate 	vsnprintf(err, SCKMD_ERR_MSG_SIZE, fmt, vap);
6007c478bd9Sstevel@tonic-gate 	va_end(vap);
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	/* send message to stderr if in standalone mode */
6037c478bd9Sstevel@tonic-gate 	if (standalone != 0) {
6047c478bd9Sstevel@tonic-gate 		fprintf(stderr, err);
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	/* always log the message */
6087c478bd9Sstevel@tonic-gate 	syslog(priority, err);
6097c478bd9Sstevel@tonic-gate }
610