1 /* 2 * 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright 2012 Milan Juri. All rights reserved. 26 * Copyright 2018 Joyent, Inc. 27 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. 28 */ 29 30 #include <unistd.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <stdarg.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <fcntl.h> 37 #include <sys/sysconf.h> 38 #include <strings.h> 39 #include <ctype.h> 40 #include <errno.h> 41 #include <sys/socket.h> 42 #include <netdb.h> 43 #include <netinet/in.h> 44 #include <arpa/inet.h> 45 #include <net/pfkeyv2.h> 46 #include <net/pfpolicy.h> 47 #include <libintl.h> 48 #include <setjmp.h> 49 #include <libgen.h> 50 #include <libscf.h> 51 #include <kmfapi.h> 52 #include <ber_der.h> 53 54 #include "ipsec_util.h" 55 #include "ikedoor.h" 56 57 /* 58 * This file contains support functions that are shared by the ipsec 59 * utilities and daemons including ipseckey(1m), ikeadm(1m) and in.iked(1m). 60 */ 61 62 63 #define EFD(file) (((file) == stdout) ? stderr : (file)) 64 65 /* Limits for interactive mode. */ 66 #define MAX_LINE_LEN IBUF_SIZE 67 #define MAX_CMD_HIST 64000 /* in bytes */ 68 69 /* Set standard default/initial values for globals... */ 70 boolean_t pflag = B_FALSE; /* paranoid w.r.t. printing keying material */ 71 boolean_t nflag = B_FALSE; /* avoid nameservice? */ 72 boolean_t interactive = B_FALSE; /* util not running on cmdline */ 73 boolean_t readfile = B_FALSE; /* cmds are being read from a file */ 74 uint_t lineno = 0; /* track location if reading cmds from file */ 75 uint_t lines_added = 0; 76 uint_t lines_parsed = 0; 77 jmp_buf env; /* for error recovery in interactive/readfile modes */ 78 char *my_fmri = NULL; 79 FILE *debugfile = stderr; 80 static GetLine *gl = NULL; /* for interactive mode */ 81 82 /* 83 * Print errno and exit if cmdline or readfile, reset state if interactive 84 * The error string *what should be dgettext()'d before calling bail(). 85 */ 86 void 87 bail(char *what) 88 { 89 if (errno != 0) 90 warn(what); 91 else 92 warnx(dgettext(TEXT_DOMAIN, "Error: %s"), what); 93 if (readfile) { 94 return; 95 } 96 if (interactive && !readfile) 97 longjmp(env, 2); 98 EXIT_FATAL(NULL); 99 } 100 101 /* 102 * Print caller-supplied variable-arg error msg, then exit if cmdline or 103 * readfile, or reset state if interactive. 104 */ 105 /*PRINTFLIKE1*/ 106 void 107 bail_msg(char *fmt, ...) 108 { 109 va_list ap; 110 char msgbuf[BUFSIZ]; 111 112 va_start(ap, fmt); 113 (void) vsnprintf(msgbuf, BUFSIZ, fmt, ap); 114 va_end(ap); 115 if (readfile) 116 warnx(dgettext(TEXT_DOMAIN, 117 "ERROR on line %u:\n%s\n"), lineno, msgbuf); 118 else 119 warnx(dgettext(TEXT_DOMAIN, "ERROR: %s\n"), msgbuf); 120 121 if (interactive && !readfile) 122 longjmp(env, 1); 123 124 EXIT_FATAL(NULL); 125 } 126 127 /* 128 * bytecnt2str() wrapper. Zeroes out the input buffer and if the number 129 * of bytes to be converted is more than 1K, it will produce readable string 130 * in parentheses, store it in the original buffer and return the pointer to it. 131 * Maximum length of the returned string is 14 characters (not including 132 * the terminating zero). 133 */ 134 char * 135 bytecnt2out(uint64_t num, char *buf, size_t bufsiz, int flags) 136 { 137 char *str; 138 139 (void) memset(buf, '\0', bufsiz); 140 141 if (num > 1024) { 142 /* Return empty string in case of out-of-memory. */ 143 if ((str = malloc(bufsiz)) == NULL) 144 return (buf); 145 146 (void) bytecnt2str(num, str, bufsiz); 147 /* Detect overflow. */ 148 if (strlen(str) == 0) { 149 free(str); 150 return (buf); 151 } 152 153 /* Emit nothing in case of overflow. */ 154 if (snprintf(buf, bufsiz, "%s(%sB)%s", 155 flags & SPC_BEGIN ? " " : "", str, 156 flags & SPC_END ? " " : "") >= bufsiz) 157 (void) memset(buf, '\0', bufsiz); 158 159 free(str); 160 } 161 162 return (buf); 163 } 164 165 /* 166 * Convert 64-bit number to human readable string. Useful mainly for the 167 * byte lifetime counters. Returns pointer to the user supplied buffer. 168 * Able to convert up to Exabytes. Maximum length of the string produced 169 * is 9 characters (not counting the terminating zero). 170 */ 171 char * 172 bytecnt2str(uint64_t num, char *buf, size_t buflen) 173 { 174 uint64_t n = num; 175 char u; 176 int index = 0; 177 178 while (n >= 1024) { 179 n /= 1024; 180 index++; 181 } 182 183 /* The field has all units this function can represent. */ 184 u = " KMGTPE"[index]; 185 186 if (index == 0) { 187 /* Less than 1K */ 188 if (snprintf(buf, buflen, "%llu ", num) >= buflen) 189 (void) memset(buf, '\0', buflen); 190 } else { 191 /* Otherwise display 2 precision digits. */ 192 if (snprintf(buf, buflen, "%.2f %c", 193 (double)num / (1ULL << index * 10), u) >= buflen) 194 (void) memset(buf, '\0', buflen); 195 } 196 197 return (buf); 198 } 199 200 /* 201 * secs2str() wrapper. Zeroes out the input buffer and if the number of 202 * seconds to be converted is more than minute, it will produce readable 203 * string in parentheses, store it in the original buffer and return the 204 * pointer to it. 205 */ 206 char * 207 secs2out(unsigned int secs, char *buf, int bufsiz, int flags) 208 { 209 char *str; 210 211 (void) memset(buf, '\0', bufsiz); 212 213 if (secs > 60) { 214 /* Return empty string in case of out-of-memory. */ 215 if ((str = malloc(bufsiz)) == NULL) 216 return (buf); 217 218 (void) secs2str(secs, str, bufsiz); 219 /* Detect overflow. */ 220 if (strlen(str) == 0) { 221 free(str); 222 return (buf); 223 } 224 225 /* Emit nothing in case of overflow. */ 226 if (snprintf(buf, bufsiz, "%s(%s)%s", 227 flags & SPC_BEGIN ? " " : "", str, 228 flags & SPC_END ? " " : "") >= bufsiz) 229 (void) memset(buf, '\0', bufsiz); 230 231 free(str); 232 } 233 234 return (buf); 235 } 236 237 /* 238 * Convert number of seconds to human readable string. Useful mainly for 239 * the lifetime counters. Returns pointer to the user supplied buffer. 240 * Able to convert up to days. 241 */ 242 char * 243 secs2str(unsigned int secs, char *buf, int bufsiz) 244 { 245 double val = secs; 246 char *unit = "second"; 247 248 if (val >= 24*60*60) { 249 val /= 86400; 250 unit = "day"; 251 } else if (val >= 60*60) { 252 val /= 60*60; 253 unit = "hour"; 254 } else if (val >= 60) { 255 val /= 60; 256 unit = "minute"; 257 } 258 259 /* Emit nothing in case of overflow. */ 260 if (snprintf(buf, bufsiz, "%.2f %s%s", val, unit, 261 val >= 2 ? "s" : "") >= bufsiz) 262 (void) memset(buf, '\0', bufsiz); 263 264 return (buf); 265 } 266 267 /* 268 * dump_XXX functions produce ASCII output from various structures. 269 * 270 * Because certain errors need to do this to stderr, dump_XXX functions 271 * take a FILE pointer. 272 * 273 * If an error occured while writing to the specified file, these 274 * functions return -1, zero otherwise. 275 */ 276 277 int 278 dump_sockaddr(struct sockaddr *sa, uint8_t prefixlen, boolean_t addr_only, 279 FILE *where, boolean_t ignore_nss) 280 { 281 struct sockaddr_in *sin; 282 struct sockaddr_in6 *sin6; 283 char *printable_addr, *protocol; 284 uint8_t *addrptr; 285 /* Add 4 chars to hold '/nnn' for prefixes. */ 286 char storage[INET6_ADDRSTRLEN + 4]; 287 uint16_t port; 288 boolean_t unspec; 289 struct hostent *hp; 290 int getipnode_errno, addrlen; 291 292 switch (sa->sa_family) { 293 case AF_INET: 294 /* LINTED E_BAD_PTR_CAST_ALIGN */ 295 sin = (struct sockaddr_in *)sa; 296 addrptr = (uint8_t *)&sin->sin_addr; 297 port = sin->sin_port; 298 protocol = "AF_INET"; 299 unspec = (sin->sin_addr.s_addr == 0); 300 addrlen = sizeof (sin->sin_addr); 301 break; 302 case AF_INET6: 303 /* LINTED E_BAD_PTR_CAST_ALIGN */ 304 sin6 = (struct sockaddr_in6 *)sa; 305 addrptr = (uint8_t *)&sin6->sin6_addr; 306 port = sin6->sin6_port; 307 protocol = "AF_INET6"; 308 unspec = IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr); 309 addrlen = sizeof (sin6->sin6_addr); 310 break; 311 default: 312 return (0); 313 } 314 315 if (inet_ntop(sa->sa_family, addrptr, storage, INET6_ADDRSTRLEN) == 316 NULL) { 317 printable_addr = dgettext(TEXT_DOMAIN, "Invalid IP address."); 318 } else { 319 char prefix[5]; /* "/nnn" with terminator. */ 320 321 (void) snprintf(prefix, sizeof (prefix), "/%d", prefixlen); 322 printable_addr = storage; 323 if (prefixlen != 0) { 324 (void) strlcat(printable_addr, prefix, 325 sizeof (storage)); 326 } 327 } 328 if (addr_only) { 329 if (fprintf(where, "%s", printable_addr) < 0) 330 return (-1); 331 } else { 332 if (fprintf(where, dgettext(TEXT_DOMAIN, 333 "%s: port %d, %s"), protocol, 334 ntohs(port), printable_addr) < 0) 335 return (-1); 336 if (ignore_nss == B_FALSE) { 337 /* 338 * Do AF_independent reverse hostname lookup here. 339 */ 340 if (unspec) { 341 if (fprintf(where, 342 dgettext(TEXT_DOMAIN, 343 " <unspecified>")) < 0) 344 return (-1); 345 } else { 346 hp = getipnodebyaddr((char *)addrptr, addrlen, 347 sa->sa_family, &getipnode_errno); 348 if (hp != NULL) { 349 if (fprintf(where, 350 " (%s)", hp->h_name) < 0) 351 return (-1); 352 freehostent(hp); 353 } else { 354 if (fprintf(where, 355 dgettext(TEXT_DOMAIN, 356 " <unknown>")) < 0) 357 return (-1); 358 } 359 } 360 } 361 if (fputs(".\n", where) == EOF) 362 return (-1); 363 } 364 return (0); 365 } 366 367 /* 368 * Dump a key, any salt and bitlen. 369 * The key is made up of a stream of bits. If the algorithm requires a salt 370 * value, this will also be part of the dumped key. The last "saltbits" of the 371 * key string, reading left to right will be the salt value. To make it easier 372 * to see which bits make up the key, the salt value is enclosed in []'s. 373 * This function can also be called when ipseckey(1m) -s is run, this "saves" 374 * the SAs, including the key to a file. When this is the case, the []'s are 375 * not printed. 376 * 377 * The implementation allows the kernel to be told about the length of the salt 378 * in whole bytes only. If this changes, this function will need to be updated. 379 */ 380 int 381 dump_key(uint8_t *keyp, uint_t bitlen, uint_t saltbits, FILE *where, 382 boolean_t separate_salt) 383 { 384 int numbytes, saltbytes; 385 386 numbytes = SADB_1TO8(bitlen); 387 saltbytes = SADB_1TO8(saltbits); 388 numbytes += saltbytes; 389 390 /* The & 0x7 is to check for leftover bits. */ 391 if ((bitlen & 0x7) != 0) 392 numbytes++; 393 394 while (numbytes-- != 0) { 395 if (pflag) { 396 /* Print no keys if paranoid */ 397 if (fprintf(where, "XX") < 0) 398 return (-1); 399 } else { 400 if (fprintf(where, "%02x", *keyp++) < 0) 401 return (-1); 402 } 403 if (separate_salt && saltbytes != 0 && 404 numbytes == saltbytes) { 405 if (fprintf(where, "[") < 0) 406 return (-1); 407 } 408 } 409 410 if (separate_salt && saltbits != 0) { 411 if (fprintf(where, "]/%u+%u", bitlen, saltbits) < 0) 412 return (-1); 413 } else { 414 if (fprintf(where, "/%u", bitlen + saltbits) < 0) 415 return (-1); 416 } 417 418 return (0); 419 } 420 421 /* 422 * Print an authentication or encryption algorithm 423 */ 424 static int 425 dump_generic_alg(uint8_t alg_num, int proto_num, FILE *where) 426 { 427 struct ipsecalgent *alg; 428 429 alg = getipsecalgbynum(alg_num, proto_num, NULL); 430 if (alg == NULL) { 431 if (fprintf(where, dgettext(TEXT_DOMAIN, 432 "<unknown %u>"), alg_num) < 0) 433 return (-1); 434 return (0); 435 } 436 437 /* 438 * Special-case <none> for backward output compat. 439 * Assume that SADB_AALG_NONE == SADB_EALG_NONE. 440 */ 441 if (alg_num == SADB_AALG_NONE) { 442 if (fputs(dgettext(TEXT_DOMAIN, 443 "<none>"), where) == EOF) 444 return (-1); 445 } else { 446 if (fputs(alg->a_names[0], where) == EOF) 447 return (-1); 448 } 449 450 freeipsecalgent(alg); 451 return (0); 452 } 453 454 int 455 dump_aalg(uint8_t aalg, FILE *where) 456 { 457 return (dump_generic_alg(aalg, IPSEC_PROTO_AH, where)); 458 } 459 460 int 461 dump_ealg(uint8_t ealg, FILE *where) 462 { 463 return (dump_generic_alg(ealg, IPSEC_PROTO_ESP, where)); 464 } 465 466 /* 467 * Print an SADB_IDENTTYPE string 468 * 469 * Also return TRUE if the actual ident may be printed, FALSE if not. 470 * 471 * If rc is not NULL, set its value to -1 if an error occured while writing 472 * to the specified file, zero otherwise. 473 */ 474 boolean_t 475 dump_sadb_idtype(uint8_t idtype, FILE *where, int *rc) 476 { 477 boolean_t canprint = B_TRUE; 478 int rc_val = 0; 479 480 switch (idtype) { 481 case SADB_IDENTTYPE_PREFIX: 482 if (fputs(dgettext(TEXT_DOMAIN, "prefix"), where) == EOF) 483 rc_val = -1; 484 break; 485 case SADB_IDENTTYPE_FQDN: 486 if (fputs(dgettext(TEXT_DOMAIN, "FQDN"), where) == EOF) 487 rc_val = -1; 488 break; 489 case SADB_IDENTTYPE_USER_FQDN: 490 if (fputs(dgettext(TEXT_DOMAIN, 491 "user-FQDN (mbox)"), where) == EOF) 492 rc_val = -1; 493 break; 494 case SADB_X_IDENTTYPE_DN: 495 if (fputs(dgettext(TEXT_DOMAIN, "ASN.1 DER Distinguished Name"), 496 where) == EOF) 497 rc_val = -1; 498 canprint = B_FALSE; 499 break; 500 case SADB_X_IDENTTYPE_GN: 501 if (fputs(dgettext(TEXT_DOMAIN, "ASN.1 DER Generic Name"), 502 where) == EOF) 503 rc_val = -1; 504 canprint = B_FALSE; 505 break; 506 case SADB_X_IDENTTYPE_KEY_ID: 507 if (fputs(dgettext(TEXT_DOMAIN, "Generic key id"), 508 where) == EOF) 509 rc_val = -1; 510 break; 511 case SADB_X_IDENTTYPE_ADDR_RANGE: 512 if (fputs(dgettext(TEXT_DOMAIN, "Address range"), where) == EOF) 513 rc_val = -1; 514 break; 515 default: 516 if (fprintf(where, dgettext(TEXT_DOMAIN, 517 "<unknown %u>"), idtype) < 0) 518 rc_val = -1; 519 break; 520 } 521 522 if (rc != NULL) 523 *rc = rc_val; 524 525 return (canprint); 526 } 527 528 /* 529 * Slice an argv/argc vector from an interactive line or a read-file line. 530 */ 531 static int 532 create_argv(char *ibuf, int *newargc, char ***thisargv) 533 { 534 unsigned int argvlen = START_ARG; 535 char **current; 536 boolean_t firstchar = B_TRUE; 537 boolean_t inquotes = B_FALSE; 538 539 *thisargv = malloc(sizeof (char *) * argvlen); 540 if ((*thisargv) == NULL) 541 return (MEMORY_ALLOCATION); 542 current = *thisargv; 543 *current = NULL; 544 545 for (; *ibuf != '\0'; ibuf++) { 546 if (isspace(*ibuf)) { 547 if (inquotes) { 548 continue; 549 } 550 if (*current != NULL) { 551 *ibuf = '\0'; 552 current++; 553 if (*thisargv + argvlen == current) { 554 /* Regrow ***thisargv. */ 555 if (argvlen == TOO_MANY_ARGS) { 556 free(*thisargv); 557 return (TOO_MANY_TOKENS); 558 } 559 /* Double the allocation. */ 560 current = realloc(*thisargv, 561 sizeof (char *) * (argvlen << 1)); 562 if (current == NULL) { 563 free(*thisargv); 564 return (MEMORY_ALLOCATION); 565 } 566 *thisargv = current; 567 current += argvlen; 568 argvlen <<= 1; /* Double the size. */ 569 } 570 *current = NULL; 571 } 572 } else { 573 if (firstchar) { 574 firstchar = B_FALSE; 575 if (*ibuf == COMMENT_CHAR || *ibuf == '\n') { 576 free(*thisargv); 577 return (COMMENT_LINE); 578 } 579 } 580 if (*ibuf == QUOTE_CHAR) { 581 if (inquotes) { 582 inquotes = B_FALSE; 583 *ibuf = '\0'; 584 } else { 585 inquotes = B_TRUE; 586 } 587 continue; 588 } 589 if (*current == NULL) { 590 *current = ibuf; 591 (*newargc)++; 592 } 593 } 594 } 595 596 /* 597 * Tricky corner case... 598 * I've parsed _exactly_ the amount of args as I have space. It 599 * won't return NULL-terminated, and bad things will happen to 600 * the caller. 601 */ 602 if (argvlen == *newargc) { 603 current = realloc(*thisargv, sizeof (char *) * (argvlen + 1)); 604 if (current == NULL) { 605 free(*thisargv); 606 return (MEMORY_ALLOCATION); 607 } 608 *thisargv = current; 609 current[argvlen] = NULL; 610 } 611 612 return (SUCCESS); 613 } 614 615 /* 616 * init interactive mode if needed and not yet initialized 617 */ 618 static void 619 init_interactive(FILE *infile, CplMatchFn *match_fn) 620 { 621 if (infile == stdin) { 622 if (gl == NULL) { 623 if ((gl = new_GetLine(MAX_LINE_LEN, 624 MAX_CMD_HIST)) == NULL) 625 errx(1, dgettext(TEXT_DOMAIN, 626 "tecla initialization failed")); 627 628 if (gl_customize_completion(gl, NULL, 629 match_fn) != 0) { 630 (void) del_GetLine(gl); 631 errx(1, dgettext(TEXT_DOMAIN, 632 "tab completion failed to initialize")); 633 } 634 635 /* 636 * In interactive mode we only want to terminate 637 * when explicitly requested (e.g. by a command). 638 */ 639 (void) sigset(SIGINT, SIG_IGN); 640 } 641 } else { 642 readfile = B_TRUE; 643 } 644 } 645 646 /* 647 * free tecla data structure 648 */ 649 static void 650 fini_interactive(void) 651 { 652 if (gl != NULL) 653 (void) del_GetLine(gl); 654 } 655 656 /* 657 * Get single input line, wrapping around interactive and non-interactive 658 * mode. 659 */ 660 static char * 661 do_getstr(FILE *infile, char *prompt, char *ibuf, size_t ibuf_size) 662 { 663 char *line; 664 665 if (infile != stdin) 666 return (fgets(ibuf, ibuf_size, infile)); 667 668 /* 669 * If the user hits ^C then we want to catch it and 670 * start over. If the user hits EOF then we want to 671 * bail out. 672 */ 673 once_again: 674 line = gl_get_line(gl, prompt, NULL, -1); 675 if (gl_return_status(gl) == GLR_SIGNAL) { 676 gl_abandon_line(gl); 677 goto once_again; 678 } else if (gl_return_status(gl) == GLR_ERROR) { 679 gl_abandon_line(gl); 680 errx(1, dgettext(TEXT_DOMAIN, "Error reading terminal: %s\n"), 681 gl_error_message(gl, NULL, 0)); 682 } else { 683 if (line != NULL) { 684 if (strlcpy(ibuf, line, ibuf_size) >= ibuf_size) 685 warnx(dgettext(TEXT_DOMAIN, 686 "Line too long (max=%d chars)"), 687 ibuf_size); 688 line = ibuf; 689 } 690 } 691 692 return (line); 693 } 694 695 /* 696 * Enter a mode where commands are read from a file. Treat stdin special. 697 */ 698 void 699 do_interactive(FILE *infile, char *configfile, char *promptstring, 700 char *my_fmri, parse_cmdln_fn parseit, CplMatchFn *match_fn) 701 { 702 char ibuf[IBUF_SIZE], holder[IBUF_SIZE]; 703 char *volatile hptr, **thisargv, *ebuf; 704 int thisargc; 705 volatile boolean_t continue_in_progress = B_FALSE; 706 char *s; 707 708 (void) setjmp(env); 709 710 ebuf = NULL; 711 interactive = B_TRUE; 712 bzero(ibuf, IBUF_SIZE); 713 714 /* panics for us */ 715 init_interactive(infile, match_fn); 716 717 while ((s = do_getstr(infile, promptstring, ibuf, IBUF_SIZE)) != NULL) { 718 if (readfile) 719 lineno++; 720 thisargc = 0; 721 thisargv = NULL; 722 723 /* 724 * Check byte IBUF_SIZE - 2, because byte IBUF_SIZE - 1 will 725 * be null-terminated because of fgets(). 726 */ 727 if (ibuf[IBUF_SIZE - 2] != '\0') { 728 if (infile == stdin) { 729 /* do_getstr() issued a warning already */ 730 bzero(ibuf, IBUF_SIZE); 731 continue; 732 } else { 733 ipsecutil_exit(SERVICE_FATAL, my_fmri, 734 debugfile, dgettext(TEXT_DOMAIN, 735 "Line %d too big."), lineno); 736 } 737 } 738 739 if (!continue_in_progress) { 740 /* Use -2 because of \n from fgets. */ 741 if (ibuf[strlen(ibuf) - 2] == CONT_CHAR) { 742 /* 743 * Can use strcpy here, I've checked the 744 * length already. 745 */ 746 (void) strcpy(holder, ibuf); 747 hptr = &(holder[strlen(holder)]); 748 749 /* Remove the CONT_CHAR from the string. */ 750 hptr[-2] = ' '; 751 752 continue_in_progress = B_TRUE; 753 bzero(ibuf, IBUF_SIZE); 754 continue; 755 } 756 } else { 757 /* Handle continuations... */ 758 (void) strncpy(hptr, ibuf, 759 (size_t)(&(holder[IBUF_SIZE]) - hptr)); 760 if (holder[IBUF_SIZE - 1] != '\0') { 761 ipsecutil_exit(SERVICE_FATAL, my_fmri, 762 debugfile, dgettext(TEXT_DOMAIN, 763 "Command buffer overrun.")); 764 } 765 /* Use - 2 because of \n from fgets. */ 766 if (hptr[strlen(hptr) - 2] == CONT_CHAR) { 767 bzero(ibuf, IBUF_SIZE); 768 hptr += strlen(hptr); 769 770 /* Remove the CONT_CHAR from the string. */ 771 hptr[-2] = ' '; 772 773 continue; 774 } else { 775 continue_in_progress = B_FALSE; 776 /* 777 * I've already checked the length... 778 */ 779 (void) strcpy(ibuf, holder); 780 } 781 } 782 783 /* 784 * Just in case the command fails keep a copy of the 785 * command buffer for diagnostic output. 786 */ 787 if (readfile) { 788 /* 789 * The error buffer needs to be big enough to 790 * hold the longest command string, plus 791 * some extra text, see below. 792 */ 793 ebuf = calloc((IBUF_SIZE * 2), sizeof (char)); 794 if (ebuf == NULL) { 795 ipsecutil_exit(SERVICE_FATAL, my_fmri, 796 debugfile, dgettext(TEXT_DOMAIN, 797 "Memory allocation error.")); 798 } else { 799 (void) snprintf(ebuf, (IBUF_SIZE * 2), 800 dgettext(TEXT_DOMAIN, 801 "Config file entry near line %u " 802 "caused error(s) or warnings:\n\n%s\n\n"), 803 lineno, ibuf); 804 } 805 } 806 807 switch (create_argv(ibuf, &thisargc, &thisargv)) { 808 case TOO_MANY_TOKENS: 809 ipsecutil_exit(SERVICE_BADCONF, my_fmri, debugfile, 810 dgettext(TEXT_DOMAIN, "Too many input tokens.")); 811 break; 812 case MEMORY_ALLOCATION: 813 ipsecutil_exit(SERVICE_BADCONF, my_fmri, debugfile, 814 dgettext(TEXT_DOMAIN, "Memory allocation error.")); 815 break; 816 case COMMENT_LINE: 817 /* Comment line. */ 818 free(ebuf); 819 break; 820 default: 821 if (thisargc != 0) { 822 lines_parsed++; 823 /* ebuf consumed */ 824 parseit(thisargc, thisargv, ebuf, readfile); 825 } else { 826 free(ebuf); 827 } 828 free(thisargv); 829 if (infile == stdin) { 830 (void) printf("%s", promptstring); 831 (void) fflush(stdout); 832 } 833 break; 834 } 835 bzero(ibuf, IBUF_SIZE); 836 } 837 838 /* 839 * The following code is ipseckey specific. This should never be 840 * used by ikeadm which also calls this function because ikeadm 841 * only runs interactively. If this ever changes this code block 842 * sould be revisited. 843 */ 844 if (readfile) { 845 if (lines_parsed != 0 && lines_added == 0) { 846 ipsecutil_exit(SERVICE_BADCONF, my_fmri, debugfile, 847 dgettext(TEXT_DOMAIN, "Configuration file did not " 848 "contain any valid SAs")); 849 } 850 851 /* 852 * There were errors. Putting the service in maintenance mode. 853 * When svc.startd(1M) allows services to degrade themselves, 854 * this should be revisited. 855 * 856 * If this function was called from a program running as a 857 * smf_method(5), print a warning message. Don't spew out the 858 * errors as these will end up in the smf(5) log file which is 859 * publically readable, the errors may contain sensitive 860 * information. 861 */ 862 if ((lines_added < lines_parsed) && (configfile != NULL)) { 863 if (my_fmri != NULL) { 864 ipsecutil_exit(SERVICE_BADCONF, my_fmri, 865 debugfile, dgettext(TEXT_DOMAIN, 866 "The configuration file contained %d " 867 "errors.\n" 868 "Manually check the configuration with:\n" 869 "ipseckey -c %s\n" 870 "Use svcadm(1M) to clear maintenance " 871 "condition when errors are resolved.\n"), 872 lines_parsed - lines_added, configfile); 873 } else { 874 EXIT_BADCONFIG(NULL); 875 } 876 } else { 877 if (my_fmri != NULL) 878 ipsecutil_exit(SERVICE_EXIT_OK, my_fmri, 879 debugfile, dgettext(TEXT_DOMAIN, 880 "%d actions successfully processed."), 881 lines_added); 882 } 883 } else { 884 /* no newline upon Ctrl-D */ 885 if (s != NULL) 886 (void) putchar('\n'); 887 (void) fflush(stdout); 888 } 889 890 fini_interactive(); 891 892 EXIT_OK(NULL); 893 } 894 895 /* 896 * Functions to parse strings that represent a debug or privilege level. 897 * These functions are copied from main.c and door.c in usr.lib/in.iked/common. 898 * If this file evolves into a common library that may be used by in.iked 899 * as well as the usr.sbin utilities, those duplicate functions should be 900 * deleted. 901 * 902 * A privilege level may be represented by a simple keyword, corresponding 903 * to one of the possible levels. A debug level may be represented by a 904 * series of keywords, separated by '+' or '-', indicating categories to 905 * be added or removed from the set of categories in the debug level. 906 * For example, +all-op corresponds to level 0xfffffffb (all flags except 907 * for D_OP set); while p1+p2+pfkey corresponds to level 0x38. Note that 908 * the leading '+' is implicit; the first keyword in the list must be for 909 * a category that is to be added. 910 * 911 * These parsing functions make use of a local version of strtok, strtok_d, 912 * which includes an additional parameter, char *delim. This param is filled 913 * in with the character which ends the returned token. In other words, 914 * this version of strtok, in addition to returning the token, also returns 915 * the single character delimiter from the original string which marked the 916 * end of the token. 917 */ 918 static char * 919 strtok_d(char *string, const char *sepset, char *delim) 920 { 921 static char *lasts; 922 char *q, *r; 923 924 /* first or subsequent call */ 925 if (string == NULL) 926 string = lasts; 927 928 if (string == 0) /* return if no tokens remaining */ 929 return (NULL); 930 931 q = string + strspn(string, sepset); /* skip leading separators */ 932 933 if (*q == '\0') /* return if no tokens remaining */ 934 return (NULL); 935 936 if ((r = strpbrk(q, sepset)) == NULL) { /* move past token */ 937 lasts = 0; /* indicate that this is last token */ 938 } else { 939 *delim = *r; /* save delimitor */ 940 *r = '\0'; 941 lasts = r + 1; 942 } 943 return (q); 944 } 945 946 static keywdtab_t privtab[] = { 947 { IKE_PRIV_MINIMUM, "base" }, 948 { IKE_PRIV_MODKEYS, "modkeys" }, 949 { IKE_PRIV_KEYMAT, "keymat" }, 950 { IKE_PRIV_MINIMUM, "0" }, 951 }; 952 953 int 954 privstr2num(char *str) 955 { 956 keywdtab_t *pp; 957 char *endp; 958 int priv; 959 960 for (pp = privtab; pp < A_END(privtab); pp++) { 961 if (strcasecmp(str, pp->kw_str) == 0) 962 return (pp->kw_tag); 963 } 964 965 priv = strtol(str, &endp, 0); 966 if (*endp == '\0') 967 return (priv); 968 969 return (-1); 970 } 971 972 static keywdtab_t dbgtab[] = { 973 { D_CERT, "cert" }, 974 { D_KEY, "key" }, 975 { D_OP, "op" }, 976 { D_P1, "p1" }, 977 { D_P1, "phase1" }, 978 { D_P2, "p2" }, 979 { D_P2, "phase2" }, 980 { D_PFKEY, "pfkey" }, 981 { D_POL, "pol" }, 982 { D_POL, "policy" }, 983 { D_PROP, "prop" }, 984 { D_DOOR, "door" }, 985 { D_CONFIG, "config" }, 986 { D_LABEL, "label" }, 987 { D_ALL, "all" }, 988 { 0, "0" }, 989 }; 990 991 int 992 dbgstr2num(char *str) 993 { 994 keywdtab_t *dp; 995 996 for (dp = dbgtab; dp < A_END(dbgtab); dp++) { 997 if (strcasecmp(str, dp->kw_str) == 0) 998 return (dp->kw_tag); 999 } 1000 return (D_INVALID); 1001 } 1002 1003 int 1004 parsedbgopts(char *optarg) 1005 { 1006 char *argp, *endp, op, nextop; 1007 int mask = 0, new; 1008 1009 mask = strtol(optarg, &endp, 0); 1010 if (*endp == '\0') 1011 return (mask); 1012 1013 op = optarg[0]; 1014 if (op != '-') 1015 op = '+'; 1016 argp = strtok_d(optarg, "+-", &nextop); 1017 do { 1018 new = dbgstr2num(argp); 1019 if (new == D_INVALID) { 1020 /* we encountered an invalid keywd */ 1021 return (new); 1022 } 1023 if (op == '+') { 1024 mask |= new; 1025 } else { 1026 mask &= ~new; 1027 } 1028 op = nextop; 1029 } while ((argp = strtok_d(NULL, "+-", &nextop)) != NULL); 1030 1031 return (mask); 1032 } 1033 1034 1035 /* 1036 * functions to manipulate the kmcookie-label mapping file 1037 */ 1038 1039 /* 1040 * Open, lockf, fdopen the given file, returning a FILE * on success, 1041 * or NULL on failure. 1042 */ 1043 FILE * 1044 kmc_open_and_lock(char *name) 1045 { 1046 int fd, rtnerr; 1047 FILE *fp; 1048 1049 if ((fd = open(name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) { 1050 return (NULL); 1051 } 1052 if (lockf(fd, F_LOCK, 0) < 0) { 1053 return (NULL); 1054 } 1055 if ((fp = fdopen(fd, "a+")) == NULL) { 1056 return (NULL); 1057 } 1058 if (fseek(fp, 0, SEEK_SET) < 0) { 1059 /* save errno in case fclose changes it */ 1060 rtnerr = errno; 1061 (void) fclose(fp); 1062 errno = rtnerr; 1063 return (NULL); 1064 } 1065 return (fp); 1066 } 1067 1068 /* 1069 * Extract an integer cookie and string label from a line from the 1070 * kmcookie-label file. Return -1 on failure, 0 on success. 1071 */ 1072 int 1073 kmc_parse_line(char *line, int *cookie, char **label) 1074 { 1075 char *cookiestr; 1076 1077 *cookie = 0; 1078 *label = NULL; 1079 1080 cookiestr = strtok(line, " \t\n"); 1081 if (cookiestr == NULL) { 1082 return (-1); 1083 } 1084 1085 /* Everything that follows, up to the newline, is the label. */ 1086 *label = strtok(NULL, "\n"); 1087 if (*label == NULL) { 1088 return (-1); 1089 } 1090 1091 *cookie = atoi(cookiestr); 1092 return (0); 1093 } 1094 1095 /* 1096 * Insert a mapping into the file (if it's not already there), given the 1097 * new label. Return the assigned cookie, or -1 on error. 1098 */ 1099 int 1100 kmc_insert_mapping(char *label) 1101 { 1102 FILE *map; 1103 char linebuf[IBUF_SIZE]; 1104 char *cur_label; 1105 int max_cookie = 0, cur_cookie, rtn_cookie; 1106 int rtnerr = 0; 1107 boolean_t found = B_FALSE; 1108 1109 /* open and lock the file; will sleep until lock is available */ 1110 if ((map = kmc_open_and_lock(KMCFILE)) == NULL) { 1111 /* kmc_open_and_lock() sets errno appropriately */ 1112 return (-1); 1113 } 1114 1115 while (fgets(linebuf, sizeof (linebuf), map) != NULL) { 1116 1117 /* Skip blank lines, which often come near EOF. */ 1118 if (strlen(linebuf) == 0) 1119 continue; 1120 1121 if (kmc_parse_line(linebuf, &cur_cookie, &cur_label) < 0) { 1122 rtnerr = EINVAL; 1123 goto error; 1124 } 1125 1126 if (cur_cookie > max_cookie) 1127 max_cookie = cur_cookie; 1128 1129 if ((!found) && (strcmp(cur_label, label) == 0)) { 1130 found = B_TRUE; 1131 rtn_cookie = cur_cookie; 1132 } 1133 } 1134 1135 if (!found) { 1136 rtn_cookie = ++max_cookie; 1137 if ((fprintf(map, "%u\t%s\n", rtn_cookie, label) < 0) || 1138 (fflush(map) < 0)) { 1139 rtnerr = errno; 1140 goto error; 1141 } 1142 } 1143 (void) fclose(map); 1144 1145 return (rtn_cookie); 1146 1147 error: 1148 (void) fclose(map); 1149 errno = rtnerr; 1150 return (-1); 1151 } 1152 1153 /* 1154 * Lookup the given cookie and return its corresponding label. Return 1155 * a pointer to the label on success, NULL on error (or if the label is 1156 * not found). Note that the returned label pointer points to a static 1157 * string, so the label will be overwritten by a subsequent call to the 1158 * function; the function is also not thread-safe as a result. 1159 * 1160 * Because this is possibly publically exported, do not change its name, 1161 * but this is for all intents and purposes an IKEv1/in.iked function. 1162 */ 1163 char * 1164 kmc_lookup_by_cookie(int cookie) 1165 { 1166 FILE *map; 1167 static char linebuf[IBUF_SIZE]; 1168 char *cur_label; 1169 int cur_cookie; 1170 1171 if ((map = kmc_open_and_lock(KMCFILE)) == NULL) { 1172 return (NULL); 1173 } 1174 1175 while (fgets(linebuf, sizeof (linebuf), map) != NULL) { 1176 1177 if (kmc_parse_line(linebuf, &cur_cookie, &cur_label) < 0) { 1178 (void) fclose(map); 1179 return (NULL); 1180 } 1181 1182 if (cookie == cur_cookie) { 1183 (void) fclose(map); 1184 return (cur_label); 1185 } 1186 } 1187 (void) fclose(map); 1188 1189 return (NULL); 1190 } 1191 1192 /* 1193 * Parse basic extension headers and return in the passed-in pointer vector. 1194 * Return values include: 1195 * 1196 * KGE_OK Everything's nice and parsed out. 1197 * If there are no extensions, place NULL in extv[0]. 1198 * KGE_DUP There is a duplicate extension. 1199 * First instance in appropriate bin. First duplicate in 1200 * extv[0]. 1201 * KGE_UNK Unknown extension type encountered. extv[0] contains 1202 * unknown header. 1203 * KGE_LEN Extension length error. 1204 * KGE_CHK High-level reality check failed on specific extension. 1205 * 1206 * My apologies for some of the pointer arithmetic in here. I'm thinking 1207 * like an assembly programmer, yet trying to make the compiler happy. 1208 */ 1209 int 1210 spdsock_get_ext(spd_ext_t *extv[], spd_msg_t *basehdr, uint_t msgsize, 1211 char *diag_buf, uint_t diag_buf_len) 1212 { 1213 int i; 1214 1215 if (diag_buf != NULL) 1216 diag_buf[0] = '\0'; 1217 1218 for (i = 1; i <= SPD_EXT_MAX; i++) 1219 extv[i] = NULL; 1220 1221 i = 0; 1222 /* Use extv[0] as the "current working pointer". */ 1223 1224 extv[0] = (spd_ext_t *)(basehdr + 1); 1225 msgsize = SPD_64TO8(msgsize); 1226 1227 while ((char *)extv[0] < ((char *)basehdr + msgsize)) { 1228 /* Check for unknown headers. */ 1229 i++; 1230 if (extv[0]->spd_ext_type == 0 || 1231 extv[0]->spd_ext_type > SPD_EXT_MAX) { 1232 if (diag_buf != NULL) { 1233 (void) snprintf(diag_buf, diag_buf_len, 1234 "spdsock ext 0x%X unknown: 0x%X", 1235 i, extv[0]->spd_ext_type); 1236 } 1237 return (KGE_UNK); 1238 } 1239 1240 /* 1241 * Check length. Use uint64_t because extlen is in units 1242 * of 64-bit words. If length goes beyond the msgsize, 1243 * return an error. (Zero length also qualifies here.) 1244 */ 1245 if (extv[0]->spd_ext_len == 0 || 1246 (uint8_t *)((uint64_t *)extv[0] + extv[0]->spd_ext_len) > 1247 (uint8_t *)((uint8_t *)basehdr + msgsize)) 1248 return (KGE_LEN); 1249 1250 /* Check for redundant headers. */ 1251 if (extv[extv[0]->spd_ext_type] != NULL) 1252 return (KGE_DUP); 1253 1254 /* If I make it here, assign the appropriate bin. */ 1255 extv[extv[0]->spd_ext_type] = extv[0]; 1256 1257 /* Advance pointer (See above for uint64_t ptr reasoning.) */ 1258 extv[0] = (spd_ext_t *) 1259 ((uint64_t *)extv[0] + extv[0]->spd_ext_len); 1260 } 1261 1262 /* Everything's cool. */ 1263 1264 /* 1265 * If extv[0] == NULL, then there are no extension headers in this 1266 * message. Ensure that this is the case. 1267 */ 1268 if (extv[0] == (spd_ext_t *)(basehdr + 1)) 1269 extv[0] = NULL; 1270 1271 return (KGE_OK); 1272 } 1273 1274 const char * 1275 spdsock_diag(int diagnostic) 1276 { 1277 switch (diagnostic) { 1278 case SPD_DIAGNOSTIC_NONE: 1279 return (dgettext(TEXT_DOMAIN, "no error")); 1280 case SPD_DIAGNOSTIC_UNKNOWN_EXT: 1281 return (dgettext(TEXT_DOMAIN, "unknown extension")); 1282 case SPD_DIAGNOSTIC_BAD_EXTLEN: 1283 return (dgettext(TEXT_DOMAIN, "bad extension length")); 1284 case SPD_DIAGNOSTIC_NO_RULE_EXT: 1285 return (dgettext(TEXT_DOMAIN, "no rule extension")); 1286 case SPD_DIAGNOSTIC_BAD_ADDR_LEN: 1287 return (dgettext(TEXT_DOMAIN, "bad address len")); 1288 case SPD_DIAGNOSTIC_MIXED_AF: 1289 return (dgettext(TEXT_DOMAIN, "mixed address family")); 1290 case SPD_DIAGNOSTIC_ADD_NO_MEM: 1291 return (dgettext(TEXT_DOMAIN, "add: no memory")); 1292 case SPD_DIAGNOSTIC_ADD_WRONG_ACT_COUNT: 1293 return (dgettext(TEXT_DOMAIN, "add: wrong action count")); 1294 case SPD_DIAGNOSTIC_ADD_BAD_TYPE: 1295 return (dgettext(TEXT_DOMAIN, "add: bad type")); 1296 case SPD_DIAGNOSTIC_ADD_BAD_FLAGS: 1297 return (dgettext(TEXT_DOMAIN, "add: bad flags")); 1298 case SPD_DIAGNOSTIC_ADD_INCON_FLAGS: 1299 return (dgettext(TEXT_DOMAIN, "add: inconsistent flags")); 1300 case SPD_DIAGNOSTIC_MALFORMED_LCLPORT: 1301 return (dgettext(TEXT_DOMAIN, "malformed local port")); 1302 case SPD_DIAGNOSTIC_DUPLICATE_LCLPORT: 1303 return (dgettext(TEXT_DOMAIN, "duplicate local port")); 1304 case SPD_DIAGNOSTIC_MALFORMED_REMPORT: 1305 return (dgettext(TEXT_DOMAIN, "malformed remote port")); 1306 case SPD_DIAGNOSTIC_DUPLICATE_REMPORT: 1307 return (dgettext(TEXT_DOMAIN, "duplicate remote port")); 1308 case SPD_DIAGNOSTIC_MALFORMED_PROTO: 1309 return (dgettext(TEXT_DOMAIN, "malformed proto")); 1310 case SPD_DIAGNOSTIC_DUPLICATE_PROTO: 1311 return (dgettext(TEXT_DOMAIN, "duplicate proto")); 1312 case SPD_DIAGNOSTIC_MALFORMED_LCLADDR: 1313 return (dgettext(TEXT_DOMAIN, "malformed local address")); 1314 case SPD_DIAGNOSTIC_DUPLICATE_LCLADDR: 1315 return (dgettext(TEXT_DOMAIN, "duplicate local address")); 1316 case SPD_DIAGNOSTIC_MALFORMED_REMADDR: 1317 return (dgettext(TEXT_DOMAIN, "malformed remote address")); 1318 case SPD_DIAGNOSTIC_DUPLICATE_REMADDR: 1319 return (dgettext(TEXT_DOMAIN, "duplicate remote address")); 1320 case SPD_DIAGNOSTIC_MALFORMED_ACTION: 1321 return (dgettext(TEXT_DOMAIN, "malformed action")); 1322 case SPD_DIAGNOSTIC_DUPLICATE_ACTION: 1323 return (dgettext(TEXT_DOMAIN, "duplicate action")); 1324 case SPD_DIAGNOSTIC_MALFORMED_RULE: 1325 return (dgettext(TEXT_DOMAIN, "malformed rule")); 1326 case SPD_DIAGNOSTIC_DUPLICATE_RULE: 1327 return (dgettext(TEXT_DOMAIN, "duplicate rule")); 1328 case SPD_DIAGNOSTIC_MALFORMED_RULESET: 1329 return (dgettext(TEXT_DOMAIN, "malformed ruleset")); 1330 case SPD_DIAGNOSTIC_DUPLICATE_RULESET: 1331 return (dgettext(TEXT_DOMAIN, "duplicate ruleset")); 1332 case SPD_DIAGNOSTIC_INVALID_RULE_INDEX: 1333 return (dgettext(TEXT_DOMAIN, "invalid rule index")); 1334 case SPD_DIAGNOSTIC_BAD_SPDID: 1335 return (dgettext(TEXT_DOMAIN, "bad spdid")); 1336 case SPD_DIAGNOSTIC_BAD_MSG_TYPE: 1337 return (dgettext(TEXT_DOMAIN, "bad message type")); 1338 case SPD_DIAGNOSTIC_UNSUPP_AH_ALG: 1339 return (dgettext(TEXT_DOMAIN, "unsupported AH algorithm")); 1340 case SPD_DIAGNOSTIC_UNSUPP_ESP_ENCR_ALG: 1341 return (dgettext(TEXT_DOMAIN, 1342 "unsupported ESP encryption algorithm")); 1343 case SPD_DIAGNOSTIC_UNSUPP_ESP_AUTH_ALG: 1344 return (dgettext(TEXT_DOMAIN, 1345 "unsupported ESP authentication algorithm")); 1346 case SPD_DIAGNOSTIC_UNSUPP_AH_KEYSIZE: 1347 return (dgettext(TEXT_DOMAIN, "unsupported AH key size")); 1348 case SPD_DIAGNOSTIC_UNSUPP_ESP_ENCR_KEYSIZE: 1349 return (dgettext(TEXT_DOMAIN, 1350 "unsupported ESP encryption key size")); 1351 case SPD_DIAGNOSTIC_UNSUPP_ESP_AUTH_KEYSIZE: 1352 return (dgettext(TEXT_DOMAIN, 1353 "unsupported ESP authentication key size")); 1354 case SPD_DIAGNOSTIC_NO_ACTION_EXT: 1355 return (dgettext(TEXT_DOMAIN, "No ACTION extension")); 1356 case SPD_DIAGNOSTIC_ALG_ID_RANGE: 1357 return (dgettext(TEXT_DOMAIN, "invalid algorithm identifer")); 1358 case SPD_DIAGNOSTIC_ALG_NUM_KEY_SIZES: 1359 return (dgettext(TEXT_DOMAIN, 1360 "number of key sizes inconsistent")); 1361 case SPD_DIAGNOSTIC_ALG_NUM_BLOCK_SIZES: 1362 return (dgettext(TEXT_DOMAIN, 1363 "number of block sizes inconsistent")); 1364 case SPD_DIAGNOSTIC_ALG_MECH_NAME_LEN: 1365 return (dgettext(TEXT_DOMAIN, "invalid mechanism name length")); 1366 case SPD_DIAGNOSTIC_NOT_GLOBAL_OP: 1367 return (dgettext(TEXT_DOMAIN, 1368 "operation not applicable to all policies")); 1369 case SPD_DIAGNOSTIC_NO_TUNNEL_SELECTORS: 1370 return (dgettext(TEXT_DOMAIN, 1371 "using selectors on a transport-mode tunnel")); 1372 default: 1373 return (dgettext(TEXT_DOMAIN, "unknown diagnostic")); 1374 } 1375 } 1376 1377 /* 1378 * PF_KEY Diagnostic table. 1379 * 1380 * PF_KEY NOTE: If you change pfkeyv2.h's SADB_X_DIAGNOSTIC_* space, this is 1381 * where you need to add new messages. 1382 */ 1383 1384 const char * 1385 keysock_diag(int diagnostic) 1386 { 1387 switch (diagnostic) { 1388 case SADB_X_DIAGNOSTIC_NONE: 1389 return (dgettext(TEXT_DOMAIN, "No diagnostic")); 1390 case SADB_X_DIAGNOSTIC_UNKNOWN_MSG: 1391 return (dgettext(TEXT_DOMAIN, "Unknown message type")); 1392 case SADB_X_DIAGNOSTIC_UNKNOWN_EXT: 1393 return (dgettext(TEXT_DOMAIN, "Unknown extension type")); 1394 case SADB_X_DIAGNOSTIC_BAD_EXTLEN: 1395 return (dgettext(TEXT_DOMAIN, "Bad extension length")); 1396 case SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE: 1397 return (dgettext(TEXT_DOMAIN, 1398 "Unknown Security Association type")); 1399 case SADB_X_DIAGNOSTIC_SATYPE_NEEDED: 1400 return (dgettext(TEXT_DOMAIN, 1401 "Specific Security Association type needed")); 1402 case SADB_X_DIAGNOSTIC_NO_SADBS: 1403 return (dgettext(TEXT_DOMAIN, 1404 "No Security Association Databases present")); 1405 case SADB_X_DIAGNOSTIC_NO_EXT: 1406 return (dgettext(TEXT_DOMAIN, 1407 "No extensions needed for message")); 1408 case SADB_X_DIAGNOSTIC_BAD_SRC_AF: 1409 return (dgettext(TEXT_DOMAIN, "Bad source address family")); 1410 case SADB_X_DIAGNOSTIC_BAD_DST_AF: 1411 return (dgettext(TEXT_DOMAIN, 1412 "Bad destination address family")); 1413 case SADB_X_DIAGNOSTIC_BAD_PROXY_AF: 1414 return (dgettext(TEXT_DOMAIN, 1415 "Bad inner-source address family")); 1416 case SADB_X_DIAGNOSTIC_AF_MISMATCH: 1417 return (dgettext(TEXT_DOMAIN, 1418 "Source/destination address family mismatch")); 1419 case SADB_X_DIAGNOSTIC_BAD_SRC: 1420 return (dgettext(TEXT_DOMAIN, "Bad source address value")); 1421 case SADB_X_DIAGNOSTIC_BAD_DST: 1422 return (dgettext(TEXT_DOMAIN, "Bad destination address value")); 1423 case SADB_X_DIAGNOSTIC_ALLOC_HSERR: 1424 return (dgettext(TEXT_DOMAIN, 1425 "Soft allocations limit more than hard limit")); 1426 case SADB_X_DIAGNOSTIC_BYTES_HSERR: 1427 return (dgettext(TEXT_DOMAIN, 1428 "Soft bytes limit more than hard limit")); 1429 case SADB_X_DIAGNOSTIC_ADDTIME_HSERR: 1430 return (dgettext(TEXT_DOMAIN, "Soft add expiration time later " 1431 "than hard expiration time")); 1432 case SADB_X_DIAGNOSTIC_USETIME_HSERR: 1433 return (dgettext(TEXT_DOMAIN, "Soft use expiration time later " 1434 "than hard expiration time")); 1435 case SADB_X_DIAGNOSTIC_MISSING_SRC: 1436 return (dgettext(TEXT_DOMAIN, "Missing source address")); 1437 case SADB_X_DIAGNOSTIC_MISSING_DST: 1438 return (dgettext(TEXT_DOMAIN, "Missing destination address")); 1439 case SADB_X_DIAGNOSTIC_MISSING_SA: 1440 return (dgettext(TEXT_DOMAIN, "Missing SA extension")); 1441 case SADB_X_DIAGNOSTIC_MISSING_EKEY: 1442 return (dgettext(TEXT_DOMAIN, "Missing encryption key")); 1443 case SADB_X_DIAGNOSTIC_MISSING_AKEY: 1444 return (dgettext(TEXT_DOMAIN, "Missing authentication key")); 1445 case SADB_X_DIAGNOSTIC_MISSING_RANGE: 1446 return (dgettext(TEXT_DOMAIN, "Missing SPI range")); 1447 case SADB_X_DIAGNOSTIC_DUPLICATE_SRC: 1448 return (dgettext(TEXT_DOMAIN, "Duplicate source address")); 1449 case SADB_X_DIAGNOSTIC_DUPLICATE_DST: 1450 return (dgettext(TEXT_DOMAIN, "Duplicate destination address")); 1451 case SADB_X_DIAGNOSTIC_DUPLICATE_SA: 1452 return (dgettext(TEXT_DOMAIN, "Duplicate SA extension")); 1453 case SADB_X_DIAGNOSTIC_DUPLICATE_EKEY: 1454 return (dgettext(TEXT_DOMAIN, "Duplicate encryption key")); 1455 case SADB_X_DIAGNOSTIC_DUPLICATE_AKEY: 1456 return (dgettext(TEXT_DOMAIN, "Duplicate authentication key")); 1457 case SADB_X_DIAGNOSTIC_DUPLICATE_RANGE: 1458 return (dgettext(TEXT_DOMAIN, "Duplicate SPI range")); 1459 case SADB_X_DIAGNOSTIC_MALFORMED_SRC: 1460 return (dgettext(TEXT_DOMAIN, "Malformed source address")); 1461 case SADB_X_DIAGNOSTIC_MALFORMED_DST: 1462 return (dgettext(TEXT_DOMAIN, "Malformed destination address")); 1463 case SADB_X_DIAGNOSTIC_MALFORMED_SA: 1464 return (dgettext(TEXT_DOMAIN, "Malformed SA extension")); 1465 case SADB_X_DIAGNOSTIC_MALFORMED_EKEY: 1466 return (dgettext(TEXT_DOMAIN, "Malformed encryption key")); 1467 case SADB_X_DIAGNOSTIC_MALFORMED_AKEY: 1468 return (dgettext(TEXT_DOMAIN, "Malformed authentication key")); 1469 case SADB_X_DIAGNOSTIC_MALFORMED_RANGE: 1470 return (dgettext(TEXT_DOMAIN, "Malformed SPI range")); 1471 case SADB_X_DIAGNOSTIC_AKEY_PRESENT: 1472 return (dgettext(TEXT_DOMAIN, "Authentication key not needed")); 1473 case SADB_X_DIAGNOSTIC_EKEY_PRESENT: 1474 return (dgettext(TEXT_DOMAIN, "Encryption key not needed")); 1475 case SADB_X_DIAGNOSTIC_PROP_PRESENT: 1476 return (dgettext(TEXT_DOMAIN, "Proposal extension not needed")); 1477 case SADB_X_DIAGNOSTIC_SUPP_PRESENT: 1478 return (dgettext(TEXT_DOMAIN, 1479 "Supported algorithms extension not needed")); 1480 case SADB_X_DIAGNOSTIC_BAD_AALG: 1481 return (dgettext(TEXT_DOMAIN, 1482 "Unsupported authentication algorithm")); 1483 case SADB_X_DIAGNOSTIC_BAD_EALG: 1484 return (dgettext(TEXT_DOMAIN, 1485 "Unsupported encryption algorithm")); 1486 case SADB_X_DIAGNOSTIC_BAD_SAFLAGS: 1487 return (dgettext(TEXT_DOMAIN, "Invalid SA flags")); 1488 case SADB_X_DIAGNOSTIC_BAD_SASTATE: 1489 return (dgettext(TEXT_DOMAIN, "Invalid SA state")); 1490 case SADB_X_DIAGNOSTIC_BAD_AKEYBITS: 1491 return (dgettext(TEXT_DOMAIN, 1492 "Bad number of authentication bits")); 1493 case SADB_X_DIAGNOSTIC_BAD_EKEYBITS: 1494 return (dgettext(TEXT_DOMAIN, 1495 "Bad number of encryption bits")); 1496 case SADB_X_DIAGNOSTIC_ENCR_NOTSUPP: 1497 return (dgettext(TEXT_DOMAIN, 1498 "Encryption not supported for this SA type")); 1499 case SADB_X_DIAGNOSTIC_WEAK_EKEY: 1500 return (dgettext(TEXT_DOMAIN, "Weak encryption key")); 1501 case SADB_X_DIAGNOSTIC_WEAK_AKEY: 1502 return (dgettext(TEXT_DOMAIN, "Weak authentication key")); 1503 case SADB_X_DIAGNOSTIC_DUPLICATE_KMP: 1504 return (dgettext(TEXT_DOMAIN, 1505 "Duplicate key management protocol")); 1506 case SADB_X_DIAGNOSTIC_DUPLICATE_KMC: 1507 return (dgettext(TEXT_DOMAIN, 1508 "Duplicate key management cookie")); 1509 case SADB_X_DIAGNOSTIC_MISSING_NATT_LOC: 1510 return (dgettext(TEXT_DOMAIN, "Missing NAT-T local address")); 1511 case SADB_X_DIAGNOSTIC_MISSING_NATT_REM: 1512 return (dgettext(TEXT_DOMAIN, "Missing NAT-T remote address")); 1513 case SADB_X_DIAGNOSTIC_DUPLICATE_NATT_LOC: 1514 return (dgettext(TEXT_DOMAIN, "Duplicate NAT-T local address")); 1515 case SADB_X_DIAGNOSTIC_DUPLICATE_NATT_REM: 1516 return (dgettext(TEXT_DOMAIN, 1517 "Duplicate NAT-T remote address")); 1518 case SADB_X_DIAGNOSTIC_MALFORMED_NATT_LOC: 1519 return (dgettext(TEXT_DOMAIN, "Malformed NAT-T local address")); 1520 case SADB_X_DIAGNOSTIC_MALFORMED_NATT_REM: 1521 return (dgettext(TEXT_DOMAIN, 1522 "Malformed NAT-T remote address")); 1523 case SADB_X_DIAGNOSTIC_DUPLICATE_NATT_PORTS: 1524 return (dgettext(TEXT_DOMAIN, "Duplicate NAT-T ports")); 1525 case SADB_X_DIAGNOSTIC_MISSING_INNER_SRC: 1526 return (dgettext(TEXT_DOMAIN, "Missing inner source address")); 1527 case SADB_X_DIAGNOSTIC_MISSING_INNER_DST: 1528 return (dgettext(TEXT_DOMAIN, 1529 "Missing inner destination address")); 1530 case SADB_X_DIAGNOSTIC_DUPLICATE_INNER_SRC: 1531 return (dgettext(TEXT_DOMAIN, 1532 "Duplicate inner source address")); 1533 case SADB_X_DIAGNOSTIC_DUPLICATE_INNER_DST: 1534 return (dgettext(TEXT_DOMAIN, 1535 "Duplicate inner destination address")); 1536 case SADB_X_DIAGNOSTIC_MALFORMED_INNER_SRC: 1537 return (dgettext(TEXT_DOMAIN, 1538 "Malformed inner source address")); 1539 case SADB_X_DIAGNOSTIC_MALFORMED_INNER_DST: 1540 return (dgettext(TEXT_DOMAIN, 1541 "Malformed inner destination address")); 1542 case SADB_X_DIAGNOSTIC_PREFIX_INNER_SRC: 1543 return (dgettext(TEXT_DOMAIN, 1544 "Invalid inner-source prefix length ")); 1545 case SADB_X_DIAGNOSTIC_PREFIX_INNER_DST: 1546 return (dgettext(TEXT_DOMAIN, 1547 "Invalid inner-destination prefix length")); 1548 case SADB_X_DIAGNOSTIC_BAD_INNER_DST_AF: 1549 return (dgettext(TEXT_DOMAIN, 1550 "Bad inner-destination address family")); 1551 case SADB_X_DIAGNOSTIC_INNER_AF_MISMATCH: 1552 return (dgettext(TEXT_DOMAIN, 1553 "Inner source/destination address family mismatch")); 1554 case SADB_X_DIAGNOSTIC_BAD_NATT_REM_AF: 1555 return (dgettext(TEXT_DOMAIN, 1556 "Bad NAT-T remote address family")); 1557 case SADB_X_DIAGNOSTIC_BAD_NATT_LOC_AF: 1558 return (dgettext(TEXT_DOMAIN, 1559 "Bad NAT-T local address family")); 1560 case SADB_X_DIAGNOSTIC_PROTO_MISMATCH: 1561 return (dgettext(TEXT_DOMAIN, 1562 "Source/desination protocol mismatch")); 1563 case SADB_X_DIAGNOSTIC_INNER_PROTO_MISMATCH: 1564 return (dgettext(TEXT_DOMAIN, 1565 "Inner source/desination protocol mismatch")); 1566 case SADB_X_DIAGNOSTIC_DUAL_PORT_SETS: 1567 return (dgettext(TEXT_DOMAIN, 1568 "Both inner ports and outer ports are set")); 1569 case SADB_X_DIAGNOSTIC_PAIR_INAPPROPRIATE: 1570 return (dgettext(TEXT_DOMAIN, 1571 "Pairing failed, target SA unsuitable for pairing")); 1572 case SADB_X_DIAGNOSTIC_PAIR_ADD_MISMATCH: 1573 return (dgettext(TEXT_DOMAIN, 1574 "Source/destination address differs from pair SA")); 1575 case SADB_X_DIAGNOSTIC_PAIR_ALREADY: 1576 return (dgettext(TEXT_DOMAIN, 1577 "Already paired with another security association")); 1578 case SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND: 1579 return (dgettext(TEXT_DOMAIN, 1580 "Command failed, pair security association not found")); 1581 case SADB_X_DIAGNOSTIC_BAD_SA_DIRECTION: 1582 return (dgettext(TEXT_DOMAIN, 1583 "Inappropriate SA direction")); 1584 case SADB_X_DIAGNOSTIC_SA_NOTFOUND: 1585 return (dgettext(TEXT_DOMAIN, 1586 "Security association not found")); 1587 case SADB_X_DIAGNOSTIC_SA_EXPIRED: 1588 return (dgettext(TEXT_DOMAIN, 1589 "Security association is not valid")); 1590 case SADB_X_DIAGNOSTIC_BAD_CTX: 1591 return (dgettext(TEXT_DOMAIN, 1592 "Algorithm invalid or not supported by Crypto Framework")); 1593 case SADB_X_DIAGNOSTIC_INVALID_REPLAY: 1594 return (dgettext(TEXT_DOMAIN, 1595 "Invalid Replay counter")); 1596 case SADB_X_DIAGNOSTIC_MISSING_LIFETIME: 1597 return (dgettext(TEXT_DOMAIN, 1598 "Inappropriate lifetimes")); 1599 default: 1600 return (dgettext(TEXT_DOMAIN, "Unknown diagnostic code")); 1601 } 1602 } 1603 1604 /* 1605 * Convert an IPv6 mask to a prefix len. I assume all IPv6 masks are 1606 * contiguous, so I stop at the first zero bit! 1607 */ 1608 int 1609 in_masktoprefix(uint8_t *mask, boolean_t is_v4mapped) 1610 { 1611 int rc = 0; 1612 uint8_t last; 1613 int limit = IPV6_ABITS; 1614 1615 if (is_v4mapped) { 1616 mask += ((IPV6_ABITS - IP_ABITS)/8); 1617 limit = IP_ABITS; 1618 } 1619 1620 while (*mask == 0xff) { 1621 rc += 8; 1622 if (rc == limit) 1623 return (limit); 1624 mask++; 1625 } 1626 1627 last = *mask; 1628 while (last != 0) { 1629 rc++; 1630 last = (last << 1) & 0xff; 1631 } 1632 1633 return (rc); 1634 } 1635 1636 /* 1637 * Expand the diagnostic code into a message. 1638 */ 1639 void 1640 print_diagnostic(FILE *file, uint16_t diagnostic) 1641 { 1642 /* Use two spaces so above strings can fit on the line. */ 1643 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1644 " Diagnostic code %u: %s.\n"), 1645 diagnostic, keysock_diag(diagnostic)); 1646 } 1647 1648 /* 1649 * Prints the base PF_KEY message. 1650 */ 1651 void 1652 print_sadb_msg(FILE *file, struct sadb_msg *samsg, time_t wallclock, 1653 boolean_t vflag) 1654 { 1655 if (wallclock != 0) 1656 printsatime(file, wallclock, dgettext(TEXT_DOMAIN, 1657 "%sTimestamp: %s\n"), "", NULL, 1658 vflag); 1659 1660 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1661 "Base message (version %u) type "), 1662 samsg->sadb_msg_version); 1663 switch (samsg->sadb_msg_type) { 1664 case SADB_RESERVED: 1665 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1666 "RESERVED (warning: set to 0)")); 1667 break; 1668 case SADB_GETSPI: 1669 (void) fprintf(file, "GETSPI"); 1670 break; 1671 case SADB_UPDATE: 1672 (void) fprintf(file, "UPDATE"); 1673 break; 1674 case SADB_X_UPDATEPAIR: 1675 (void) fprintf(file, "UPDATE PAIR"); 1676 break; 1677 case SADB_ADD: 1678 (void) fprintf(file, "ADD"); 1679 break; 1680 case SADB_DELETE: 1681 (void) fprintf(file, "DELETE"); 1682 break; 1683 case SADB_X_DELPAIR: 1684 (void) fprintf(file, "DELETE PAIR"); 1685 break; 1686 case SADB_GET: 1687 (void) fprintf(file, "GET"); 1688 break; 1689 case SADB_ACQUIRE: 1690 (void) fprintf(file, "ACQUIRE"); 1691 break; 1692 case SADB_REGISTER: 1693 (void) fprintf(file, "REGISTER"); 1694 break; 1695 case SADB_EXPIRE: 1696 (void) fprintf(file, "EXPIRE"); 1697 break; 1698 case SADB_FLUSH: 1699 (void) fprintf(file, "FLUSH"); 1700 break; 1701 case SADB_DUMP: 1702 (void) fprintf(file, "DUMP"); 1703 break; 1704 case SADB_X_PROMISC: 1705 (void) fprintf(file, "X_PROMISC"); 1706 break; 1707 case SADB_X_INVERSE_ACQUIRE: 1708 (void) fprintf(file, "X_INVERSE_ACQUIRE"); 1709 break; 1710 default: 1711 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1712 "Unknown (%u)"), samsg->sadb_msg_type); 1713 break; 1714 } 1715 (void) fprintf(file, dgettext(TEXT_DOMAIN, ", SA type ")); 1716 1717 switch (samsg->sadb_msg_satype) { 1718 case SADB_SATYPE_UNSPEC: 1719 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1720 "<unspecified/all>")); 1721 break; 1722 case SADB_SATYPE_AH: 1723 (void) fprintf(file, "AH"); 1724 break; 1725 case SADB_SATYPE_ESP: 1726 (void) fprintf(file, "ESP"); 1727 break; 1728 case SADB_SATYPE_RSVP: 1729 (void) fprintf(file, "RSVP"); 1730 break; 1731 case SADB_SATYPE_OSPFV2: 1732 (void) fprintf(file, "OSPFv2"); 1733 break; 1734 case SADB_SATYPE_RIPV2: 1735 (void) fprintf(file, "RIPv2"); 1736 break; 1737 case SADB_SATYPE_MIP: 1738 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Mobile IP")); 1739 break; 1740 default: 1741 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1742 "<unknown %u>"), samsg->sadb_msg_satype); 1743 break; 1744 } 1745 1746 (void) fprintf(file, ".\n"); 1747 1748 if (samsg->sadb_msg_errno != 0) { 1749 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1750 "Error %s from PF_KEY.\n"), 1751 strerror(samsg->sadb_msg_errno)); 1752 print_diagnostic(file, samsg->sadb_x_msg_diagnostic); 1753 } 1754 1755 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1756 "Message length %u bytes, seq=%u, pid=%u.\n"), 1757 SADB_64TO8(samsg->sadb_msg_len), samsg->sadb_msg_seq, 1758 samsg->sadb_msg_pid); 1759 } 1760 1761 /* 1762 * Print the SA extension for PF_KEY. 1763 */ 1764 void 1765 print_sa(FILE *file, char *prefix, struct sadb_sa *assoc) 1766 { 1767 if (assoc->sadb_sa_len != SADB_8TO64(sizeof (*assoc))) { 1768 warnxfp(EFD(file), dgettext(TEXT_DOMAIN, 1769 "WARNING: SA info extension length (%u) is bad."), 1770 SADB_64TO8(assoc->sadb_sa_len)); 1771 } 1772 1773 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1774 "%sSADB_ASSOC spi=0x%x, replay window size=%u, state="), 1775 prefix, ntohl(assoc->sadb_sa_spi), assoc->sadb_sa_replay); 1776 switch (assoc->sadb_sa_state) { 1777 case SADB_SASTATE_LARVAL: 1778 (void) fprintf(file, dgettext(TEXT_DOMAIN, "LARVAL")); 1779 break; 1780 case SADB_SASTATE_MATURE: 1781 (void) fprintf(file, dgettext(TEXT_DOMAIN, "MATURE")); 1782 break; 1783 case SADB_SASTATE_DYING: 1784 (void) fprintf(file, dgettext(TEXT_DOMAIN, "DYING")); 1785 break; 1786 case SADB_SASTATE_DEAD: 1787 (void) fprintf(file, dgettext(TEXT_DOMAIN, "DEAD")); 1788 break; 1789 case SADB_X_SASTATE_ACTIVE_ELSEWHERE: 1790 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1791 "ACTIVE_ELSEWHERE")); 1792 break; 1793 case SADB_X_SASTATE_IDLE: 1794 (void) fprintf(file, dgettext(TEXT_DOMAIN, "IDLE")); 1795 break; 1796 default: 1797 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1798 "<unknown %u>"), assoc->sadb_sa_state); 1799 } 1800 1801 if (assoc->sadb_sa_auth != SADB_AALG_NONE) { 1802 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1803 "\n%sAuthentication algorithm = "), 1804 prefix); 1805 (void) dump_aalg(assoc->sadb_sa_auth, file); 1806 } 1807 1808 if (assoc->sadb_sa_encrypt != SADB_EALG_NONE) { 1809 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1810 "\n%sEncryption algorithm = "), prefix); 1811 (void) dump_ealg(assoc->sadb_sa_encrypt, file); 1812 } 1813 1814 (void) fprintf(file, dgettext(TEXT_DOMAIN, "\n%sflags=0x%x < "), prefix, 1815 assoc->sadb_sa_flags); 1816 if (assoc->sadb_sa_flags & SADB_SAFLAGS_PFS) 1817 (void) fprintf(file, "PFS "); 1818 if (assoc->sadb_sa_flags & SADB_SAFLAGS_NOREPLAY) 1819 (void) fprintf(file, "NOREPLAY "); 1820 1821 /* BEGIN Solaris-specific flags. */ 1822 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_USED) 1823 (void) fprintf(file, "X_USED "); 1824 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_PAIRED) 1825 (void) fprintf(file, "X_PAIRED "); 1826 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_OUTBOUND) 1827 (void) fprintf(file, "X_OUTBOUND "); 1828 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_INBOUND) 1829 (void) fprintf(file, "X_INBOUND "); 1830 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_UNIQUE) 1831 (void) fprintf(file, "X_UNIQUE "); 1832 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_AALG1) 1833 (void) fprintf(file, "X_AALG1 "); 1834 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_AALG2) 1835 (void) fprintf(file, "X_AALG2 "); 1836 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_EALG1) 1837 (void) fprintf(file, "X_EALG1 "); 1838 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_EALG2) 1839 (void) fprintf(file, "X_EALG2 "); 1840 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_LOC) 1841 (void) fprintf(file, "X_NATT_LOC "); 1842 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_REM) 1843 (void) fprintf(file, "X_NATT_REM "); 1844 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_TUNNEL) 1845 (void) fprintf(file, "X_TUNNEL "); 1846 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATTED) 1847 (void) fprintf(file, "X_NATTED "); 1848 /* END Solaris-specific flags. */ 1849 1850 (void) fprintf(file, ">\n"); 1851 } 1852 1853 void 1854 printsatime(FILE *file, int64_t lt, const char *msg, const char *pfx, 1855 const char *pfx2, boolean_t vflag) 1856 { 1857 char tbuf[TBUF_SIZE]; /* For strftime() call. */ 1858 const char *tp = tbuf; 1859 time_t t = lt; 1860 struct tm res; 1861 1862 if (t != lt) { 1863 if (lt > 0) 1864 t = LONG_MAX; 1865 else 1866 t = LONG_MIN; 1867 } 1868 1869 if (strftime(tbuf, TBUF_SIZE, NULL, localtime_r(&t, &res)) == 0) 1870 tp = dgettext(TEXT_DOMAIN, "<time conversion failed>"); 1871 (void) fprintf(file, msg, pfx, tp); 1872 if (vflag && (pfx2 != NULL)) 1873 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1874 "%s\t(raw time value %" PRIu64 ")\n"), pfx2, lt); 1875 } 1876 1877 /* 1878 * Print the SA lifetime information. (An SADB_EXT_LIFETIME_* extension.) 1879 */ 1880 void 1881 print_lifetimes(FILE *file, time_t wallclock, struct sadb_lifetime *current, 1882 struct sadb_lifetime *hard, struct sadb_lifetime *soft, 1883 struct sadb_lifetime *idle, boolean_t vflag) 1884 { 1885 int64_t scratch; 1886 char *soft_prefix = dgettext(TEXT_DOMAIN, "SLT: "); 1887 char *hard_prefix = dgettext(TEXT_DOMAIN, "HLT: "); 1888 char *current_prefix = dgettext(TEXT_DOMAIN, "CLT: "); 1889 char *idle_prefix = dgettext(TEXT_DOMAIN, "ILT: "); 1890 char byte_str[BYTE_STR_SIZE]; /* byte lifetime string representation */ 1891 char secs_str[SECS_STR_SIZE]; /* buffer for seconds representation */ 1892 1893 if (current != NULL && 1894 current->sadb_lifetime_len != SADB_8TO64(sizeof (*current))) { 1895 warnxfp(EFD(file), dgettext(TEXT_DOMAIN, 1896 "WARNING: CURRENT lifetime extension length (%u) is bad."), 1897 SADB_64TO8(current->sadb_lifetime_len)); 1898 } 1899 1900 if (hard != NULL && 1901 hard->sadb_lifetime_len != SADB_8TO64(sizeof (*hard))) { 1902 warnxfp(EFD(file), dgettext(TEXT_DOMAIN, 1903 "WARNING: HARD lifetime extension length (%u) is bad."), 1904 SADB_64TO8(hard->sadb_lifetime_len)); 1905 } 1906 1907 if (soft != NULL && 1908 soft->sadb_lifetime_len != SADB_8TO64(sizeof (*soft))) { 1909 warnxfp(EFD(file), dgettext(TEXT_DOMAIN, 1910 "WARNING: SOFT lifetime extension length (%u) is bad."), 1911 SADB_64TO8(soft->sadb_lifetime_len)); 1912 } 1913 1914 if (idle != NULL && 1915 idle->sadb_lifetime_len != SADB_8TO64(sizeof (*idle))) { 1916 warnxfp(EFD(file), dgettext(TEXT_DOMAIN, 1917 "WARNING: IDLE lifetime extension length (%u) is bad."), 1918 SADB_64TO8(idle->sadb_lifetime_len)); 1919 } 1920 1921 (void) fprintf(file, " LT: Lifetime information\n"); 1922 if (current != NULL) { 1923 /* Express values as current values. */ 1924 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1925 "%sCurrent lifetime information:\n"), 1926 current_prefix); 1927 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1928 "%s%" PRIu64 " bytes %sprotected, %u allocations " 1929 "used.\n"), current_prefix, 1930 current->sadb_lifetime_bytes, 1931 bytecnt2out(current->sadb_lifetime_bytes, byte_str, 1932 sizeof (byte_str), SPC_END), 1933 current->sadb_lifetime_allocations); 1934 printsatime(file, current->sadb_lifetime_addtime, 1935 dgettext(TEXT_DOMAIN, "%sSA added at time: %s\n"), 1936 current_prefix, current_prefix, vflag); 1937 if (current->sadb_lifetime_usetime != 0) { 1938 printsatime(file, current->sadb_lifetime_usetime, 1939 dgettext(TEXT_DOMAIN, 1940 "%sSA first used at time %s\n"), 1941 current_prefix, current_prefix, vflag); 1942 } 1943 printsatime(file, wallclock, dgettext(TEXT_DOMAIN, 1944 "%sTime now is %s\n"), current_prefix, current_prefix, 1945 vflag); 1946 } 1947 1948 if (soft != NULL) { 1949 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1950 "%sSoft lifetime information:\n"), 1951 soft_prefix); 1952 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1953 "%s%" PRIu64 " bytes %sof lifetime, %u allocations.\n"), 1954 soft_prefix, 1955 soft->sadb_lifetime_bytes, 1956 bytecnt2out(soft->sadb_lifetime_bytes, byte_str, 1957 sizeof (byte_str), SPC_END), 1958 soft->sadb_lifetime_allocations); 1959 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1960 "%s%" PRIu64 " seconds %sof post-add lifetime.\n"), 1961 soft_prefix, soft->sadb_lifetime_addtime, 1962 secs2out(soft->sadb_lifetime_addtime, secs_str, 1963 sizeof (secs_str), SPC_END)); 1964 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1965 "%s%" PRIu64 " seconds %sof post-use lifetime.\n"), 1966 soft_prefix, soft->sadb_lifetime_usetime, 1967 secs2out(soft->sadb_lifetime_usetime, secs_str, 1968 sizeof (secs_str), SPC_END)); 1969 /* If possible, express values as time remaining. */ 1970 if (current != NULL) { 1971 if (soft->sadb_lifetime_bytes != 0) 1972 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%s" 1973 "%" PRIu64 " bytes %smore can be " 1974 "protected.\n"), soft_prefix, 1975 (soft->sadb_lifetime_bytes > 1976 current->sadb_lifetime_bytes) ? 1977 soft->sadb_lifetime_bytes - 1978 current->sadb_lifetime_bytes : 0, 1979 (soft->sadb_lifetime_bytes > 1980 current->sadb_lifetime_bytes) ? 1981 bytecnt2out(soft->sadb_lifetime_bytes - 1982 current->sadb_lifetime_bytes, byte_str, 1983 sizeof (byte_str), SPC_END) : ""); 1984 if (soft->sadb_lifetime_addtime != 0 || 1985 (soft->sadb_lifetime_usetime != 0 && 1986 current->sadb_lifetime_usetime != 0)) { 1987 int64_t adddelta, usedelta; 1988 1989 if (soft->sadb_lifetime_addtime != 0) { 1990 adddelta = 1991 current->sadb_lifetime_addtime + 1992 soft->sadb_lifetime_addtime - 1993 wallclock; 1994 } else { 1995 adddelta = TIME_MAX; 1996 } 1997 1998 if (soft->sadb_lifetime_usetime != 0 && 1999 current->sadb_lifetime_usetime != 0) { 2000 usedelta = 2001 current->sadb_lifetime_usetime + 2002 soft->sadb_lifetime_usetime - 2003 wallclock; 2004 } else { 2005 usedelta = TIME_MAX; 2006 } 2007 (void) fprintf(file, "%s", soft_prefix); 2008 scratch = MIN(adddelta, usedelta); 2009 if (scratch >= 0) { 2010 (void) fprintf(file, 2011 dgettext(TEXT_DOMAIN, 2012 "Soft expiration occurs in %" 2013 PRId64 " seconds%s\n"), scratch, 2014 secs2out(scratch, secs_str, 2015 sizeof (secs_str), SPC_BEGIN)); 2016 } else { 2017 (void) fprintf(file, 2018 dgettext(TEXT_DOMAIN, 2019 "Soft expiration occurred\n")); 2020 } 2021 scratch += wallclock; 2022 printsatime(file, scratch, dgettext(TEXT_DOMAIN, 2023 "%sTime of expiration: %s.\n"), 2024 soft_prefix, soft_prefix, vflag); 2025 } 2026 } 2027 } 2028 2029 if (hard != NULL) { 2030 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2031 "%sHard lifetime information:\n"), hard_prefix); 2032 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2033 "%s%" PRIu64 " bytes %sof lifetime, %u allocations.\n"), 2034 hard_prefix, 2035 hard->sadb_lifetime_bytes, 2036 bytecnt2out(hard->sadb_lifetime_bytes, byte_str, 2037 sizeof (byte_str), SPC_END), 2038 hard->sadb_lifetime_allocations); 2039 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2040 "%s%" PRIu64 " seconds %sof post-add lifetime.\n"), 2041 hard_prefix, hard->sadb_lifetime_addtime, 2042 secs2out(hard->sadb_lifetime_addtime, secs_str, 2043 sizeof (secs_str), SPC_END)); 2044 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2045 "%s%" PRIu64 " seconds %sof post-use lifetime.\n"), 2046 hard_prefix, hard->sadb_lifetime_usetime, 2047 secs2out(hard->sadb_lifetime_usetime, secs_str, 2048 sizeof (secs_str), SPC_END)); 2049 /* If possible, express values as time remaining. */ 2050 if (current != NULL) { 2051 if (hard->sadb_lifetime_bytes != 0) 2052 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%s" 2053 "%" PRIu64 " bytes %smore can be " 2054 "protected.\n"), hard_prefix, 2055 (hard->sadb_lifetime_bytes > 2056 current->sadb_lifetime_bytes) ? 2057 hard->sadb_lifetime_bytes - 2058 current->sadb_lifetime_bytes : 0, 2059 (hard->sadb_lifetime_bytes > 2060 current->sadb_lifetime_bytes) ? 2061 bytecnt2out(hard->sadb_lifetime_bytes - 2062 current->sadb_lifetime_bytes, byte_str, 2063 sizeof (byte_str), SPC_END) : ""); 2064 if (hard->sadb_lifetime_addtime != 0 || 2065 (hard->sadb_lifetime_usetime != 0 && 2066 current->sadb_lifetime_usetime != 0)) { 2067 int64_t adddelta, usedelta; 2068 2069 if (hard->sadb_lifetime_addtime != 0) { 2070 adddelta = 2071 current->sadb_lifetime_addtime + 2072 hard->sadb_lifetime_addtime - 2073 wallclock; 2074 } else { 2075 adddelta = TIME_MAX; 2076 } 2077 2078 if (hard->sadb_lifetime_usetime != 0 && 2079 current->sadb_lifetime_usetime != 0) { 2080 usedelta = 2081 current->sadb_lifetime_usetime + 2082 hard->sadb_lifetime_usetime - 2083 wallclock; 2084 } else { 2085 usedelta = TIME_MAX; 2086 } 2087 (void) fprintf(file, "%s", hard_prefix); 2088 scratch = MIN(adddelta, usedelta); 2089 if (scratch >= 0) { 2090 (void) fprintf(file, 2091 dgettext(TEXT_DOMAIN, 2092 "Hard expiration occurs in %" 2093 PRId64 " seconds%s\n"), scratch, 2094 secs2out(scratch, secs_str, 2095 sizeof (secs_str), SPC_BEGIN)); 2096 } else { 2097 (void) fprintf(file, 2098 dgettext(TEXT_DOMAIN, 2099 "Hard expiration occurred\n")); 2100 } 2101 scratch += wallclock; 2102 printsatime(file, scratch, dgettext(TEXT_DOMAIN, 2103 "%sTime of expiration: %s.\n"), 2104 hard_prefix, hard_prefix, vflag); 2105 } 2106 } 2107 } 2108 if (idle != NULL) { 2109 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2110 "%sIdle lifetime information:\n"), idle_prefix); 2111 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2112 "%s%" PRIu64 " seconds %sof post-add lifetime.\n"), 2113 idle_prefix, idle->sadb_lifetime_addtime, 2114 secs2out(idle->sadb_lifetime_addtime, secs_str, 2115 sizeof (secs_str), SPC_END)); 2116 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2117 "%s%" PRIu64 " seconds %sof post-use lifetime.\n"), 2118 idle_prefix, idle->sadb_lifetime_usetime, 2119 secs2out(idle->sadb_lifetime_usetime, secs_str, 2120 sizeof (secs_str), SPC_END)); 2121 } 2122 } 2123 2124 /* 2125 * Print an SADB_EXT_ADDRESS_* extension. 2126 */ 2127 void 2128 print_address(FILE *file, char *prefix, struct sadb_address *addr, 2129 boolean_t ignore_nss) 2130 { 2131 struct protoent *pe; 2132 2133 (void) fprintf(file, "%s", prefix); 2134 switch (addr->sadb_address_exttype) { 2135 case SADB_EXT_ADDRESS_SRC: 2136 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Source address ")); 2137 break; 2138 case SADB_X_EXT_ADDRESS_INNER_SRC: 2139 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2140 "Inner source address ")); 2141 break; 2142 case SADB_EXT_ADDRESS_DST: 2143 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2144 "Destination address ")); 2145 break; 2146 case SADB_X_EXT_ADDRESS_INNER_DST: 2147 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2148 "Inner destination address ")); 2149 break; 2150 case SADB_X_EXT_ADDRESS_NATT_LOC: 2151 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2152 "NAT-T local address ")); 2153 break; 2154 case SADB_X_EXT_ADDRESS_NATT_REM: 2155 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2156 "NAT-T remote address ")); 2157 break; 2158 } 2159 2160 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2161 "(proto=%d"), addr->sadb_address_proto); 2162 if (ignore_nss == B_FALSE) { 2163 if (addr->sadb_address_proto == 0) { 2164 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2165 "/<unspecified>")); 2166 } else if ((pe = getprotobynumber(addr->sadb_address_proto)) 2167 != NULL) { 2168 (void) fprintf(file, "/%s", pe->p_name); 2169 } else { 2170 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2171 "/<unknown>")); 2172 } 2173 } 2174 (void) fprintf(file, dgettext(TEXT_DOMAIN, ")\n%s"), prefix); 2175 (void) dump_sockaddr((struct sockaddr *)(addr + 1), 2176 addr->sadb_address_prefixlen, B_FALSE, file, ignore_nss); 2177 } 2178 2179 /* 2180 * Print an SADB_EXT_KEY extension. 2181 */ 2182 void 2183 print_key(FILE *file, char *prefix, struct sadb_key *key) 2184 { 2185 (void) fprintf(file, "%s", prefix); 2186 2187 switch (key->sadb_key_exttype) { 2188 case SADB_EXT_KEY_AUTH: 2189 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Authentication")); 2190 break; 2191 case SADB_EXT_KEY_ENCRYPT: 2192 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Encryption")); 2193 break; 2194 } 2195 2196 (void) fprintf(file, dgettext(TEXT_DOMAIN, " key.\n%s"), prefix); 2197 (void) dump_key((uint8_t *)(key + 1), key->sadb_key_bits, 2198 key->sadb_key_reserved, file, B_TRUE); 2199 (void) fprintf(file, "\n"); 2200 } 2201 2202 /* 2203 * Print an SADB_EXT_IDENTITY_* extension. 2204 */ 2205 void 2206 print_ident(FILE *file, char *prefix, struct sadb_ident *id) 2207 { 2208 boolean_t canprint = B_TRUE; 2209 2210 (void) fprintf(file, "%s", prefix); 2211 switch (id->sadb_ident_exttype) { 2212 case SADB_EXT_IDENTITY_SRC: 2213 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Source")); 2214 break; 2215 case SADB_EXT_IDENTITY_DST: 2216 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Destination")); 2217 break; 2218 } 2219 2220 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2221 " identity, uid=%d, type "), id->sadb_ident_id); 2222 canprint = dump_sadb_idtype(id->sadb_ident_type, file, NULL); 2223 (void) fprintf(file, "\n%s", prefix); 2224 if (canprint) { 2225 (void) fprintf(file, "%s\n", (char *)(id + 1)); 2226 } else { 2227 print_asn1_name(file, (const unsigned char *)(id + 1), 2228 SADB_64TO8(id->sadb_ident_len) - sizeof (sadb_ident_t)); 2229 } 2230 } 2231 2232 /* 2233 * Convert sadb_sens extension into binary security label. 2234 */ 2235 2236 #include <tsol/label.h> 2237 #include <sys/tsol/tndb.h> 2238 #include <sys/tsol/label_macro.h> 2239 2240 void 2241 ipsec_convert_sens_to_bslabel(const struct sadb_sens *sens, bslabel_t *sl) 2242 { 2243 uint64_t *bitmap = (uint64_t *)(sens + 1); 2244 int bitmap_len = SADB_64TO8(sens->sadb_sens_sens_len); 2245 2246 bsllow(sl); 2247 LCLASS_SET((_bslabel_impl_t *)sl, sens->sadb_sens_sens_level); 2248 bcopy(bitmap, &((_bslabel_impl_t *)sl)->compartments, 2249 bitmap_len); 2250 } 2251 2252 void 2253 ipsec_convert_bslabel_to_string(bslabel_t *sl, char **plabel) 2254 { 2255 if (label_to_str(sl, plabel, M_LABEL, DEF_NAMES) != 0) { 2256 *plabel = strdup(dgettext(TEXT_DOMAIN, 2257 "** Label conversion failed **")); 2258 } 2259 } 2260 2261 void 2262 ipsec_convert_bslabel_to_hex(bslabel_t *sl, char **plabel) 2263 { 2264 if (label_to_str(sl, plabel, M_INTERNAL, DEF_NAMES) != 0) { 2265 *plabel = strdup(dgettext(TEXT_DOMAIN, 2266 "** Label conversion failed **")); 2267 } 2268 } 2269 2270 int 2271 ipsec_convert_sl_to_sens(int doi, bslabel_t *sl, sadb_sens_t *sens) 2272 { 2273 uint8_t *bitmap; 2274 int sens_len = sizeof (sadb_sens_t) + _C_LEN * 4; 2275 2276 2277 if (sens == NULL) 2278 return (sens_len); 2279 2280 2281 (void) memset(sens, 0, sens_len); 2282 2283 sens->sadb_sens_exttype = SADB_EXT_SENSITIVITY; 2284 sens->sadb_sens_len = SADB_8TO64(sens_len); 2285 sens->sadb_sens_dpd = doi; 2286 2287 sens->sadb_sens_sens_level = LCLASS(sl); 2288 sens->sadb_sens_integ_level = 0; 2289 sens->sadb_sens_sens_len = _C_LEN >> 1; 2290 sens->sadb_sens_integ_len = 0; 2291 2292 sens->sadb_x_sens_flags = 0; 2293 2294 bitmap = (uint8_t *)(sens + 1); 2295 bcopy(&(((_bslabel_impl_t *)sl)->compartments), bitmap, _C_LEN * 4); 2296 2297 return (sens_len); 2298 } 2299 2300 2301 /* 2302 * Print an SADB_SENSITIVITY extension. 2303 */ 2304 void 2305 print_sens(FILE *file, char *prefix, const struct sadb_sens *sens, 2306 boolean_t ignore_nss) 2307 { 2308 char *plabel; 2309 char *hlabel; 2310 uint64_t *bitmap = (uint64_t *)(sens + 1); 2311 bslabel_t sl; 2312 int i; 2313 int sens_len = sens->sadb_sens_sens_len; 2314 int integ_len = sens->sadb_sens_integ_len; 2315 boolean_t inner = (sens->sadb_sens_exttype == SADB_EXT_SENSITIVITY); 2316 const char *sensname = inner ? 2317 dgettext(TEXT_DOMAIN, "Plaintext Sensitivity") : 2318 dgettext(TEXT_DOMAIN, "Ciphertext Sensitivity"); 2319 2320 ipsec_convert_sens_to_bslabel(sens, &sl); 2321 2322 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2323 "%s%s DPD %d, sens level=%d, integ level=%d, flags=%x\n"), 2324 prefix, sensname, sens->sadb_sens_dpd, sens->sadb_sens_sens_level, 2325 sens->sadb_sens_integ_level, sens->sadb_x_sens_flags); 2326 2327 ipsec_convert_bslabel_to_hex(&sl, &hlabel); 2328 2329 if (ignore_nss) { 2330 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2331 "%s %s Label: %s\n"), prefix, sensname, hlabel); 2332 2333 for (i = 0; i < sens_len; i++, bitmap++) 2334 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2335 "%s %s BM extended word %d 0x%" PRIx64 "\n"), 2336 prefix, sensname, i, *bitmap); 2337 2338 } else { 2339 ipsec_convert_bslabel_to_string(&sl, &plabel); 2340 2341 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2342 "%s %s Label: %s (%s)\n"), 2343 prefix, sensname, plabel, hlabel); 2344 free(plabel); 2345 2346 } 2347 free(hlabel); 2348 2349 bitmap = (uint64_t *)(sens + 1 + sens_len); 2350 2351 for (i = 0; i < integ_len; i++, bitmap++) 2352 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2353 "%s Integrity BM extended word %d 0x%" PRIx64 "\n"), 2354 prefix, i, *bitmap); 2355 } 2356 2357 /* 2358 * Print an SADB_EXT_PROPOSAL extension. 2359 */ 2360 void 2361 print_prop(FILE *file, char *prefix, struct sadb_prop *prop) 2362 { 2363 struct sadb_comb *combs; 2364 int i, numcombs; 2365 2366 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2367 "%sProposal, replay counter = %u.\n"), prefix, 2368 prop->sadb_prop_replay); 2369 2370 numcombs = prop->sadb_prop_len - SADB_8TO64(sizeof (*prop)); 2371 numcombs /= SADB_8TO64(sizeof (*combs)); 2372 2373 combs = (struct sadb_comb *)(prop + 1); 2374 2375 for (i = 0; i < numcombs; i++) { 2376 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2377 "%s Combination #%u "), prefix, i + 1); 2378 if (combs[i].sadb_comb_auth != SADB_AALG_NONE) { 2379 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2380 "Authentication = ")); 2381 (void) dump_aalg(combs[i].sadb_comb_auth, file); 2382 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2383 " minbits=%u, maxbits=%u.\n%s "), 2384 combs[i].sadb_comb_auth_minbits, 2385 combs[i].sadb_comb_auth_maxbits, prefix); 2386 } 2387 2388 if (combs[i].sadb_comb_encrypt != SADB_EALG_NONE) { 2389 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2390 "Encryption = ")); 2391 (void) dump_ealg(combs[i].sadb_comb_encrypt, file); 2392 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2393 " minbits=%u, maxbits=%u, saltbits=%u.\n%s "), 2394 combs[i].sadb_comb_encrypt_minbits, 2395 combs[i].sadb_comb_encrypt_maxbits, 2396 combs[i].sadb_x_comb_encrypt_saltbits, prefix); 2397 } 2398 2399 (void) fprintf(file, dgettext(TEXT_DOMAIN, "HARD: ")); 2400 if (combs[i].sadb_comb_hard_allocations) 2401 (void) fprintf(file, dgettext(TEXT_DOMAIN, "alloc=%u "), 2402 combs[i].sadb_comb_hard_allocations); 2403 if (combs[i].sadb_comb_hard_bytes) 2404 (void) fprintf(file, dgettext(TEXT_DOMAIN, "bytes=%" 2405 PRIu64 " "), combs[i].sadb_comb_hard_bytes); 2406 if (combs[i].sadb_comb_hard_addtime) 2407 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2408 "post-add secs=%" PRIu64 " "), 2409 combs[i].sadb_comb_hard_addtime); 2410 if (combs[i].sadb_comb_hard_usetime) 2411 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2412 "post-use secs=%" PRIu64 ""), 2413 combs[i].sadb_comb_hard_usetime); 2414 2415 (void) fprintf(file, dgettext(TEXT_DOMAIN, "\n%s SOFT: "), 2416 prefix); 2417 if (combs[i].sadb_comb_soft_allocations) 2418 (void) fprintf(file, dgettext(TEXT_DOMAIN, "alloc=%u "), 2419 combs[i].sadb_comb_soft_allocations); 2420 if (combs[i].sadb_comb_soft_bytes) 2421 (void) fprintf(file, dgettext(TEXT_DOMAIN, "bytes=%" 2422 PRIu64 " "), combs[i].sadb_comb_soft_bytes); 2423 if (combs[i].sadb_comb_soft_addtime) 2424 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2425 "post-add secs=%" PRIu64 " "), 2426 combs[i].sadb_comb_soft_addtime); 2427 if (combs[i].sadb_comb_soft_usetime) 2428 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2429 "post-use secs=%" PRIu64 ""), 2430 combs[i].sadb_comb_soft_usetime); 2431 (void) fprintf(file, "\n"); 2432 } 2433 } 2434 2435 /* 2436 * Print an extended proposal (SADB_X_EXT_EPROP). 2437 */ 2438 void 2439 print_eprop(FILE *file, char *prefix, struct sadb_prop *eprop) 2440 { 2441 uint64_t *sofar; 2442 struct sadb_x_ecomb *ecomb; 2443 struct sadb_x_algdesc *algdesc; 2444 int i, j; 2445 2446 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2447 "%sExtended Proposal, replay counter = %u, "), prefix, 2448 eprop->sadb_prop_replay); 2449 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2450 "number of combinations = %u.\n"), eprop->sadb_x_prop_numecombs); 2451 2452 sofar = (uint64_t *)(eprop + 1); 2453 ecomb = (struct sadb_x_ecomb *)sofar; 2454 2455 for (i = 0; i < eprop->sadb_x_prop_numecombs; ) { 2456 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2457 "%s Extended combination #%u:\n"), prefix, ++i); 2458 2459 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%s HARD: "), 2460 prefix); 2461 (void) fprintf(file, dgettext(TEXT_DOMAIN, "alloc=%u, "), 2462 ecomb->sadb_x_ecomb_hard_allocations); 2463 (void) fprintf(file, dgettext(TEXT_DOMAIN, "bytes=%" PRIu64 2464 ", "), ecomb->sadb_x_ecomb_hard_bytes); 2465 (void) fprintf(file, dgettext(TEXT_DOMAIN, "post-add secs=%" 2466 PRIu64 ", "), ecomb->sadb_x_ecomb_hard_addtime); 2467 (void) fprintf(file, dgettext(TEXT_DOMAIN, "post-use secs=%" 2468 PRIu64 "\n"), ecomb->sadb_x_ecomb_hard_usetime); 2469 2470 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%s SOFT: "), 2471 prefix); 2472 (void) fprintf(file, dgettext(TEXT_DOMAIN, "alloc=%u, "), 2473 ecomb->sadb_x_ecomb_soft_allocations); 2474 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2475 "bytes=%" PRIu64 ", "), ecomb->sadb_x_ecomb_soft_bytes); 2476 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2477 "post-add secs=%" PRIu64 ", "), 2478 ecomb->sadb_x_ecomb_soft_addtime); 2479 (void) fprintf(file, dgettext(TEXT_DOMAIN, "post-use secs=%" 2480 PRIu64 "\n"), ecomb->sadb_x_ecomb_soft_usetime); 2481 2482 sofar = (uint64_t *)(ecomb + 1); 2483 algdesc = (struct sadb_x_algdesc *)sofar; 2484 2485 for (j = 0; j < ecomb->sadb_x_ecomb_numalgs; ) { 2486 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2487 "%s Alg #%u "), prefix, ++j); 2488 switch (algdesc->sadb_x_algdesc_satype) { 2489 case SADB_SATYPE_ESP: 2490 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2491 "for ESP ")); 2492 break; 2493 case SADB_SATYPE_AH: 2494 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2495 "for AH ")); 2496 break; 2497 default: 2498 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2499 "for satype=%d "), 2500 algdesc->sadb_x_algdesc_satype); 2501 } 2502 switch (algdesc->sadb_x_algdesc_algtype) { 2503 case SADB_X_ALGTYPE_CRYPT: 2504 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2505 "Encryption = ")); 2506 (void) dump_ealg(algdesc->sadb_x_algdesc_alg, 2507 file); 2508 break; 2509 case SADB_X_ALGTYPE_AUTH: 2510 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2511 "Authentication = ")); 2512 (void) dump_aalg(algdesc->sadb_x_algdesc_alg, 2513 file); 2514 break; 2515 default: 2516 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2517 "algtype(%d) = alg(%d)"), 2518 algdesc->sadb_x_algdesc_algtype, 2519 algdesc->sadb_x_algdesc_alg); 2520 break; 2521 } 2522 2523 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2524 " minbits=%u, maxbits=%u, saltbits=%u\n"), 2525 algdesc->sadb_x_algdesc_minbits, 2526 algdesc->sadb_x_algdesc_maxbits, 2527 algdesc->sadb_x_algdesc_saltbits); 2528 2529 sofar = (uint64_t *)(++algdesc); 2530 } 2531 ecomb = (struct sadb_x_ecomb *)sofar; 2532 } 2533 } 2534 2535 /* 2536 * Print an SADB_EXT_SUPPORTED extension. 2537 */ 2538 void 2539 print_supp(FILE *file, char *prefix, struct sadb_supported *supp) 2540 { 2541 struct sadb_alg *algs; 2542 int i, numalgs; 2543 2544 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%sSupported "), prefix); 2545 switch (supp->sadb_supported_exttype) { 2546 case SADB_EXT_SUPPORTED_AUTH: 2547 (void) fprintf(file, dgettext(TEXT_DOMAIN, "authentication")); 2548 break; 2549 case SADB_EXT_SUPPORTED_ENCRYPT: 2550 (void) fprintf(file, dgettext(TEXT_DOMAIN, "encryption")); 2551 break; 2552 } 2553 (void) fprintf(file, dgettext(TEXT_DOMAIN, " algorithms.\n")); 2554 2555 algs = (struct sadb_alg *)(supp + 1); 2556 numalgs = supp->sadb_supported_len - SADB_8TO64(sizeof (*supp)); 2557 numalgs /= SADB_8TO64(sizeof (*algs)); 2558 for (i = 0; i < numalgs; i++) { 2559 uint16_t exttype = supp->sadb_supported_exttype; 2560 2561 (void) fprintf(file, "%s", prefix); 2562 switch (exttype) { 2563 case SADB_EXT_SUPPORTED_AUTH: 2564 (void) dump_aalg(algs[i].sadb_alg_id, file); 2565 break; 2566 case SADB_EXT_SUPPORTED_ENCRYPT: 2567 (void) dump_ealg(algs[i].sadb_alg_id, file); 2568 break; 2569 } 2570 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2571 " minbits=%u, maxbits=%u, ivlen=%u, saltbits=%u"), 2572 algs[i].sadb_alg_minbits, algs[i].sadb_alg_maxbits, 2573 algs[i].sadb_alg_ivlen, algs[i].sadb_x_alg_saltbits); 2574 if (exttype == SADB_EXT_SUPPORTED_ENCRYPT) 2575 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2576 ", increment=%u"), algs[i].sadb_x_alg_increment); 2577 (void) fprintf(file, dgettext(TEXT_DOMAIN, ".\n")); 2578 } 2579 } 2580 2581 /* 2582 * Print an SADB_EXT_SPIRANGE extension. 2583 */ 2584 void 2585 print_spirange(FILE *file, char *prefix, struct sadb_spirange *range) 2586 { 2587 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2588 "%sSPI Range, min=0x%x, max=0x%x\n"), prefix, 2589 htonl(range->sadb_spirange_min), 2590 htonl(range->sadb_spirange_max)); 2591 } 2592 2593 /* 2594 * Print an SADB_X_EXT_KM_COOKIE extension. 2595 */ 2596 2597 void 2598 print_kmc(FILE *file, char *prefix, struct sadb_x_kmc *kmc) 2599 { 2600 char *cookie_label; 2601 2602 switch (kmc->sadb_x_kmc_proto) { 2603 case SADB_X_KMP_IKE: 2604 cookie_label = kmc_lookup_by_cookie(kmc->sadb_x_kmc_cookie); 2605 if (cookie_label == NULL) 2606 cookie_label = 2607 dgettext(TEXT_DOMAIN, "<Label not found.>"); 2608 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2609 "%s Protocol %u, cookie=\"%s\" (%u)\n"), prefix, 2610 kmc->sadb_x_kmc_proto, cookie_label, 2611 kmc->sadb_x_kmc_cookie); 2612 return; 2613 case SADB_X_KMP_KINK: 2614 cookie_label = dgettext(TEXT_DOMAIN, "KINK:"); 2615 break; 2616 case SADB_X_KMP_MANUAL: 2617 cookie_label = dgettext(TEXT_DOMAIN, "Manual SA with cookie:"); 2618 break; 2619 case SADB_X_KMP_IKEV2: 2620 cookie_label = dgettext(TEXT_DOMAIN, "IKEV2:"); 2621 break; 2622 default: 2623 cookie_label = 2624 dgettext(TEXT_DOMAIN, "<unknown KM protocol>"); 2625 break; 2626 } 2627 2628 /* 2629 * Assume native-byte-order printing for now. Exceptions (like 2630 * byte-swapping) should be handled in per-KM-protocol cases above. 2631 */ 2632 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2633 "%s Protocol %u, cookie=\"%s\" (0x%"PRIx64"/%"PRIu64")\n"), 2634 prefix, kmc->sadb_x_kmc_proto, cookie_label, 2635 kmc->sadb_x_kmc_cookie64, kmc->sadb_x_kmc_cookie64); 2636 } 2637 2638 /* 2639 * Print an SADB_X_EXT_REPLAY_CTR extension. 2640 */ 2641 2642 void 2643 print_replay(FILE *file, char *prefix, sadb_x_replay_ctr_t *repl) 2644 { 2645 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2646 "%sReplay Value "), prefix); 2647 if ((repl->sadb_x_rc_replay32 == 0) && 2648 (repl->sadb_x_rc_replay64 == 0)) { 2649 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2650 "<Value not found.>")); 2651 } 2652 /* 2653 * We currently do not support a 64-bit replay value. 2654 * RFC 4301 will require one, however, and we have a field 2655 * in place when 4301 is built. 2656 */ 2657 (void) fprintf(file, "% " PRIu64 "\n", 2658 ((repl->sadb_x_rc_replay32 == 0) ? 2659 repl->sadb_x_rc_replay64 : repl->sadb_x_rc_replay32)); 2660 } 2661 /* 2662 * Print an SADB_X_EXT_PAIR extension. 2663 */ 2664 static void 2665 print_pair(FILE *file, char *prefix, struct sadb_x_pair *pair) 2666 { 2667 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%sPaired with spi=0x%x\n"), 2668 prefix, ntohl(pair->sadb_x_pair_spi)); 2669 } 2670 2671 /* 2672 * Take a PF_KEY message pointed to buffer and print it. Useful for DUMP 2673 * and GET. 2674 */ 2675 void 2676 print_samsg(FILE *file, uint64_t *buffer, boolean_t want_timestamp, 2677 boolean_t vflag, boolean_t ignore_nss) 2678 { 2679 uint64_t *current; 2680 struct sadb_msg *samsg = (struct sadb_msg *)buffer; 2681 struct sadb_ext *ext; 2682 struct sadb_lifetime *currentlt = NULL, *hardlt = NULL, *softlt = NULL; 2683 struct sadb_lifetime *idlelt = NULL; 2684 int i; 2685 time_t wallclock; 2686 2687 (void) time(&wallclock); 2688 2689 print_sadb_msg(file, samsg, want_timestamp ? wallclock : 0, vflag); 2690 current = (uint64_t *)(samsg + 1); 2691 while (current - buffer < samsg->sadb_msg_len) { 2692 int lenbytes; 2693 2694 ext = (struct sadb_ext *)current; 2695 lenbytes = SADB_64TO8(ext->sadb_ext_len); 2696 switch (ext->sadb_ext_type) { 2697 case SADB_EXT_SA: 2698 print_sa(file, dgettext(TEXT_DOMAIN, 2699 "SA: "), (struct sadb_sa *)current); 2700 break; 2701 /* 2702 * Pluck out lifetimes and print them at the end. This is 2703 * to show relative lifetimes. 2704 */ 2705 case SADB_EXT_LIFETIME_CURRENT: 2706 currentlt = (struct sadb_lifetime *)current; 2707 break; 2708 case SADB_EXT_LIFETIME_HARD: 2709 hardlt = (struct sadb_lifetime *)current; 2710 break; 2711 case SADB_EXT_LIFETIME_SOFT: 2712 softlt = (struct sadb_lifetime *)current; 2713 break; 2714 case SADB_X_EXT_LIFETIME_IDLE: 2715 idlelt = (struct sadb_lifetime *)current; 2716 break; 2717 2718 case SADB_EXT_ADDRESS_SRC: 2719 print_address(file, dgettext(TEXT_DOMAIN, "SRC: "), 2720 (struct sadb_address *)current, ignore_nss); 2721 break; 2722 case SADB_X_EXT_ADDRESS_INNER_SRC: 2723 print_address(file, dgettext(TEXT_DOMAIN, "INS: "), 2724 (struct sadb_address *)current, ignore_nss); 2725 break; 2726 case SADB_EXT_ADDRESS_DST: 2727 print_address(file, dgettext(TEXT_DOMAIN, "DST: "), 2728 (struct sadb_address *)current, ignore_nss); 2729 break; 2730 case SADB_X_EXT_ADDRESS_INNER_DST: 2731 print_address(file, dgettext(TEXT_DOMAIN, "IND: "), 2732 (struct sadb_address *)current, ignore_nss); 2733 break; 2734 case SADB_EXT_KEY_AUTH: 2735 print_key(file, dgettext(TEXT_DOMAIN, 2736 "AKY: "), (struct sadb_key *)current); 2737 break; 2738 case SADB_EXT_KEY_ENCRYPT: 2739 print_key(file, dgettext(TEXT_DOMAIN, 2740 "EKY: "), (struct sadb_key *)current); 2741 break; 2742 case SADB_EXT_IDENTITY_SRC: 2743 print_ident(file, dgettext(TEXT_DOMAIN, "SID: "), 2744 (struct sadb_ident *)current); 2745 break; 2746 case SADB_EXT_IDENTITY_DST: 2747 print_ident(file, dgettext(TEXT_DOMAIN, "DID: "), 2748 (struct sadb_ident *)current); 2749 break; 2750 case SADB_EXT_SENSITIVITY: 2751 print_sens(file, dgettext(TEXT_DOMAIN, "SNS: "), 2752 (struct sadb_sens *)current, ignore_nss); 2753 break; 2754 case SADB_EXT_PROPOSAL: 2755 print_prop(file, dgettext(TEXT_DOMAIN, "PRP: "), 2756 (struct sadb_prop *)current); 2757 break; 2758 case SADB_EXT_SUPPORTED_AUTH: 2759 print_supp(file, dgettext(TEXT_DOMAIN, "SUA: "), 2760 (struct sadb_supported *)current); 2761 break; 2762 case SADB_EXT_SUPPORTED_ENCRYPT: 2763 print_supp(file, dgettext(TEXT_DOMAIN, "SUE: "), 2764 (struct sadb_supported *)current); 2765 break; 2766 case SADB_EXT_SPIRANGE: 2767 print_spirange(file, dgettext(TEXT_DOMAIN, "SPR: "), 2768 (struct sadb_spirange *)current); 2769 break; 2770 case SADB_X_EXT_EPROP: 2771 print_eprop(file, dgettext(TEXT_DOMAIN, "EPR: "), 2772 (struct sadb_prop *)current); 2773 break; 2774 case SADB_X_EXT_KM_COOKIE: 2775 print_kmc(file, dgettext(TEXT_DOMAIN, "KMC: "), 2776 (struct sadb_x_kmc *)current); 2777 break; 2778 case SADB_X_EXT_ADDRESS_NATT_REM: 2779 print_address(file, dgettext(TEXT_DOMAIN, "NRM: "), 2780 (struct sadb_address *)current, ignore_nss); 2781 break; 2782 case SADB_X_EXT_ADDRESS_NATT_LOC: 2783 print_address(file, dgettext(TEXT_DOMAIN, "NLC: "), 2784 (struct sadb_address *)current, ignore_nss); 2785 break; 2786 case SADB_X_EXT_PAIR: 2787 print_pair(file, dgettext(TEXT_DOMAIN, "OTH: "), 2788 (struct sadb_x_pair *)current); 2789 break; 2790 case SADB_X_EXT_OUTER_SENS: 2791 print_sens(file, dgettext(TEXT_DOMAIN, "OSN: "), 2792 (struct sadb_sens *)current, ignore_nss); 2793 break; 2794 case SADB_X_EXT_REPLAY_VALUE: 2795 (void) print_replay(file, dgettext(TEXT_DOMAIN, 2796 "RPL: "), (sadb_x_replay_ctr_t *)current); 2797 break; 2798 default: 2799 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2800 "UNK: Unknown ext. %d, len %d.\n"), 2801 ext->sadb_ext_type, lenbytes); 2802 for (i = 0; i < ext->sadb_ext_len; i++) 2803 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2804 "UNK: 0x%" PRIx64 "\n"), 2805 ((uint64_t *)ext)[i]); 2806 break; 2807 } 2808 current += (lenbytes == 0) ? 2809 SADB_8TO64(sizeof (struct sadb_ext)) : ext->sadb_ext_len; 2810 } 2811 /* 2812 * Print lifetimes NOW. 2813 */ 2814 if (currentlt != NULL || hardlt != NULL || softlt != NULL || 2815 idlelt != NULL) 2816 print_lifetimes(file, wallclock, currentlt, hardlt, 2817 softlt, idlelt, vflag); 2818 2819 if (current - buffer != samsg->sadb_msg_len) { 2820 warnxfp(EFD(file), dgettext(TEXT_DOMAIN, 2821 "WARNING: insufficient buffer space or corrupt message.")); 2822 } 2823 2824 (void) fflush(file); /* Make sure our message is out there. */ 2825 } 2826 2827 /* 2828 * save_XXX functions are used when "saving" the SA tables to either a 2829 * file or standard output. They use the dump_XXX functions where needed, 2830 * but mostly they use the rparseXXX functions. 2831 */ 2832 2833 /* 2834 * Print save information for a lifetime extension. 2835 * 2836 * NOTE : It saves the lifetime in absolute terms. For example, if you 2837 * had a hard_usetime of 60 seconds, you'll save it as 60 seconds, even though 2838 * there may have been 59 seconds burned off the clock. 2839 */ 2840 boolean_t 2841 save_lifetime(struct sadb_lifetime *lifetime, FILE *ofile) 2842 { 2843 char *prefix; 2844 2845 switch (lifetime->sadb_lifetime_exttype) { 2846 case SADB_EXT_LIFETIME_HARD: 2847 prefix = "hard"; 2848 break; 2849 case SADB_EXT_LIFETIME_SOFT: 2850 prefix = "soft"; 2851 break; 2852 case SADB_X_EXT_LIFETIME_IDLE: 2853 prefix = "idle"; 2854 break; 2855 } 2856 2857 if (putc('\t', ofile) == EOF) 2858 return (B_FALSE); 2859 2860 if (lifetime->sadb_lifetime_allocations != 0 && fprintf(ofile, 2861 "%s_alloc %u ", prefix, lifetime->sadb_lifetime_allocations) < 0) 2862 return (B_FALSE); 2863 2864 if (lifetime->sadb_lifetime_bytes != 0 && fprintf(ofile, 2865 "%s_bytes %" PRIu64 " ", prefix, lifetime->sadb_lifetime_bytes) < 0) 2866 return (B_FALSE); 2867 2868 if (lifetime->sadb_lifetime_addtime != 0 && fprintf(ofile, 2869 "%s_addtime %" PRIu64 " ", prefix, 2870 lifetime->sadb_lifetime_addtime) < 0) 2871 return (B_FALSE); 2872 2873 if (lifetime->sadb_lifetime_usetime != 0 && fprintf(ofile, 2874 "%s_usetime %" PRIu64 " ", prefix, 2875 lifetime->sadb_lifetime_usetime) < 0) 2876 return (B_FALSE); 2877 2878 return (B_TRUE); 2879 } 2880 2881 /* 2882 * Print save information for an address extension. 2883 */ 2884 boolean_t 2885 save_address(struct sadb_address *addr, FILE *ofile) 2886 { 2887 char *printable_addr, buf[INET6_ADDRSTRLEN]; 2888 const char *prefix, *pprefix; 2889 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)(addr + 1); 2890 struct sockaddr_in *sin = (struct sockaddr_in *)sin6; 2891 int af = sin->sin_family; 2892 2893 /* 2894 * Address-family reality check. 2895 */ 2896 if (af != AF_INET6 && af != AF_INET) 2897 return (B_FALSE); 2898 2899 switch (addr->sadb_address_exttype) { 2900 case SADB_EXT_ADDRESS_SRC: 2901 prefix = "src"; 2902 pprefix = "sport"; 2903 break; 2904 case SADB_X_EXT_ADDRESS_INNER_SRC: 2905 prefix = "isrc"; 2906 pprefix = "isport"; 2907 break; 2908 case SADB_EXT_ADDRESS_DST: 2909 prefix = "dst"; 2910 pprefix = "dport"; 2911 break; 2912 case SADB_X_EXT_ADDRESS_INNER_DST: 2913 prefix = "idst"; 2914 pprefix = "idport"; 2915 break; 2916 case SADB_X_EXT_ADDRESS_NATT_LOC: 2917 prefix = "nat_loc "; 2918 pprefix = "nat_lport"; 2919 break; 2920 case SADB_X_EXT_ADDRESS_NATT_REM: 2921 prefix = "nat_rem "; 2922 pprefix = "nat_rport"; 2923 break; 2924 } 2925 2926 if (fprintf(ofile, " %s ", prefix) < 0) 2927 return (B_FALSE); 2928 2929 /* 2930 * Do not do address-to-name translation, given that we live in 2931 * an age of names that explode into many addresses. 2932 */ 2933 printable_addr = (char *)inet_ntop(af, 2934 (af == AF_INET) ? (char *)&sin->sin_addr : (char *)&sin6->sin6_addr, 2935 buf, sizeof (buf)); 2936 if (printable_addr == NULL) 2937 printable_addr = "Invalid IP address."; 2938 if (fprintf(ofile, "%s", printable_addr) < 0) 2939 return (B_FALSE); 2940 if (addr->sadb_address_prefixlen != 0 && 2941 !((addr->sadb_address_prefixlen == 32 && af == AF_INET) || 2942 (addr->sadb_address_prefixlen == 128 && af == AF_INET6))) { 2943 if (fprintf(ofile, "/%d", addr->sadb_address_prefixlen) < 0) 2944 return (B_FALSE); 2945 } 2946 2947 /* 2948 * The port is in the same position for struct sockaddr_in and 2949 * struct sockaddr_in6. We exploit that property here. 2950 */ 2951 if ((pprefix != NULL) && (sin->sin_port != 0)) 2952 (void) fprintf(ofile, " %s %d", pprefix, ntohs(sin->sin_port)); 2953 2954 return (B_TRUE); 2955 } 2956 2957 /* 2958 * Print save information for a key extension. Returns whether writing 2959 * to the specified output file was successful or not. 2960 */ 2961 boolean_t 2962 save_key(struct sadb_key *key, FILE *ofile) 2963 { 2964 char *prefix; 2965 2966 if (putc('\t', ofile) == EOF) 2967 return (B_FALSE); 2968 2969 prefix = (key->sadb_key_exttype == SADB_EXT_KEY_AUTH) ? "auth" : "encr"; 2970 2971 if (fprintf(ofile, "%skey ", prefix) < 0) 2972 return (B_FALSE); 2973 2974 if (dump_key((uint8_t *)(key + 1), key->sadb_key_bits, 2975 key->sadb_key_reserved, ofile, B_FALSE) == -1) 2976 return (B_FALSE); 2977 2978 return (B_TRUE); 2979 } 2980 2981 /* 2982 * Print save information for an identity extension. 2983 */ 2984 boolean_t 2985 save_ident(struct sadb_ident *ident, FILE *ofile) 2986 { 2987 char *prefix; 2988 2989 if (putc('\t', ofile) == EOF) 2990 return (B_FALSE); 2991 2992 prefix = (ident->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC) ? "src" : 2993 "dst"; 2994 2995 if (fprintf(ofile, "%sidtype %s ", prefix, 2996 rparseidtype(ident->sadb_ident_type)) < 0) 2997 return (B_FALSE); 2998 2999 if (ident->sadb_ident_type == SADB_X_IDENTTYPE_DN || 3000 ident->sadb_ident_type == SADB_X_IDENTTYPE_GN) { 3001 if (fprintf(ofile, dgettext(TEXT_DOMAIN, 3002 "<can-not-print>")) < 0) 3003 return (B_FALSE); 3004 } else { 3005 if (fprintf(ofile, "%s", (char *)(ident + 1)) < 0) 3006 return (B_FALSE); 3007 } 3008 3009 return (B_TRUE); 3010 } 3011 3012 boolean_t 3013 save_sens(struct sadb_sens *sens, FILE *ofile) 3014 { 3015 char *prefix; 3016 char *hlabel; 3017 bslabel_t sl; 3018 3019 if (putc('\t', ofile) == EOF) 3020 return (B_FALSE); 3021 3022 if (sens->sadb_sens_exttype == SADB_EXT_SENSITIVITY) 3023 prefix = "label"; 3024 else if ((sens->sadb_x_sens_flags & SADB_X_SENS_IMPLICIT) == 0) 3025 prefix = "outer-label"; 3026 else 3027 prefix = "implicit-label"; 3028 3029 ipsec_convert_sens_to_bslabel(sens, &sl); 3030 ipsec_convert_bslabel_to_hex(&sl, &hlabel); 3031 3032 if (fprintf(ofile, "%s %s ", prefix, hlabel) < 0) { 3033 free(hlabel); 3034 return (B_FALSE); 3035 } 3036 free(hlabel); 3037 3038 return (B_TRUE); 3039 } 3040 3041 /* 3042 * "Save" a security association to an output file. 3043 * 3044 * NOTE the lack of calls to dgettext() because I'm outputting parseable stuff. 3045 * ALSO NOTE that if you change keywords (see parsecmd()), you'll have to 3046 * change them here as well. 3047 */ 3048 void 3049 save_assoc(uint64_t *buffer, FILE *ofile) 3050 { 3051 int terrno; 3052 boolean_t seen_proto = B_FALSE, seen_iproto = B_FALSE; 3053 uint64_t *current; 3054 struct sadb_address *addr; 3055 struct sadb_x_replay_ctr *repl; 3056 struct sadb_msg *samsg = (struct sadb_msg *)buffer; 3057 struct sadb_ext *ext; 3058 3059 #define tidyup() \ 3060 terrno = errno; (void) fclose(ofile); errno = terrno; \ 3061 interactive = B_FALSE 3062 3063 #define savenl() if (fputs(" \\\n", ofile) == EOF) \ 3064 { bail(dgettext(TEXT_DOMAIN, "savenl")); } 3065 3066 if (fputs("# begin assoc\n", ofile) == EOF) 3067 bail(dgettext(TEXT_DOMAIN, 3068 "save_assoc: Opening comment of SA")); 3069 if (fprintf(ofile, "add %s ", rparsesatype(samsg->sadb_msg_satype)) < 0) 3070 bail(dgettext(TEXT_DOMAIN, "save_assoc: First line of SA")); 3071 savenl(); 3072 3073 current = (uint64_t *)(samsg + 1); 3074 while (current - buffer < samsg->sadb_msg_len) { 3075 struct sadb_sa *assoc; 3076 3077 ext = (struct sadb_ext *)current; 3078 addr = (struct sadb_address *)ext; /* Just in case... */ 3079 switch (ext->sadb_ext_type) { 3080 case SADB_EXT_SA: 3081 assoc = (struct sadb_sa *)ext; 3082 if (assoc->sadb_sa_state != SADB_SASTATE_MATURE) { 3083 if (fprintf(ofile, "# WARNING: SA was dying " 3084 "or dead.\n") < 0) { 3085 tidyup(); 3086 bail(dgettext(TEXT_DOMAIN, 3087 "save_assoc: fprintf not mature")); 3088 } 3089 } 3090 if (fprintf(ofile, " spi 0x%x ", 3091 ntohl(assoc->sadb_sa_spi)) < 0) { 3092 tidyup(); 3093 bail(dgettext(TEXT_DOMAIN, 3094 "save_assoc: fprintf spi")); 3095 } 3096 if (assoc->sadb_sa_encrypt != SADB_EALG_NONE) { 3097 if (fprintf(ofile, "encr_alg %s ", 3098 rparsealg(assoc->sadb_sa_encrypt, 3099 IPSEC_PROTO_ESP)) < 0) { 3100 tidyup(); 3101 bail(dgettext(TEXT_DOMAIN, 3102 "save_assoc: fprintf encrypt")); 3103 } 3104 } 3105 if (assoc->sadb_sa_auth != SADB_AALG_NONE) { 3106 if (fprintf(ofile, "auth_alg %s ", 3107 rparsealg(assoc->sadb_sa_auth, 3108 IPSEC_PROTO_AH)) < 0) { 3109 tidyup(); 3110 bail(dgettext(TEXT_DOMAIN, 3111 "save_assoc: fprintf auth")); 3112 } 3113 } 3114 if (fprintf(ofile, "replay %d ", 3115 assoc->sadb_sa_replay) < 0) { 3116 tidyup(); 3117 bail(dgettext(TEXT_DOMAIN, 3118 "save_assoc: fprintf replay")); 3119 } 3120 if (assoc->sadb_sa_flags & (SADB_X_SAFLAGS_NATT_LOC | 3121 SADB_X_SAFLAGS_NATT_REM)) { 3122 if (fprintf(ofile, "encap udp") < 0) { 3123 tidyup(); 3124 bail(dgettext(TEXT_DOMAIN, 3125 "save_assoc: fprintf encap")); 3126 } 3127 } 3128 savenl(); 3129 break; 3130 case SADB_EXT_LIFETIME_HARD: 3131 case SADB_EXT_LIFETIME_SOFT: 3132 case SADB_X_EXT_LIFETIME_IDLE: 3133 if (!save_lifetime((struct sadb_lifetime *)ext, 3134 ofile)) { 3135 tidyup(); 3136 bail(dgettext(TEXT_DOMAIN, "save_lifetime")); 3137 } 3138 savenl(); 3139 break; 3140 case SADB_X_EXT_ADDRESS_INNER_SRC: 3141 case SADB_X_EXT_ADDRESS_INNER_DST: 3142 if (!seen_iproto && addr->sadb_address_proto) { 3143 (void) fprintf(ofile, " iproto %d", 3144 addr->sadb_address_proto); 3145 savenl(); 3146 seen_iproto = B_TRUE; 3147 } 3148 goto skip_srcdst; /* Hack to avoid cases below... */ 3149 /* FALLTHRU */ 3150 case SADB_EXT_ADDRESS_SRC: 3151 case SADB_EXT_ADDRESS_DST: 3152 if (!seen_proto && addr->sadb_address_proto) { 3153 (void) fprintf(ofile, " proto %d", 3154 addr->sadb_address_proto); 3155 savenl(); 3156 seen_proto = B_TRUE; 3157 } 3158 /* FALLTHRU */ 3159 case SADB_X_EXT_ADDRESS_NATT_REM: 3160 case SADB_X_EXT_ADDRESS_NATT_LOC: 3161 skip_srcdst: 3162 if (!save_address(addr, ofile)) { 3163 tidyup(); 3164 bail(dgettext(TEXT_DOMAIN, "save_address")); 3165 } 3166 savenl(); 3167 break; 3168 case SADB_EXT_KEY_AUTH: 3169 case SADB_EXT_KEY_ENCRYPT: 3170 if (!save_key((struct sadb_key *)ext, ofile)) { 3171 tidyup(); 3172 bail(dgettext(TEXT_DOMAIN, "save_address")); 3173 } 3174 savenl(); 3175 break; 3176 case SADB_EXT_IDENTITY_SRC: 3177 case SADB_EXT_IDENTITY_DST: 3178 if (!save_ident((struct sadb_ident *)ext, ofile)) { 3179 tidyup(); 3180 bail(dgettext(TEXT_DOMAIN, "save_address")); 3181 } 3182 savenl(); 3183 break; 3184 case SADB_X_EXT_REPLAY_VALUE: 3185 repl = (sadb_x_replay_ctr_t *)ext; 3186 if ((repl->sadb_x_rc_replay32 == 0) && 3187 (repl->sadb_x_rc_replay64 == 0)) { 3188 tidyup(); 3189 bail(dgettext(TEXT_DOMAIN, "Replay Value")); 3190 } 3191 if (fprintf(ofile, "replay_value %" PRIu64 "", 3192 (repl->sadb_x_rc_replay32 == 0 ? 3193 repl->sadb_x_rc_replay64 : 3194 repl->sadb_x_rc_replay32)) < 0) { 3195 tidyup(); 3196 bail(dgettext(TEXT_DOMAIN, 3197 "save_assoc: fprintf replay value")); 3198 } 3199 savenl(); 3200 break; 3201 case SADB_EXT_SENSITIVITY: 3202 case SADB_X_EXT_OUTER_SENS: 3203 if (!save_sens((struct sadb_sens *)ext, ofile)) { 3204 tidyup(); 3205 bail(dgettext(TEXT_DOMAIN, "save_sens")); 3206 } 3207 savenl(); 3208 break; 3209 default: 3210 /* Skip over irrelevant extensions. */ 3211 break; 3212 } 3213 current += ext->sadb_ext_len; 3214 } 3215 3216 if (fputs(dgettext(TEXT_DOMAIN, "\n# end assoc\n\n"), ofile) == EOF) { 3217 tidyup(); 3218 bail(dgettext(TEXT_DOMAIN, "save_assoc: last fputs")); 3219 } 3220 } 3221 3222 /* 3223 * Open the output file for the "save" command. 3224 */ 3225 FILE * 3226 opensavefile(char *filename) 3227 { 3228 int fd; 3229 FILE *retval; 3230 struct stat buf; 3231 3232 /* 3233 * If the user specifies "-" or doesn't give a filename, then 3234 * dump to stdout. Make sure to document the dangers of files 3235 * that are NFS, directing your output to strange places, etc. 3236 */ 3237 if (filename == NULL || strcmp("-", filename) == 0) 3238 return (stdout); 3239 3240 /* 3241 * open the file with the create bits set. Since I check for 3242 * real UID == root in main(), I won't worry about the ownership 3243 * problem. 3244 */ 3245 fd = open(filename, O_WRONLY | O_EXCL | O_CREAT | O_TRUNC, S_IRUSR); 3246 if (fd == -1) { 3247 if (errno != EEXIST) 3248 bail_msg("%s %s: %s", filename, dgettext(TEXT_DOMAIN, 3249 "open error"), 3250 strerror(errno)); 3251 fd = open(filename, O_WRONLY | O_TRUNC, 0); 3252 if (fd == -1) 3253 bail_msg("%s %s: %s", filename, dgettext(TEXT_DOMAIN, 3254 "open error"), strerror(errno)); 3255 if (fstat(fd, &buf) == -1) { 3256 (void) close(fd); 3257 bail_msg("%s fstat: %s", filename, strerror(errno)); 3258 } 3259 if (S_ISREG(buf.st_mode) && 3260 ((buf.st_mode & S_IAMB) != S_IRUSR)) { 3261 warnx(dgettext(TEXT_DOMAIN, 3262 "WARNING: Save file already exists with " 3263 "permission %o."), buf.st_mode & S_IAMB); 3264 warnx(dgettext(TEXT_DOMAIN, 3265 "Normal users may be able to read IPsec " 3266 "keying material.")); 3267 } 3268 } 3269 3270 /* Okay, we have an FD. Assign it to a stdio FILE pointer. */ 3271 retval = fdopen(fd, "w"); 3272 if (retval == NULL) { 3273 (void) close(fd); 3274 bail_msg("%s %s: %s", filename, dgettext(TEXT_DOMAIN, 3275 "fdopen error"), strerror(errno)); 3276 } 3277 return (retval); 3278 } 3279 3280 const char * 3281 do_inet_ntop(const void *addr, char *cp, size_t size) 3282 { 3283 boolean_t isv4; 3284 struct in6_addr *inaddr6 = (struct in6_addr *)addr; 3285 struct in_addr inaddr; 3286 3287 if ((isv4 = IN6_IS_ADDR_V4MAPPED(inaddr6)) == B_TRUE) { 3288 IN6_V4MAPPED_TO_INADDR(inaddr6, &inaddr); 3289 } 3290 3291 return (inet_ntop(isv4 ? AF_INET : AF_INET6, 3292 isv4 ? (void *)&inaddr : inaddr6, cp, size)); 3293 } 3294 3295 char numprint[NBUF_SIZE]; 3296 3297 /* 3298 * Parse and reverse parse a specific SA type (AH, ESP, etc.). 3299 */ 3300 static struct typetable { 3301 char *type; 3302 int token; 3303 } type_table[] = { 3304 {"all", SADB_SATYPE_UNSPEC}, 3305 {"ah", SADB_SATYPE_AH}, 3306 {"esp", SADB_SATYPE_ESP}, 3307 /* PF_KEY NOTE: More to come if net/pfkeyv2.h gets updated. */ 3308 {NULL, 0} /* Token value is irrelevant for this entry. */ 3309 }; 3310 3311 char * 3312 rparsesatype(int type) 3313 { 3314 struct typetable *tt = type_table; 3315 3316 while (tt->type != NULL && type != tt->token) 3317 tt++; 3318 3319 if (tt->type == NULL) { 3320 (void) snprintf(numprint, NBUF_SIZE, "%d", type); 3321 } else { 3322 return (tt->type); 3323 } 3324 3325 return (numprint); 3326 } 3327 3328 3329 /* 3330 * Return a string containing the name of the specified numerical algorithm 3331 * identifier. 3332 */ 3333 char * 3334 rparsealg(uint8_t alg, int proto_num) 3335 { 3336 static struct ipsecalgent *holder = NULL; /* we're single-threaded */ 3337 3338 if (holder != NULL) 3339 freeipsecalgent(holder); 3340 3341 holder = getipsecalgbynum(alg, proto_num, NULL); 3342 if (holder == NULL) { 3343 (void) snprintf(numprint, NBUF_SIZE, "%d", alg); 3344 return (numprint); 3345 } 3346 3347 return (*(holder->a_names)); 3348 } 3349 3350 /* 3351 * Parse and reverse parse out a source/destination ID type. 3352 */ 3353 static struct idtypes { 3354 char *idtype; 3355 uint8_t retval; 3356 } idtypes[] = { 3357 {"prefix", SADB_IDENTTYPE_PREFIX}, 3358 {"fqdn", SADB_IDENTTYPE_FQDN}, 3359 {"domain", SADB_IDENTTYPE_FQDN}, 3360 {"domainname", SADB_IDENTTYPE_FQDN}, 3361 {"user_fqdn", SADB_IDENTTYPE_USER_FQDN}, 3362 {"mailbox", SADB_IDENTTYPE_USER_FQDN}, 3363 {"der_dn", SADB_X_IDENTTYPE_DN}, 3364 {"der_gn", SADB_X_IDENTTYPE_GN}, 3365 {NULL, 0} 3366 }; 3367 3368 char * 3369 rparseidtype(uint16_t type) 3370 { 3371 struct idtypes *idp; 3372 3373 for (idp = idtypes; idp->idtype != NULL; idp++) { 3374 if (type == idp->retval) 3375 return (idp->idtype); 3376 } 3377 3378 (void) snprintf(numprint, NBUF_SIZE, "%d", type); 3379 return (numprint); 3380 } 3381 3382 /* 3383 * This is a general purpose exit function, calling functions can specify an 3384 * error type. If the command calling this function was started by smf(5) the 3385 * error type could be used as a hint to the restarter. In the future this 3386 * function could be used to do something more intelligent with a process that 3387 * encounters an error. If exit() is called with an error code other than those 3388 * defined by smf(5), the program will just get restarted. Unless restarting 3389 * is likely to resolve the error condition, its probably sensible to just 3390 * log the error and keep running. 3391 * 3392 * The SERVICE_* exit_types mean nothing if the command was run from the 3393 * command line, just exit(). There are two special cases: 3394 * 3395 * SERVICE_DEGRADE - Not implemented in smf(5), one day it could hint that 3396 * the service is not running as well is it could. For 3397 * now, don't do anything, just record the error. 3398 * DEBUG_FATAL - Something happened, if the command was being run in debug 3399 * mode, exit() as you really want to know something happened, 3400 * otherwise just keep running. This is ignored when running 3401 * under smf(5). 3402 * 3403 * The function will handle an optional variable args error message, this 3404 * will be written to the error stream, typically a log file or stderr. 3405 */ 3406 void 3407 ipsecutil_exit(exit_type_t type, char *fmri, FILE *fp, const char *fmt, ...) 3408 { 3409 int exit_status; 3410 va_list args; 3411 3412 if (fp == NULL) 3413 fp = stderr; 3414 if (fmt != NULL) { 3415 va_start(args, fmt); 3416 vwarnxfp(fp, fmt, args); 3417 va_end(args); 3418 } 3419 3420 if (fmri == NULL) { 3421 /* Command being run directly from a shell. */ 3422 switch (type) { 3423 case SERVICE_EXIT_OK: 3424 exit_status = 0; 3425 break; 3426 case SERVICE_DEGRADE: 3427 return; 3428 case SERVICE_BADPERM: 3429 case SERVICE_BADCONF: 3430 case SERVICE_MAINTAIN: 3431 case SERVICE_DISABLE: 3432 case SERVICE_FATAL: 3433 case SERVICE_RESTART: 3434 case DEBUG_FATAL: 3435 warnxfp(fp, "Fatal error - exiting."); 3436 exit_status = 1; 3437 break; 3438 } 3439 } else { 3440 /* Command being run as a smf(5) method. */ 3441 switch (type) { 3442 case SERVICE_EXIT_OK: 3443 exit_status = SMF_EXIT_OK; 3444 break; 3445 case SERVICE_DEGRADE: /* Not implemented yet. */ 3446 case DEBUG_FATAL: 3447 /* Keep running, don't exit(). */ 3448 return; 3449 case SERVICE_BADPERM: 3450 warnxfp(fp, dgettext(TEXT_DOMAIN, 3451 "Permission error with %s."), fmri); 3452 exit_status = SMF_EXIT_ERR_PERM; 3453 break; 3454 case SERVICE_BADCONF: 3455 warnxfp(fp, dgettext(TEXT_DOMAIN, 3456 "Bad configuration of service %s."), fmri); 3457 exit_status = SMF_EXIT_ERR_FATAL; 3458 break; 3459 case SERVICE_MAINTAIN: 3460 warnxfp(fp, dgettext(TEXT_DOMAIN, 3461 "Service %s needs maintenance."), fmri); 3462 exit_status = SMF_EXIT_ERR_FATAL; 3463 break; 3464 case SERVICE_DISABLE: 3465 exit_status = SMF_EXIT_ERR_FATAL; 3466 break; 3467 case SERVICE_FATAL: 3468 warnxfp(fp, dgettext(TEXT_DOMAIN, 3469 "Service %s fatal error."), fmri); 3470 exit_status = SMF_EXIT_ERR_FATAL; 3471 break; 3472 case SERVICE_RESTART: 3473 exit_status = 1; 3474 break; 3475 } 3476 } 3477 (void) fflush(fp); 3478 (void) fclose(fp); 3479 exit(exit_status); 3480 } 3481 3482 void 3483 print_asn1_name(FILE *file, const unsigned char *buf, long buflen) 3484 { 3485 KMF_X509_NAME name = { 0 }; 3486 KMF_DATA data = { 0 }; 3487 char *str = NULL; 3488 3489 data.Data = (unsigned char *)buf; 3490 data.Length = buflen; 3491 3492 if (DerDecodeName(&data, &name) != KMF_OK) 3493 goto fail; 3494 3495 if (kmf_dn_to_string(&name, &str) != KMF_OK) 3496 goto fail; 3497 3498 (void) fprintf(file, "%s\n", str); 3499 kmf_free_dn(&name); 3500 free(str); 3501 return; 3502 fail: 3503 kmf_free_dn(&name); 3504 (void) fprintf(file, dgettext(TEXT_DOMAIN, "<cannot interpret>\n")); 3505 } 3506