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