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