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