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