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