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 /* check for errors in SADB message */ 443 if (msg->sadb_msg_errno != 0) { 444 445 char unknown_type_str[16]; 446 int unknown_type = 0; 447 int arr_sz; 448 const char *diagnostic_str; 449 450 arr_sz = sizeof (pfkey_msg_type) / sizeof (*pfkey_msg_type); 451 452 /* generate unknown type string, if necessary */ 453 if (msg->sadb_msg_type >= arr_sz) { 454 (void) snprintf(unknown_type_str, 455 sizeof (unknown_type_str), "UNKNOWN-%d", 456 msg->sadb_msg_type); 457 unknown_type = 1; 458 } 459 460 /* use libipsecutil to lookup the SADB diagnostic string */ 461 diagnostic_str = keysock_diag(msg->sadb_x_msg_diagnostic); 462 463 sckmd_log(LOG_ERR, "PF_KEY error: type=%s, errno=%d: %s, " 464 "diagnostic code=%d: %s\n", 465 (unknown_type) ? unknown_type_str : 466 pfkey_msg_type[msg->sadb_msg_type], 467 msg->sadb_msg_errno, strerror(msg->sadb_msg_errno), 468 msg->sadb_x_msg_diagnostic, diagnostic_str); 469 470 *err = SCKM_IOCTL_STAT_ERR_PFKEY; 471 errno = msg->sadb_msg_errno; 472 return (-1); 473 } 474 475 return (0); 476 } 477 478 479 /* 480 * read_pfkey_msg: 481 * 482 * Get a PF_KEY message from the socket using the global file descriptor 483 * 'keysock'. Data is stored in the global buffer 'msg_buf'. The function 484 * returns a pointer to the next PF_KEY message. Note that this is not 485 * necessarily at the start of 'msg_buf'. NULL is returned for errors. 486 */ 487 static struct sadb_msg * 488 read_pfkey_msg(void) 489 { 490 static uint64_t *offset; 491 static int len; 492 struct sadb_msg *retval; 493 494 495 /* Assume offset and len are initialized to NULL and 0 */ 496 497 if ((offset == NULL) || (offset - len == msg_buf)) { 498 /* read a new block from the socket. */ 499 len = read(keysock, &msg_buf, sizeof (msg_buf)); 500 501 if (len == -1) { 502 sckmd_log(LOG_ERR, "PF_KEY read: %s\n", 503 strerror(errno)); 504 505 offset = NULL; 506 return (NULL); 507 } 508 offset = msg_buf; 509 len = SADB_8TO64(len); 510 } 511 512 retval = (struct sadb_msg *)offset; 513 offset += retval->sadb_msg_len; 514 515 if (offset > msg_buf + len) { 516 sckmd_log(LOG_ERR, "PF_KEY read: message corruption, " 517 "message length %d exceeds boundary %d\n", 518 SADB_64TO8(retval->sadb_msg_len), 519 SADB_64TO8((msg_buf + len) - (uint64_t *)retval)); 520 521 offset = NULL; 522 return (NULL); 523 } 524 525 return (retval); 526 } 527 528 529 /* 530 * convert_pfkey_msg: 531 * 532 * Convert a lower version PF_KEY message to the current version 533 * being used by sckmd. 534 * 535 * Currently, there is only one implemented version of PF_KEY (v2). 536 * If future versions are added to the PF_KEY specification (RFC 2367), 537 * this function should be updated to provide backwards compatibility 538 * with version 2 and above. 539 */ 540 static int 541 convert_pfkey_msg(struct sadb_msg *msg) 542 { 543 sckmd_log(LOG_DEBUG, "PF_KEY conversion necessary...\n"); 544 545 switch (msg->sadb_msg_version) { 546 547 case PF_KEY_V2: 548 /* 549 * Current supported version: 550 * No conversion required 551 */ 552 break; 553 default: 554 sckmd_log(LOG_ERR, "No conversion possible for " 555 "PF_KEY version %d\n", msg->sadb_msg_version); 556 return (-1); 557 } 558 559 return (0); 560 } 561 562 563 /* 564 * sckmd_log: 565 * 566 * Log a message using the syslog facility. If sckmd is running in 567 * standalone mode (global flag 'standalone' set), messages are also 568 * sent to stderr. 569 */ 570 static void 571 sckmd_log(int priority, char *fmt, ...) 572 { 573 va_list vap; 574 char err[SCKMD_ERR_MSG_SIZE]; 575 576 577 /* if this is a debug message, check if debugging is enabled */ 578 if ((priority == LOG_DEBUG) && (debug == 0)) { 579 return; 580 } 581 582 va_start(vap, fmt); 583 vsnprintf(err, SCKMD_ERR_MSG_SIZE, fmt, vap); 584 va_end(vap); 585 586 /* send message to stderr if in standalone mode */ 587 if (standalone != 0) { 588 fprintf(stderr, err); 589 } 590 591 /* always log the message */ 592 syslog(priority, err); 593 } 594