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