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