1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * sckmd - Starcat Key Management Daemon 28 * 29 * The sckmd is a daemon that runs on a domain and is responsible for 30 * establishing security associations (SAs) for secure communication 31 * with the System Controller (SC). All SAs are created on the SC 32 * and propogated to the sckmd through the sckm driver running on 33 * the domain. The sckmd then passes the SA to the key engine via the 34 * PF_KEY interface. 35 */ 36 37 #include <stdlib.h> 38 #include <stdio.h> 39 #include <stdarg.h> 40 #include <unistd.h> 41 #include <fcntl.h> 42 #include <string.h> 43 #include <errno.h> 44 #include <syslog.h> 45 #include <sys/types.h> 46 #include <sys/stat.h> 47 #include <sys/times.h> 48 #include <sys/fcntl.h> 49 #include <sys/socket.h> 50 #include <net/pfkeyv2.h> 51 #include <netinet/in.h> 52 #include <ipsec_util.h> 53 54 #include <sys/sckm_io.h> 55 56 57 #ifdef SCKMD_DEBUG 58 #define OPT_STR "ds" 59 #else /* SCKMD_DEBUG */ 60 #define OPT_STR "" 61 #endif /* SCKMD_DEBUG */ 62 63 #define KM_DEV "/dev/kmdrv" 64 65 #define SCKMD_MAX_MSG_SIZE 1024 66 #define SCKMD_ERR_MSG_SIZE 512 67 #define SCKMD_MSG_HDR_SIZE sizeof (struct sadb_msg) 68 69 #define SCKMD_CURR_PFKEY_VER PF_KEY_V2 70 #define SCKMD_PFKEY_TIMEOUT 3000 /* 3 seconds */ 71 72 73 static pid_t mypid; 74 static int standalone; 75 static int debug; 76 static int keysock; 77 static uint32_t seq = 0; 78 static uint64_t msg_buf[SCKMD_MAX_MSG_SIZE]; 79 80 81 static int process_sckm_req(int fd, sckm_ioctl_getreq_t *msg); 82 static int send_sckm_status(int fd, sckm_ioctl_status_t *msg); 83 static int get_pfkey_reply(uint32_t req_seq, uint8_t req_type, int *err); 84 static struct sadb_msg *read_pfkey_msg(void); 85 static int convert_pfkey_msg(struct sadb_msg *msg); 86 static void sckmd_log(int priority, char *fmt, ...); 87 88 89 /* 90 * main: 91 * 92 * Initialize sckmd and enter an infinite loop. The loop waits for 93 * sckm messages from the sckm driver and dispatches each message 94 * to be processed synchronously. 95 */ 96 int 97 main(int argc, char **argv) 98 { 99 int opt; 100 int fd; 101 sckm_ioctl_getreq_t msg; 102 103 104 /* 105 * Set defaults 106 */ 107 standalone = 0; 108 debug = 0; 109 mypid = getpid(); 110 111 openlog("sckmd", LOG_CONS | LOG_NDELAY, LOG_DAEMON); 112 113 /* 114 * Check command line options 115 */ 116 opterr = 0; /* disable getopt error messages */ 117 while ((opt = getopt(argc, argv, OPT_STR)) != EOF) { 118 119 switch (opt) { 120 121 case 'd': 122 debug++; 123 break; 124 125 case 's': 126 standalone++; 127 break; 128 129 default: 130 sckmd_log(LOG_ERR, "unknown command line option\n"); 131 exit(1); 132 } 133 } 134 135 sckmd_log(LOG_DEBUG, "starting sckmd...\n"); 136 137 /* 138 * IPsec must get loaded in-kernel. The easiest way to do this is 139 * to open (then close) a PF_KEY socket. 140 */ 141 if ((keysock = socket(PF_KEY, SOCK_RAW, SCKMD_CURR_PFKEY_VER)) == -1) { 142 sckmd_log(LOG_DEBUG, "PF_KEY open for IPsec load failed: %s\n", 143 strerror(errno)); 144 exit(1); 145 } 146 (void) close(keysock); 147 sckmd_log(LOG_ERR, "PF_KEY socket for IPsec load succeeded.\n"); 148 149 /* must be root */ 150 if (geteuid() != 0) { 151 sckmd_log(LOG_ERR, "must run as root\n"); 152 exit(1); 153 } 154 155 if (standalone == 0) { 156 157 int i; 158 159 for (i = 0; i < NOFILE; i++) { 160 (void) close(i); 161 } 162 163 (void) chdir("/"); 164 (void) umask(0); 165 if (fork() != 0) { 166 exit(0); 167 } 168 (void) setpgrp(); 169 170 /* reinitialize syslog after closing all fds */ 171 openlog("sckmd", LOG_CONS | LOG_NDELAY, LOG_DAEMON); 172 } 173 174 /* open driver */ 175 if ((fd = open(KM_DEV, O_RDONLY)) == -1) { 176 sckmd_log(LOG_ERR, "error initializing km driver: %s\n", 177 strerror(errno)); 178 exit(1); 179 } 180 181 /* 182 * Main processing loop 183 */ 184 for (;;) { 185 186 /* initialize the ioctl request */ 187 (void) memset(&msg, 0, sizeof (sckm_ioctl_getreq_t)); 188 msg.buf = (caddr_t)msg_buf; 189 (void) memset(&msg_buf, 0, SCKMD_MAX_MSG_SIZE); 190 msg.buf_len = SCKMD_MAX_MSG_SIZE; 191 192 /* wait for the next message */ 193 if (ioctl(fd, SCKM_IOCTL_GETREQ, &msg) == -1) { 194 sckmd_log(LOG_ERR, "failed to receive sckm message: " 195 "%s\n", strerror(errno)); 196 continue; 197 } 198 199 /* pass the message to pf_key */ 200 if (process_sckm_req(fd, &msg) == -1) { 201 sckmd_log(LOG_DEBUG, "error processing sckm message\n"); 202 continue; 203 } 204 } 205 206 /*NOTREACHED*/ 207 return (0); 208 } 209 210 211 /* 212 * process_sckm_req: 213 * 214 * Process a sckm request message. If the message is valid, pass the 215 * included SADB message to PF_KEY and return status to the sckm driver. 216 * The function only fails if it is unable to return a status message 217 * to the driver. 218 */ 219 static int 220 process_sckm_req(int fd, sckm_ioctl_getreq_t *msg) 221 { 222 sckm_ioctl_status_t reply; 223 struct sadb_msg *pfkey_msg; 224 unsigned int msg_ver; 225 unsigned int msg_type; 226 unsigned int msg_len; 227 int err; 228 229 230 if (msg == NULL) { 231 sckmd_log(LOG_ERR, "invalid message\n"); 232 return (-1); 233 } 234 235 /* initialize a reply message */ 236 (void) memset(&reply, 0, sizeof (sckm_ioctl_status_t)); 237 reply.transid = msg->transid; 238 239 /* currently, we only support sadb messages */ 240 if (msg->type != SCKM_IOCTL_REQ_SADB) { 241 sckmd_log(LOG_ERR, "unsupported message type (%d)\n", 242 msg->type); 243 reply.status = SCKM_IOCTL_STAT_ERR_REQ; 244 return (send_sckm_status(fd, &reply)); 245 } 246 247 /* check that we have at least the sadb header */ 248 if (msg->buf_len < sizeof (struct sadb_msg)) { 249 sckmd_log(LOG_ERR, "incomplete sadb message received\n"); 250 reply.status = SCKM_IOCTL_STAT_ERR_REQ; 251 return (send_sckm_status(fd, &reply)); 252 } 253 254 /* LINTED Pointer Cast Alignment Warning */ 255 pfkey_msg = (struct sadb_msg *)msg->buf; 256 msg_ver = pfkey_msg->sadb_msg_version; 257 msg_len = SADB_64TO8(pfkey_msg->sadb_msg_len); 258 msg_type = pfkey_msg->sadb_msg_type; 259 260 /* check for an unsupported PF_KEY version */ 261 if ((msg_ver > SCKMD_CURR_PFKEY_VER) || (msg_ver < PF_KEY_V2)) { 262 263 sckmd_log(LOG_ERR, "unsupported PF_KEY version (%d)\n", 264 msg_ver); 265 reply.status = SCKM_IOCTL_STAT_ERR_VERSION; 266 reply.sadb_msg_version = SCKMD_CURR_PFKEY_VER; 267 return (send_sckm_status(fd, &reply)); 268 } 269 270 /* convert the PF_KEY message if necessary */ 271 if (msg_ver != SCKMD_CURR_PFKEY_VER) { 272 273 if (convert_pfkey_msg(pfkey_msg) == -1) { 274 reply.status = SCKM_IOCTL_STAT_ERR_VERSION; 275 reply.sadb_msg_version = SCKMD_CURR_PFKEY_VER; 276 return (send_sckm_status(fd, &reply)); 277 } 278 } 279 280 /* 281 * Process the PF_KEY message 282 */ 283 pfkey_msg->sadb_msg_seq = ++seq; 284 pfkey_msg->sadb_msg_pid = mypid; 285 286 switch (msg_type) { 287 288 case SADB_UPDATE: 289 case SADB_ADD: 290 case SADB_DELETE: 291 292 /* 293 * Only update, add, and delete are supported. Pass the 294 * message directly to PF_KEY. 295 */ 296 break; 297 298 default: 299 sckmd_log(LOG_ERR, "received unsupported operation " 300 "from client (%d)\n", msg_type); 301 reply.status = SCKM_IOCTL_STAT_ERR_SADB_TYPE; 302 return (send_sckm_status(fd, &reply)); 303 } 304 305 /* initialize global key socket */ 306 if ((keysock = socket(PF_KEY, SOCK_RAW, SCKMD_CURR_PFKEY_VER)) == -1) { 307 sckmd_log(LOG_ERR, "error initializing PF_KEY socket: %s\n", 308 strerror(errno)); 309 reply.status = SCKM_IOCTL_STAT_ERR_OTHER; 310 return (send_sckm_status(fd, &reply)); 311 } 312 313 /* send the PF_KEY message */ 314 if (write(keysock, pfkey_msg, msg_len) != msg_len) { 315 sckmd_log(LOG_ERR, "PF_KEY write failed\n"); 316 reply.status = SCKM_IOCTL_STAT_ERR_OTHER; 317 close(keysock); 318 return (send_sckm_status(fd, &reply)); 319 } 320 321 /* wait for key engine reply */ 322 if (get_pfkey_reply(pfkey_msg->sadb_msg_seq, msg_type, &err) == -1) { 323 reply.status = err; 324 if (err == SCKM_IOCTL_STAT_ERR_PFKEY) { 325 reply.sadb_msg_errno = errno; 326 } 327 } else { 328 sckmd_log(LOG_DEBUG, "PF_KEY operation succeeded\n"); 329 reply.status = SCKM_IOCTL_STAT_SUCCESS; 330 } 331 332 close(keysock); 333 return (send_sckm_status(fd, &reply)); 334 } 335 336 337 /* 338 * send_sckm_status: 339 * 340 * Send a sckm status message to the sckm driver 341 */ 342 static int 343 send_sckm_status(int fd, sckm_ioctl_status_t *msg) 344 { 345 if (ioctl(fd, SCKM_IOCTL_STATUS, msg) == -1) { 346 sckmd_log(LOG_ERR, "error sending sckm status message: %s\n", 347 strerror(errno)); 348 return (-1); 349 } 350 351 return (0); 352 } 353 354 355 /* 356 * get_pfkey_reply: 357 * 358 * Wait for a reply from PF_KEY. Get the reply from the socket using 359 * the global file desciptor 'keysock'. If PF_KEY returns an error, 360 * the global errno is set to the error returned in the reply message. 361 * If an error occurs, the parameter 'err' is set to one of the error 362 * codes prefixed by SCKM_IOCTL_STAT_ERR to indicate the overall status 363 * of the operation. 364 */ 365 static int 366 get_pfkey_reply(uint32_t req_seq, uint8_t req_type, int *err) 367 { 368 int timeout; 369 int pollstatus; 370 clock_t before; 371 clock_t after; 372 double diff; 373 struct tms unused; 374 struct pollfd pfd; 375 struct sadb_msg *msg; 376 377 static char *pfkey_msg_type[] = { 378 "RESERVED", 379 "GETSPI", 380 "UPDATE", 381 "ADD", 382 "DELETE", 383 "GET", 384 "ACQUIRE", 385 "REGISTER", 386 "EXPIRE", 387 "FLUSH", 388 "DUMP", 389 "X_PROMISC", 390 "X_INVERSE_ACQUIRE", 391 }; 392 393 394 sckmd_log(LOG_DEBUG, "waiting for key engine reply\n"); 395 396 timeout = SCKMD_PFKEY_TIMEOUT; 397 398 pfd.fd = keysock; 399 pfd.events = POLLIN; 400 401 while (timeout > 0) { 402 403 before = times(&unused); 404 405 pfd.revents = 0; 406 pollstatus = poll(&pfd, 1, timeout); 407 408 /* check for a timeout */ 409 if (pollstatus == 0) { 410 sckmd_log(LOG_NOTICE, "timed out waiting for PF_KEY " 411 "reply\n"); 412 *err = SCKM_IOCTL_STAT_ERR_TIMEOUT; 413 return (-1); 414 } 415 416 /* read in the next PF_KEY message */ 417 msg = read_pfkey_msg(); 418 419 if (msg == NULL) { 420 *err = SCKM_IOCTL_STAT_ERR_OTHER; 421 return (-1); 422 } 423 424 /* check if the message is intended for us */ 425 if (msg->sadb_msg_seq == req_seq && 426 msg->sadb_msg_pid == mypid) { 427 break; 428 } 429 430 after = times(&unused); 431 432 diff = (double)(after - before)/(double)CLK_TCK; 433 timeout -= (int)(diff * 1000); 434 } 435 436 /* check for a timeout */ 437 if (timeout <= 0) { 438 sckmd_log(LOG_NOTICE, "timed out waiting for PF_KEY " 439 "reply\n"); 440 *err = SCKM_IOCTL_STAT_ERR_TIMEOUT; 441 return (-1); 442 } 443 444 /* did we get what we were expecting? */ 445 if (msg->sadb_msg_type != req_type) { 446 sckmd_log(LOG_ERR, "unexpected message type from PF_KEY: %d\n", 447 msg->sadb_msg_type); 448 *err = SCKM_IOCTL_STAT_ERR_OTHER; 449 return (-1); 450 } 451 452 /* 453 * Check for errors in SADB message, but ignore the 454 * ESRCH error for DELETE operation. This can happen if the SP 455 * sends a DELETE request first before sending the ADD 456 * request, just to make sure the keys are installed without a failure. 457 */ 458 if ((msg->sadb_msg_errno != 0) && !((msg->sadb_msg_errno == ESRCH) && 459 (msg->sadb_msg_type == SADB_DELETE))) { 460 461 char unknown_type_str[16]; 462 int unknown_type = 0; 463 int arr_sz; 464 const char *diagnostic_str; 465 466 arr_sz = sizeof (pfkey_msg_type) / sizeof (*pfkey_msg_type); 467 468 /* generate unknown type string, if necessary */ 469 if (msg->sadb_msg_type >= arr_sz) { 470 (void) snprintf(unknown_type_str, 471 sizeof (unknown_type_str), "UNKNOWN-%d", 472 msg->sadb_msg_type); 473 unknown_type = 1; 474 } 475 476 /* use libipsecutil to lookup the SADB diagnostic string */ 477 diagnostic_str = keysock_diag(msg->sadb_x_msg_diagnostic); 478 479 sckmd_log(LOG_ERR, "PF_KEY error: type=%s, errno=%d: %s, " 480 "diagnostic code=%d: %s\n", 481 (unknown_type) ? unknown_type_str : 482 pfkey_msg_type[msg->sadb_msg_type], 483 msg->sadb_msg_errno, strerror(msg->sadb_msg_errno), 484 msg->sadb_x_msg_diagnostic, diagnostic_str); 485 486 *err = SCKM_IOCTL_STAT_ERR_PFKEY; 487 errno = msg->sadb_msg_errno; 488 return (-1); 489 } 490 491 return (0); 492 } 493 494 495 /* 496 * read_pfkey_msg: 497 * 498 * Get a PF_KEY message from the socket using the global file descriptor 499 * 'keysock'. Data is stored in the global buffer 'msg_buf'. The function 500 * returns a pointer to the next PF_KEY message. Note that this is not 501 * necessarily at the start of 'msg_buf'. NULL is returned for errors. 502 */ 503 static struct sadb_msg * 504 read_pfkey_msg(void) 505 { 506 static uint64_t *offset; 507 static int len; 508 struct sadb_msg *retval; 509 510 511 /* Assume offset and len are initialized to NULL and 0 */ 512 513 if ((offset == NULL) || (offset - len == msg_buf)) { 514 /* read a new block from the socket. */ 515 len = read(keysock, &msg_buf, sizeof (msg_buf)); 516 517 if (len == -1) { 518 sckmd_log(LOG_ERR, "PF_KEY read: %s\n", 519 strerror(errno)); 520 521 offset = NULL; 522 return (NULL); 523 } 524 offset = msg_buf; 525 len = SADB_8TO64(len); 526 } 527 528 retval = (struct sadb_msg *)offset; 529 offset += retval->sadb_msg_len; 530 531 if (offset > msg_buf + len) { 532 sckmd_log(LOG_ERR, "PF_KEY read: message corruption, " 533 "message length %d exceeds boundary %d\n", 534 SADB_64TO8(retval->sadb_msg_len), 535 SADB_64TO8((msg_buf + len) - (uint64_t *)retval)); 536 537 offset = NULL; 538 return (NULL); 539 } 540 541 return (retval); 542 } 543 544 545 /* 546 * convert_pfkey_msg: 547 * 548 * Convert a lower version PF_KEY message to the current version 549 * being used by sckmd. 550 * 551 * Currently, there is only one implemented version of PF_KEY (v2). 552 * If future versions are added to the PF_KEY specification (RFC 2367), 553 * this function should be updated to provide backwards compatibility 554 * with version 2 and above. 555 */ 556 static int 557 convert_pfkey_msg(struct sadb_msg *msg) 558 { 559 sckmd_log(LOG_DEBUG, "PF_KEY conversion necessary...\n"); 560 561 switch (msg->sadb_msg_version) { 562 563 case PF_KEY_V2: 564 /* 565 * Current supported version: 566 * No conversion required 567 */ 568 break; 569 default: 570 sckmd_log(LOG_ERR, "No conversion possible for " 571 "PF_KEY version %d\n", msg->sadb_msg_version); 572 return (-1); 573 } 574 575 return (0); 576 } 577 578 579 /* 580 * sckmd_log: 581 * 582 * Log a message using the syslog facility. If sckmd is running in 583 * standalone mode (global flag 'standalone' set), messages are also 584 * sent to stderr. 585 */ 586 static void 587 sckmd_log(int priority, char *fmt, ...) 588 { 589 va_list vap; 590 char err[SCKMD_ERR_MSG_SIZE]; 591 592 593 /* if this is a debug message, check if debugging is enabled */ 594 if ((priority == LOG_DEBUG) && (debug == 0)) { 595 return; 596 } 597 598 va_start(vap, fmt); 599 vsnprintf(err, SCKMD_ERR_MSG_SIZE, fmt, vap); 600 va_end(vap); 601 602 /* send message to stderr if in standalone mode */ 603 if (standalone != 0) { 604 fprintf(stderr, err); 605 } 606 607 /* always log the message */ 608 syslog(priority, err); 609 } 610