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 525cf1a30Sjl139090 * Common Development and Distribution License (the "License"). 625cf1a30Sjl139090 * 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 6325cf1a30Sjl139090 #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 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 */ 17525cf1a30Sjl139090 if ((fd = open(KM_DEV, O_RDONLY)) == -1) { 17625cf1a30Sjl139090 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 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 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 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 * 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 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 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