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_LABEL, "label" }, 843 { D_ALL, "all" }, 844 { 0, "0" }, 845 }; 846 847 int 848 dbgstr2num(char *str) 849 { 850 keywdtab_t *dp; 851 852 for (dp = dbgtab; dp < A_END(dbgtab); dp++) { 853 if (strcasecmp(str, dp->kw_str) == 0) 854 return (dp->kw_tag); 855 } 856 return (D_INVALID); 857 } 858 859 int 860 parsedbgopts(char *optarg) 861 { 862 char *argp, *endp, op, nextop; 863 int mask = 0, new; 864 865 mask = strtol(optarg, &endp, 0); 866 if (*endp == '\0') 867 return (mask); 868 869 op = optarg[0]; 870 if (op != '-') 871 op = '+'; 872 argp = strtok_d(optarg, "+-", &nextop); 873 do { 874 new = dbgstr2num(argp); 875 if (new == D_INVALID) { 876 /* we encountered an invalid keywd */ 877 return (new); 878 } 879 if (op == '+') { 880 mask |= new; 881 } else { 882 mask &= ~new; 883 } 884 op = nextop; 885 } while ((argp = strtok_d(NULL, "+-", &nextop)) != NULL); 886 887 return (mask); 888 } 889 890 891 /* 892 * functions to manipulate the kmcookie-label mapping file 893 */ 894 895 /* 896 * Open, lockf, fdopen the given file, returning a FILE * on success, 897 * or NULL on failure. 898 */ 899 FILE * 900 kmc_open_and_lock(char *name) 901 { 902 int fd, rtnerr; 903 FILE *fp; 904 905 if ((fd = open(name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) { 906 return (NULL); 907 } 908 if (lockf(fd, F_LOCK, 0) < 0) { 909 return (NULL); 910 } 911 if ((fp = fdopen(fd, "a+")) == NULL) { 912 return (NULL); 913 } 914 if (fseek(fp, 0, SEEK_SET) < 0) { 915 /* save errno in case fclose changes it */ 916 rtnerr = errno; 917 (void) fclose(fp); 918 errno = rtnerr; 919 return (NULL); 920 } 921 return (fp); 922 } 923 924 /* 925 * Extract an integer cookie and string label from a line from the 926 * kmcookie-label file. Return -1 on failure, 0 on success. 927 */ 928 int 929 kmc_parse_line(char *line, int *cookie, char **label) 930 { 931 char *cookiestr; 932 933 *cookie = 0; 934 *label = NULL; 935 936 cookiestr = strtok(line, " \t\n"); 937 if (cookiestr == NULL) { 938 return (-1); 939 } 940 941 /* Everything that follows, up to the newline, is the label. */ 942 *label = strtok(NULL, "\n"); 943 if (*label == NULL) { 944 return (-1); 945 } 946 947 *cookie = atoi(cookiestr); 948 return (0); 949 } 950 951 /* 952 * Insert a mapping into the file (if it's not already there), given the 953 * new label. Return the assigned cookie, or -1 on error. 954 */ 955 int 956 kmc_insert_mapping(char *label) 957 { 958 FILE *map; 959 char linebuf[IBUF_SIZE]; 960 char *cur_label; 961 int max_cookie = 0, cur_cookie, rtn_cookie; 962 int rtnerr = 0; 963 boolean_t found = B_FALSE; 964 965 /* open and lock the file; will sleep until lock is available */ 966 if ((map = kmc_open_and_lock(KMCFILE)) == NULL) { 967 /* kmc_open_and_lock() sets errno appropriately */ 968 return (-1); 969 } 970 971 while (fgets(linebuf, sizeof (linebuf), map) != NULL) { 972 973 /* Skip blank lines, which often come near EOF. */ 974 if (strlen(linebuf) == 0) 975 continue; 976 977 if (kmc_parse_line(linebuf, &cur_cookie, &cur_label) < 0) { 978 rtnerr = EINVAL; 979 goto error; 980 } 981 982 if (cur_cookie > max_cookie) 983 max_cookie = cur_cookie; 984 985 if ((!found) && (strcmp(cur_label, label) == 0)) { 986 found = B_TRUE; 987 rtn_cookie = cur_cookie; 988 } 989 } 990 991 if (!found) { 992 rtn_cookie = ++max_cookie; 993 if ((fprintf(map, "%u\t%s\n", rtn_cookie, label) < 0) || 994 (fflush(map) < 0)) { 995 rtnerr = errno; 996 goto error; 997 } 998 } 999 (void) fclose(map); 1000 1001 return (rtn_cookie); 1002 1003 error: 1004 (void) fclose(map); 1005 errno = rtnerr; 1006 return (-1); 1007 } 1008 1009 /* 1010 * Lookup the given cookie and return its corresponding label. Return 1011 * a pointer to the label on success, NULL on error (or if the label is 1012 * not found). Note that the returned label pointer points to a static 1013 * string, so the label will be overwritten by a subsequent call to the 1014 * function; the function is also not thread-safe as a result. 1015 */ 1016 char * 1017 kmc_lookup_by_cookie(int cookie) 1018 { 1019 FILE *map; 1020 static char linebuf[IBUF_SIZE]; 1021 char *cur_label; 1022 int cur_cookie; 1023 1024 if ((map = kmc_open_and_lock(KMCFILE)) == NULL) { 1025 return (NULL); 1026 } 1027 1028 while (fgets(linebuf, sizeof (linebuf), map) != NULL) { 1029 1030 if (kmc_parse_line(linebuf, &cur_cookie, &cur_label) < 0) { 1031 (void) fclose(map); 1032 return (NULL); 1033 } 1034 1035 if (cookie == cur_cookie) { 1036 (void) fclose(map); 1037 return (cur_label); 1038 } 1039 } 1040 (void) fclose(map); 1041 1042 return (NULL); 1043 } 1044 1045 /* 1046 * Parse basic extension headers and return in the passed-in pointer vector. 1047 * Return values include: 1048 * 1049 * KGE_OK Everything's nice and parsed out. 1050 * If there are no extensions, place NULL in extv[0]. 1051 * KGE_DUP There is a duplicate extension. 1052 * First instance in appropriate bin. First duplicate in 1053 * extv[0]. 1054 * KGE_UNK Unknown extension type encountered. extv[0] contains 1055 * unknown header. 1056 * KGE_LEN Extension length error. 1057 * KGE_CHK High-level reality check failed on specific extension. 1058 * 1059 * My apologies for some of the pointer arithmetic in here. I'm thinking 1060 * like an assembly programmer, yet trying to make the compiler happy. 1061 */ 1062 int 1063 spdsock_get_ext(spd_ext_t *extv[], spd_msg_t *basehdr, uint_t msgsize, 1064 char *diag_buf, uint_t diag_buf_len) 1065 { 1066 int i; 1067 1068 if (diag_buf != NULL) 1069 diag_buf[0] = '\0'; 1070 1071 for (i = 1; i <= SPD_EXT_MAX; i++) 1072 extv[i] = NULL; 1073 1074 i = 0; 1075 /* Use extv[0] as the "current working pointer". */ 1076 1077 extv[0] = (spd_ext_t *)(basehdr + 1); 1078 msgsize = SPD_64TO8(msgsize); 1079 1080 while ((char *)extv[0] < ((char *)basehdr + msgsize)) { 1081 /* Check for unknown headers. */ 1082 i++; 1083 if (extv[0]->spd_ext_type == 0 || 1084 extv[0]->spd_ext_type > SPD_EXT_MAX) { 1085 if (diag_buf != NULL) { 1086 (void) snprintf(diag_buf, diag_buf_len, 1087 "spdsock ext 0x%X unknown: 0x%X", 1088 i, extv[0]->spd_ext_type); 1089 } 1090 return (KGE_UNK); 1091 } 1092 1093 /* 1094 * Check length. Use uint64_t because extlen is in units 1095 * of 64-bit words. If length goes beyond the msgsize, 1096 * return an error. (Zero length also qualifies here.) 1097 */ 1098 if (extv[0]->spd_ext_len == 0 || 1099 (uint8_t *)((uint64_t *)extv[0] + extv[0]->spd_ext_len) > 1100 (uint8_t *)((uint8_t *)basehdr + msgsize)) 1101 return (KGE_LEN); 1102 1103 /* Check for redundant headers. */ 1104 if (extv[extv[0]->spd_ext_type] != NULL) 1105 return (KGE_DUP); 1106 1107 /* If I make it here, assign the appropriate bin. */ 1108 extv[extv[0]->spd_ext_type] = extv[0]; 1109 1110 /* Advance pointer (See above for uint64_t ptr reasoning.) */ 1111 extv[0] = (spd_ext_t *) 1112 ((uint64_t *)extv[0] + extv[0]->spd_ext_len); 1113 } 1114 1115 /* Everything's cool. */ 1116 1117 /* 1118 * If extv[0] == NULL, then there are no extension headers in this 1119 * message. Ensure that this is the case. 1120 */ 1121 if (extv[0] == (spd_ext_t *)(basehdr + 1)) 1122 extv[0] = NULL; 1123 1124 return (KGE_OK); 1125 } 1126 1127 const char * 1128 spdsock_diag(int diagnostic) 1129 { 1130 switch (diagnostic) { 1131 case SPD_DIAGNOSTIC_NONE: 1132 return (dgettext(TEXT_DOMAIN, "no error")); 1133 case SPD_DIAGNOSTIC_UNKNOWN_EXT: 1134 return (dgettext(TEXT_DOMAIN, "unknown extension")); 1135 case SPD_DIAGNOSTIC_BAD_EXTLEN: 1136 return (dgettext(TEXT_DOMAIN, "bad extension length")); 1137 case SPD_DIAGNOSTIC_NO_RULE_EXT: 1138 return (dgettext(TEXT_DOMAIN, "no rule extension")); 1139 case SPD_DIAGNOSTIC_BAD_ADDR_LEN: 1140 return (dgettext(TEXT_DOMAIN, "bad address len")); 1141 case SPD_DIAGNOSTIC_MIXED_AF: 1142 return (dgettext(TEXT_DOMAIN, "mixed address family")); 1143 case SPD_DIAGNOSTIC_ADD_NO_MEM: 1144 return (dgettext(TEXT_DOMAIN, "add: no memory")); 1145 case SPD_DIAGNOSTIC_ADD_WRONG_ACT_COUNT: 1146 return (dgettext(TEXT_DOMAIN, "add: wrong action count")); 1147 case SPD_DIAGNOSTIC_ADD_BAD_TYPE: 1148 return (dgettext(TEXT_DOMAIN, "add: bad type")); 1149 case SPD_DIAGNOSTIC_ADD_BAD_FLAGS: 1150 return (dgettext(TEXT_DOMAIN, "add: bad flags")); 1151 case SPD_DIAGNOSTIC_ADD_INCON_FLAGS: 1152 return (dgettext(TEXT_DOMAIN, "add: inconsistent flags")); 1153 case SPD_DIAGNOSTIC_MALFORMED_LCLPORT: 1154 return (dgettext(TEXT_DOMAIN, "malformed local port")); 1155 case SPD_DIAGNOSTIC_DUPLICATE_LCLPORT: 1156 return (dgettext(TEXT_DOMAIN, "duplicate local port")); 1157 case SPD_DIAGNOSTIC_MALFORMED_REMPORT: 1158 return (dgettext(TEXT_DOMAIN, "malformed remote port")); 1159 case SPD_DIAGNOSTIC_DUPLICATE_REMPORT: 1160 return (dgettext(TEXT_DOMAIN, "duplicate remote port")); 1161 case SPD_DIAGNOSTIC_MALFORMED_PROTO: 1162 return (dgettext(TEXT_DOMAIN, "malformed proto")); 1163 case SPD_DIAGNOSTIC_DUPLICATE_PROTO: 1164 return (dgettext(TEXT_DOMAIN, "duplicate proto")); 1165 case SPD_DIAGNOSTIC_MALFORMED_LCLADDR: 1166 return (dgettext(TEXT_DOMAIN, "malformed local address")); 1167 case SPD_DIAGNOSTIC_DUPLICATE_LCLADDR: 1168 return (dgettext(TEXT_DOMAIN, "duplicate local address")); 1169 case SPD_DIAGNOSTIC_MALFORMED_REMADDR: 1170 return (dgettext(TEXT_DOMAIN, "malformed remote address")); 1171 case SPD_DIAGNOSTIC_DUPLICATE_REMADDR: 1172 return (dgettext(TEXT_DOMAIN, "duplicate remote address")); 1173 case SPD_DIAGNOSTIC_MALFORMED_ACTION: 1174 return (dgettext(TEXT_DOMAIN, "malformed action")); 1175 case SPD_DIAGNOSTIC_DUPLICATE_ACTION: 1176 return (dgettext(TEXT_DOMAIN, "duplicate action")); 1177 case SPD_DIAGNOSTIC_MALFORMED_RULE: 1178 return (dgettext(TEXT_DOMAIN, "malformed rule")); 1179 case SPD_DIAGNOSTIC_DUPLICATE_RULE: 1180 return (dgettext(TEXT_DOMAIN, "duplicate rule")); 1181 case SPD_DIAGNOSTIC_MALFORMED_RULESET: 1182 return (dgettext(TEXT_DOMAIN, "malformed ruleset")); 1183 case SPD_DIAGNOSTIC_DUPLICATE_RULESET: 1184 return (dgettext(TEXT_DOMAIN, "duplicate ruleset")); 1185 case SPD_DIAGNOSTIC_INVALID_RULE_INDEX: 1186 return (dgettext(TEXT_DOMAIN, "invalid rule index")); 1187 case SPD_DIAGNOSTIC_BAD_SPDID: 1188 return (dgettext(TEXT_DOMAIN, "bad spdid")); 1189 case SPD_DIAGNOSTIC_BAD_MSG_TYPE: 1190 return (dgettext(TEXT_DOMAIN, "bad message type")); 1191 case SPD_DIAGNOSTIC_UNSUPP_AH_ALG: 1192 return (dgettext(TEXT_DOMAIN, "unsupported AH algorithm")); 1193 case SPD_DIAGNOSTIC_UNSUPP_ESP_ENCR_ALG: 1194 return (dgettext(TEXT_DOMAIN, 1195 "unsupported ESP encryption algorithm")); 1196 case SPD_DIAGNOSTIC_UNSUPP_ESP_AUTH_ALG: 1197 return (dgettext(TEXT_DOMAIN, 1198 "unsupported ESP authentication algorithm")); 1199 case SPD_DIAGNOSTIC_UNSUPP_AH_KEYSIZE: 1200 return (dgettext(TEXT_DOMAIN, "unsupported AH key size")); 1201 case SPD_DIAGNOSTIC_UNSUPP_ESP_ENCR_KEYSIZE: 1202 return (dgettext(TEXT_DOMAIN, 1203 "unsupported ESP encryption key size")); 1204 case SPD_DIAGNOSTIC_UNSUPP_ESP_AUTH_KEYSIZE: 1205 return (dgettext(TEXT_DOMAIN, 1206 "unsupported ESP authentication key size")); 1207 case SPD_DIAGNOSTIC_NO_ACTION_EXT: 1208 return (dgettext(TEXT_DOMAIN, "No ACTION extension")); 1209 case SPD_DIAGNOSTIC_ALG_ID_RANGE: 1210 return (dgettext(TEXT_DOMAIN, "invalid algorithm identifer")); 1211 case SPD_DIAGNOSTIC_ALG_NUM_KEY_SIZES: 1212 return (dgettext(TEXT_DOMAIN, 1213 "number of key sizes inconsistent")); 1214 case SPD_DIAGNOSTIC_ALG_NUM_BLOCK_SIZES: 1215 return (dgettext(TEXT_DOMAIN, 1216 "number of block sizes inconsistent")); 1217 case SPD_DIAGNOSTIC_ALG_MECH_NAME_LEN: 1218 return (dgettext(TEXT_DOMAIN, "invalid mechanism name length")); 1219 case SPD_DIAGNOSTIC_NOT_GLOBAL_OP: 1220 return (dgettext(TEXT_DOMAIN, 1221 "operation not applicable to all policies")); 1222 case SPD_DIAGNOSTIC_NO_TUNNEL_SELECTORS: 1223 return (dgettext(TEXT_DOMAIN, 1224 "using selectors on a transport-mode tunnel")); 1225 default: 1226 return (dgettext(TEXT_DOMAIN, "unknown diagnostic")); 1227 } 1228 } 1229 1230 /* 1231 * PF_KEY Diagnostic table. 1232 * 1233 * PF_KEY NOTE: If you change pfkeyv2.h's SADB_X_DIAGNOSTIC_* space, this is 1234 * where you need to add new messages. 1235 */ 1236 1237 const char * 1238 keysock_diag(int diagnostic) 1239 { 1240 switch (diagnostic) { 1241 case SADB_X_DIAGNOSTIC_NONE: 1242 return (dgettext(TEXT_DOMAIN, "No diagnostic")); 1243 case SADB_X_DIAGNOSTIC_UNKNOWN_MSG: 1244 return (dgettext(TEXT_DOMAIN, "Unknown message type")); 1245 case SADB_X_DIAGNOSTIC_UNKNOWN_EXT: 1246 return (dgettext(TEXT_DOMAIN, "Unknown extension type")); 1247 case SADB_X_DIAGNOSTIC_BAD_EXTLEN: 1248 return (dgettext(TEXT_DOMAIN, "Bad extension length")); 1249 case SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE: 1250 return (dgettext(TEXT_DOMAIN, 1251 "Unknown Security Association type")); 1252 case SADB_X_DIAGNOSTIC_SATYPE_NEEDED: 1253 return (dgettext(TEXT_DOMAIN, 1254 "Specific Security Association type needed")); 1255 case SADB_X_DIAGNOSTIC_NO_SADBS: 1256 return (dgettext(TEXT_DOMAIN, 1257 "No Security Association Databases present")); 1258 case SADB_X_DIAGNOSTIC_NO_EXT: 1259 return (dgettext(TEXT_DOMAIN, 1260 "No extensions needed for message")); 1261 case SADB_X_DIAGNOSTIC_BAD_SRC_AF: 1262 return (dgettext(TEXT_DOMAIN, "Bad source address family")); 1263 case SADB_X_DIAGNOSTIC_BAD_DST_AF: 1264 return (dgettext(TEXT_DOMAIN, 1265 "Bad destination address family")); 1266 case SADB_X_DIAGNOSTIC_BAD_PROXY_AF: 1267 return (dgettext(TEXT_DOMAIN, 1268 "Bad inner-source address family")); 1269 case SADB_X_DIAGNOSTIC_AF_MISMATCH: 1270 return (dgettext(TEXT_DOMAIN, 1271 "Source/destination address family mismatch")); 1272 case SADB_X_DIAGNOSTIC_BAD_SRC: 1273 return (dgettext(TEXT_DOMAIN, "Bad source address value")); 1274 case SADB_X_DIAGNOSTIC_BAD_DST: 1275 return (dgettext(TEXT_DOMAIN, "Bad destination address value")); 1276 case SADB_X_DIAGNOSTIC_ALLOC_HSERR: 1277 return (dgettext(TEXT_DOMAIN, 1278 "Soft allocations limit more than hard limit")); 1279 case SADB_X_DIAGNOSTIC_BYTES_HSERR: 1280 return (dgettext(TEXT_DOMAIN, 1281 "Soft bytes limit more than hard limit")); 1282 case SADB_X_DIAGNOSTIC_ADDTIME_HSERR: 1283 return (dgettext(TEXT_DOMAIN, "Soft add expiration time later " 1284 "than hard expiration time")); 1285 case SADB_X_DIAGNOSTIC_USETIME_HSERR: 1286 return (dgettext(TEXT_DOMAIN, "Soft use expiration time later " 1287 "than hard expiration time")); 1288 case SADB_X_DIAGNOSTIC_MISSING_SRC: 1289 return (dgettext(TEXT_DOMAIN, "Missing source address")); 1290 case SADB_X_DIAGNOSTIC_MISSING_DST: 1291 return (dgettext(TEXT_DOMAIN, "Missing destination address")); 1292 case SADB_X_DIAGNOSTIC_MISSING_SA: 1293 return (dgettext(TEXT_DOMAIN, "Missing SA extension")); 1294 case SADB_X_DIAGNOSTIC_MISSING_EKEY: 1295 return (dgettext(TEXT_DOMAIN, "Missing encryption key")); 1296 case SADB_X_DIAGNOSTIC_MISSING_AKEY: 1297 return (dgettext(TEXT_DOMAIN, "Missing authentication key")); 1298 case SADB_X_DIAGNOSTIC_MISSING_RANGE: 1299 return (dgettext(TEXT_DOMAIN, "Missing SPI range")); 1300 case SADB_X_DIAGNOSTIC_DUPLICATE_SRC: 1301 return (dgettext(TEXT_DOMAIN, "Duplicate source address")); 1302 case SADB_X_DIAGNOSTIC_DUPLICATE_DST: 1303 return (dgettext(TEXT_DOMAIN, "Duplicate destination address")); 1304 case SADB_X_DIAGNOSTIC_DUPLICATE_SA: 1305 return (dgettext(TEXT_DOMAIN, "Duplicate SA extension")); 1306 case SADB_X_DIAGNOSTIC_DUPLICATE_EKEY: 1307 return (dgettext(TEXT_DOMAIN, "Duplicate encryption key")); 1308 case SADB_X_DIAGNOSTIC_DUPLICATE_AKEY: 1309 return (dgettext(TEXT_DOMAIN, "Duplicate authentication key")); 1310 case SADB_X_DIAGNOSTIC_DUPLICATE_RANGE: 1311 return (dgettext(TEXT_DOMAIN, "Duplicate SPI range")); 1312 case SADB_X_DIAGNOSTIC_MALFORMED_SRC: 1313 return (dgettext(TEXT_DOMAIN, "Malformed source address")); 1314 case SADB_X_DIAGNOSTIC_MALFORMED_DST: 1315 return (dgettext(TEXT_DOMAIN, "Malformed destination address")); 1316 case SADB_X_DIAGNOSTIC_MALFORMED_SA: 1317 return (dgettext(TEXT_DOMAIN, "Malformed SA extension")); 1318 case SADB_X_DIAGNOSTIC_MALFORMED_EKEY: 1319 return (dgettext(TEXT_DOMAIN, "Malformed encryption key")); 1320 case SADB_X_DIAGNOSTIC_MALFORMED_AKEY: 1321 return (dgettext(TEXT_DOMAIN, "Malformed authentication key")); 1322 case SADB_X_DIAGNOSTIC_MALFORMED_RANGE: 1323 return (dgettext(TEXT_DOMAIN, "Malformed SPI range")); 1324 case SADB_X_DIAGNOSTIC_AKEY_PRESENT: 1325 return (dgettext(TEXT_DOMAIN, "Authentication key not needed")); 1326 case SADB_X_DIAGNOSTIC_EKEY_PRESENT: 1327 return (dgettext(TEXT_DOMAIN, "Encryption key not needed")); 1328 case SADB_X_DIAGNOSTIC_PROP_PRESENT: 1329 return (dgettext(TEXT_DOMAIN, "Proposal extension not needed")); 1330 case SADB_X_DIAGNOSTIC_SUPP_PRESENT: 1331 return (dgettext(TEXT_DOMAIN, 1332 "Supported algorithms extension not needed")); 1333 case SADB_X_DIAGNOSTIC_BAD_AALG: 1334 return (dgettext(TEXT_DOMAIN, 1335 "Unsupported authentication algorithm")); 1336 case SADB_X_DIAGNOSTIC_BAD_EALG: 1337 return (dgettext(TEXT_DOMAIN, 1338 "Unsupported encryption algorithm")); 1339 case SADB_X_DIAGNOSTIC_BAD_SAFLAGS: 1340 return (dgettext(TEXT_DOMAIN, "Invalid SA flags")); 1341 case SADB_X_DIAGNOSTIC_BAD_SASTATE: 1342 return (dgettext(TEXT_DOMAIN, "Invalid SA state")); 1343 case SADB_X_DIAGNOSTIC_BAD_AKEYBITS: 1344 return (dgettext(TEXT_DOMAIN, 1345 "Bad number of authentication bits")); 1346 case SADB_X_DIAGNOSTIC_BAD_EKEYBITS: 1347 return (dgettext(TEXT_DOMAIN, 1348 "Bad number of encryption bits")); 1349 case SADB_X_DIAGNOSTIC_ENCR_NOTSUPP: 1350 return (dgettext(TEXT_DOMAIN, 1351 "Encryption not supported for this SA type")); 1352 case SADB_X_DIAGNOSTIC_WEAK_EKEY: 1353 return (dgettext(TEXT_DOMAIN, "Weak encryption key")); 1354 case SADB_X_DIAGNOSTIC_WEAK_AKEY: 1355 return (dgettext(TEXT_DOMAIN, "Weak authentication key")); 1356 case SADB_X_DIAGNOSTIC_DUPLICATE_KMP: 1357 return (dgettext(TEXT_DOMAIN, 1358 "Duplicate key management protocol")); 1359 case SADB_X_DIAGNOSTIC_DUPLICATE_KMC: 1360 return (dgettext(TEXT_DOMAIN, 1361 "Duplicate key management cookie")); 1362 case SADB_X_DIAGNOSTIC_MISSING_NATT_LOC: 1363 return (dgettext(TEXT_DOMAIN, "Missing NAT-T local address")); 1364 case SADB_X_DIAGNOSTIC_MISSING_NATT_REM: 1365 return (dgettext(TEXT_DOMAIN, "Missing NAT-T remote address")); 1366 case SADB_X_DIAGNOSTIC_DUPLICATE_NATT_LOC: 1367 return (dgettext(TEXT_DOMAIN, "Duplicate NAT-T local address")); 1368 case SADB_X_DIAGNOSTIC_DUPLICATE_NATT_REM: 1369 return (dgettext(TEXT_DOMAIN, 1370 "Duplicate NAT-T remote address")); 1371 case SADB_X_DIAGNOSTIC_MALFORMED_NATT_LOC: 1372 return (dgettext(TEXT_DOMAIN, "Malformed NAT-T local address")); 1373 case SADB_X_DIAGNOSTIC_MALFORMED_NATT_REM: 1374 return (dgettext(TEXT_DOMAIN, 1375 "Malformed NAT-T remote address")); 1376 case SADB_X_DIAGNOSTIC_DUPLICATE_NATT_PORTS: 1377 return (dgettext(TEXT_DOMAIN, "Duplicate NAT-T ports")); 1378 case SADB_X_DIAGNOSTIC_MISSING_INNER_SRC: 1379 return (dgettext(TEXT_DOMAIN, "Missing inner source address")); 1380 case SADB_X_DIAGNOSTIC_MISSING_INNER_DST: 1381 return (dgettext(TEXT_DOMAIN, 1382 "Missing inner destination address")); 1383 case SADB_X_DIAGNOSTIC_DUPLICATE_INNER_SRC: 1384 return (dgettext(TEXT_DOMAIN, 1385 "Duplicate inner source address")); 1386 case SADB_X_DIAGNOSTIC_DUPLICATE_INNER_DST: 1387 return (dgettext(TEXT_DOMAIN, 1388 "Duplicate inner destination address")); 1389 case SADB_X_DIAGNOSTIC_MALFORMED_INNER_SRC: 1390 return (dgettext(TEXT_DOMAIN, 1391 "Malformed inner source address")); 1392 case SADB_X_DIAGNOSTIC_MALFORMED_INNER_DST: 1393 return (dgettext(TEXT_DOMAIN, 1394 "Malformed inner destination address")); 1395 case SADB_X_DIAGNOSTIC_PREFIX_INNER_SRC: 1396 return (dgettext(TEXT_DOMAIN, 1397 "Invalid inner-source prefix length ")); 1398 case SADB_X_DIAGNOSTIC_PREFIX_INNER_DST: 1399 return (dgettext(TEXT_DOMAIN, 1400 "Invalid inner-destination prefix length")); 1401 case SADB_X_DIAGNOSTIC_BAD_INNER_DST_AF: 1402 return (dgettext(TEXT_DOMAIN, 1403 "Bad inner-destination address family")); 1404 case SADB_X_DIAGNOSTIC_INNER_AF_MISMATCH: 1405 return (dgettext(TEXT_DOMAIN, 1406 "Inner source/destination address family mismatch")); 1407 case SADB_X_DIAGNOSTIC_BAD_NATT_REM_AF: 1408 return (dgettext(TEXT_DOMAIN, 1409 "Bad NAT-T remote address family")); 1410 case SADB_X_DIAGNOSTIC_BAD_NATT_LOC_AF: 1411 return (dgettext(TEXT_DOMAIN, 1412 "Bad NAT-T local address family")); 1413 case SADB_X_DIAGNOSTIC_PROTO_MISMATCH: 1414 return (dgettext(TEXT_DOMAIN, 1415 "Source/desination protocol mismatch")); 1416 case SADB_X_DIAGNOSTIC_INNER_PROTO_MISMATCH: 1417 return (dgettext(TEXT_DOMAIN, 1418 "Inner source/desination protocol mismatch")); 1419 case SADB_X_DIAGNOSTIC_DUAL_PORT_SETS: 1420 return (dgettext(TEXT_DOMAIN, 1421 "Both inner ports and outer ports are set")); 1422 case SADB_X_DIAGNOSTIC_PAIR_INAPPROPRIATE: 1423 return (dgettext(TEXT_DOMAIN, 1424 "Pairing failed, target SA unsuitable for pairing")); 1425 case SADB_X_DIAGNOSTIC_PAIR_ADD_MISMATCH: 1426 return (dgettext(TEXT_DOMAIN, 1427 "Source/destination address differs from pair SA")); 1428 case SADB_X_DIAGNOSTIC_PAIR_ALREADY: 1429 return (dgettext(TEXT_DOMAIN, 1430 "Already paired with another security association")); 1431 case SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND: 1432 return (dgettext(TEXT_DOMAIN, 1433 "Command failed, pair security association not found")); 1434 case SADB_X_DIAGNOSTIC_BAD_SA_DIRECTION: 1435 return (dgettext(TEXT_DOMAIN, 1436 "Inappropriate SA direction")); 1437 case SADB_X_DIAGNOSTIC_SA_NOTFOUND: 1438 return (dgettext(TEXT_DOMAIN, 1439 "Security association not found")); 1440 case SADB_X_DIAGNOSTIC_SA_EXPIRED: 1441 return (dgettext(TEXT_DOMAIN, 1442 "Security association is not valid")); 1443 case SADB_X_DIAGNOSTIC_BAD_CTX: 1444 return (dgettext(TEXT_DOMAIN, 1445 "Algorithm invalid or not supported by Crypto Framework")); 1446 case SADB_X_DIAGNOSTIC_INVALID_REPLAY: 1447 return (dgettext(TEXT_DOMAIN, 1448 "Invalid Replay counter")); 1449 case SADB_X_DIAGNOSTIC_MISSING_LIFETIME: 1450 return (dgettext(TEXT_DOMAIN, 1451 "Inappropriate lifetimes")); 1452 default: 1453 return (dgettext(TEXT_DOMAIN, "Unknown diagnostic code")); 1454 } 1455 } 1456 1457 /* 1458 * Convert an IPv6 mask to a prefix len. I assume all IPv6 masks are 1459 * contiguous, so I stop at the first zero bit! 1460 */ 1461 int 1462 in_masktoprefix(uint8_t *mask, boolean_t is_v4mapped) 1463 { 1464 int rc = 0; 1465 uint8_t last; 1466 int limit = IPV6_ABITS; 1467 1468 if (is_v4mapped) { 1469 mask += ((IPV6_ABITS - IP_ABITS)/8); 1470 limit = IP_ABITS; 1471 } 1472 1473 while (*mask == 0xff) { 1474 rc += 8; 1475 if (rc == limit) 1476 return (limit); 1477 mask++; 1478 } 1479 1480 last = *mask; 1481 while (last != 0) { 1482 rc++; 1483 last = (last << 1) & 0xff; 1484 } 1485 1486 return (rc); 1487 } 1488 1489 /* 1490 * Expand the diagnostic code into a message. 1491 */ 1492 void 1493 print_diagnostic(FILE *file, uint16_t diagnostic) 1494 { 1495 /* Use two spaces so above strings can fit on the line. */ 1496 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1497 " Diagnostic code %u: %s.\n"), 1498 diagnostic, keysock_diag(diagnostic)); 1499 } 1500 1501 /* 1502 * Prints the base PF_KEY message. 1503 */ 1504 void 1505 print_sadb_msg(FILE *file, struct sadb_msg *samsg, time_t wallclock, 1506 boolean_t vflag) 1507 { 1508 if (wallclock != 0) 1509 printsatime(file, wallclock, dgettext(TEXT_DOMAIN, 1510 "%sTimestamp: %s\n"), "", NULL, 1511 vflag); 1512 1513 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1514 "Base message (version %u) type "), 1515 samsg->sadb_msg_version); 1516 switch (samsg->sadb_msg_type) { 1517 case SADB_RESERVED: 1518 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1519 "RESERVED (warning: set to 0)")); 1520 break; 1521 case SADB_GETSPI: 1522 (void) fprintf(file, "GETSPI"); 1523 break; 1524 case SADB_UPDATE: 1525 (void) fprintf(file, "UPDATE"); 1526 break; 1527 case SADB_X_UPDATEPAIR: 1528 (void) fprintf(file, "UPDATE PAIR"); 1529 break; 1530 case SADB_ADD: 1531 (void) fprintf(file, "ADD"); 1532 break; 1533 case SADB_DELETE: 1534 (void) fprintf(file, "DELETE"); 1535 break; 1536 case SADB_X_DELPAIR: 1537 (void) fprintf(file, "DELETE PAIR"); 1538 break; 1539 case SADB_GET: 1540 (void) fprintf(file, "GET"); 1541 break; 1542 case SADB_ACQUIRE: 1543 (void) fprintf(file, "ACQUIRE"); 1544 break; 1545 case SADB_REGISTER: 1546 (void) fprintf(file, "REGISTER"); 1547 break; 1548 case SADB_EXPIRE: 1549 (void) fprintf(file, "EXPIRE"); 1550 break; 1551 case SADB_FLUSH: 1552 (void) fprintf(file, "FLUSH"); 1553 break; 1554 case SADB_DUMP: 1555 (void) fprintf(file, "DUMP"); 1556 break; 1557 case SADB_X_PROMISC: 1558 (void) fprintf(file, "X_PROMISC"); 1559 break; 1560 case SADB_X_INVERSE_ACQUIRE: 1561 (void) fprintf(file, "X_INVERSE_ACQUIRE"); 1562 break; 1563 default: 1564 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1565 "Unknown (%u)"), samsg->sadb_msg_type); 1566 break; 1567 } 1568 (void) fprintf(file, dgettext(TEXT_DOMAIN, ", SA type ")); 1569 1570 switch (samsg->sadb_msg_satype) { 1571 case SADB_SATYPE_UNSPEC: 1572 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1573 "<unspecified/all>")); 1574 break; 1575 case SADB_SATYPE_AH: 1576 (void) fprintf(file, "AH"); 1577 break; 1578 case SADB_SATYPE_ESP: 1579 (void) fprintf(file, "ESP"); 1580 break; 1581 case SADB_SATYPE_RSVP: 1582 (void) fprintf(file, "RSVP"); 1583 break; 1584 case SADB_SATYPE_OSPFV2: 1585 (void) fprintf(file, "OSPFv2"); 1586 break; 1587 case SADB_SATYPE_RIPV2: 1588 (void) fprintf(file, "RIPv2"); 1589 break; 1590 case SADB_SATYPE_MIP: 1591 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Mobile IP")); 1592 break; 1593 default: 1594 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1595 "<unknown %u>"), samsg->sadb_msg_satype); 1596 break; 1597 } 1598 1599 (void) fprintf(file, ".\n"); 1600 1601 if (samsg->sadb_msg_errno != 0) { 1602 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1603 "Error %s from PF_KEY.\n"), 1604 strerror(samsg->sadb_msg_errno)); 1605 print_diagnostic(file, samsg->sadb_x_msg_diagnostic); 1606 } 1607 1608 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1609 "Message length %u bytes, seq=%u, pid=%u.\n"), 1610 SADB_64TO8(samsg->sadb_msg_len), samsg->sadb_msg_seq, 1611 samsg->sadb_msg_pid); 1612 } 1613 1614 /* 1615 * Print the SA extension for PF_KEY. 1616 */ 1617 void 1618 print_sa(FILE *file, char *prefix, struct sadb_sa *assoc) 1619 { 1620 if (assoc->sadb_sa_len != SADB_8TO64(sizeof (*assoc))) { 1621 warnxfp(EFD(file), dgettext(TEXT_DOMAIN, 1622 "WARNING: SA info extension length (%u) is bad."), 1623 SADB_64TO8(assoc->sadb_sa_len)); 1624 } 1625 1626 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1627 "%sSADB_ASSOC spi=0x%x, replay window size=%u, state="), 1628 prefix, ntohl(assoc->sadb_sa_spi), assoc->sadb_sa_replay); 1629 switch (assoc->sadb_sa_state) { 1630 case SADB_SASTATE_LARVAL: 1631 (void) fprintf(file, dgettext(TEXT_DOMAIN, "LARVAL")); 1632 break; 1633 case SADB_SASTATE_MATURE: 1634 (void) fprintf(file, dgettext(TEXT_DOMAIN, "MATURE")); 1635 break; 1636 case SADB_SASTATE_DYING: 1637 (void) fprintf(file, dgettext(TEXT_DOMAIN, "DYING")); 1638 break; 1639 case SADB_SASTATE_DEAD: 1640 (void) fprintf(file, dgettext(TEXT_DOMAIN, "DEAD")); 1641 break; 1642 case SADB_X_SASTATE_ACTIVE_ELSEWHERE: 1643 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1644 "ACTIVE_ELSEWHERE")); 1645 break; 1646 case SADB_X_SASTATE_IDLE: 1647 (void) fprintf(file, dgettext(TEXT_DOMAIN, "IDLE")); 1648 break; 1649 default: 1650 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1651 "<unknown %u>"), assoc->sadb_sa_state); 1652 } 1653 1654 if (assoc->sadb_sa_auth != SADB_AALG_NONE) { 1655 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1656 "\n%sAuthentication algorithm = "), 1657 prefix); 1658 (void) dump_aalg(assoc->sadb_sa_auth, file); 1659 } 1660 1661 if (assoc->sadb_sa_encrypt != SADB_EALG_NONE) { 1662 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1663 "\n%sEncryption algorithm = "), prefix); 1664 (void) dump_ealg(assoc->sadb_sa_encrypt, file); 1665 } 1666 1667 (void) fprintf(file, dgettext(TEXT_DOMAIN, "\n%sflags=0x%x < "), prefix, 1668 assoc->sadb_sa_flags); 1669 if (assoc->sadb_sa_flags & SADB_SAFLAGS_PFS) 1670 (void) fprintf(file, "PFS "); 1671 if (assoc->sadb_sa_flags & SADB_SAFLAGS_NOREPLAY) 1672 (void) fprintf(file, "NOREPLAY "); 1673 1674 /* BEGIN Solaris-specific flags. */ 1675 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_USED) 1676 (void) fprintf(file, "X_USED "); 1677 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_PAIRED) 1678 (void) fprintf(file, "X_PAIRED "); 1679 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_OUTBOUND) 1680 (void) fprintf(file, "X_OUTBOUND "); 1681 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_INBOUND) 1682 (void) fprintf(file, "X_INBOUND "); 1683 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_UNIQUE) 1684 (void) fprintf(file, "X_UNIQUE "); 1685 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_AALG1) 1686 (void) fprintf(file, "X_AALG1 "); 1687 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_AALG2) 1688 (void) fprintf(file, "X_AALG2 "); 1689 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_EALG1) 1690 (void) fprintf(file, "X_EALG1 "); 1691 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_EALG2) 1692 (void) fprintf(file, "X_EALG2 "); 1693 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_LOC) 1694 (void) fprintf(file, "X_NATT_LOC "); 1695 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_REM) 1696 (void) fprintf(file, "X_NATT_REM "); 1697 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_TUNNEL) 1698 (void) fprintf(file, "X_TUNNEL "); 1699 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATTED) 1700 (void) fprintf(file, "X_NATTED "); 1701 /* END Solaris-specific flags. */ 1702 1703 (void) fprintf(file, ">\n"); 1704 } 1705 1706 void 1707 printsatime(FILE *file, int64_t lt, const char *msg, const char *pfx, 1708 const char *pfx2, boolean_t vflag) 1709 { 1710 char tbuf[TBUF_SIZE]; /* For strftime() call. */ 1711 const char *tp = tbuf; 1712 time_t t = lt; 1713 struct tm res; 1714 1715 if (t != lt) { 1716 if (lt > 0) 1717 t = LONG_MAX; 1718 else 1719 t = LONG_MIN; 1720 } 1721 1722 if (strftime(tbuf, TBUF_SIZE, NULL, localtime_r(&t, &res)) == 0) 1723 tp = dgettext(TEXT_DOMAIN, "<time conversion failed>"); 1724 (void) fprintf(file, msg, pfx, tp); 1725 if (vflag && (pfx2 != NULL)) 1726 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1727 "%s\t(raw time value %" PRIu64 ")\n"), pfx2, lt); 1728 } 1729 1730 /* 1731 * Print the SA lifetime information. (An SADB_EXT_LIFETIME_* extension.) 1732 */ 1733 void 1734 print_lifetimes(FILE *file, time_t wallclock, struct sadb_lifetime *current, 1735 struct sadb_lifetime *hard, struct sadb_lifetime *soft, 1736 struct sadb_lifetime *idle, boolean_t vflag) 1737 { 1738 int64_t scratch; 1739 char *soft_prefix = dgettext(TEXT_DOMAIN, "SLT: "); 1740 char *hard_prefix = dgettext(TEXT_DOMAIN, "HLT: "); 1741 char *current_prefix = dgettext(TEXT_DOMAIN, "CLT: "); 1742 char *idle_prefix = dgettext(TEXT_DOMAIN, "ILT: "); 1743 1744 if (current != NULL && 1745 current->sadb_lifetime_len != SADB_8TO64(sizeof (*current))) { 1746 warnxfp(EFD(file), dgettext(TEXT_DOMAIN, 1747 "WARNING: CURRENT lifetime extension length (%u) is bad."), 1748 SADB_64TO8(current->sadb_lifetime_len)); 1749 } 1750 1751 if (hard != NULL && 1752 hard->sadb_lifetime_len != SADB_8TO64(sizeof (*hard))) { 1753 warnxfp(EFD(file), dgettext(TEXT_DOMAIN, 1754 "WARNING: HARD lifetime extension length (%u) is bad."), 1755 SADB_64TO8(hard->sadb_lifetime_len)); 1756 } 1757 1758 if (soft != NULL && 1759 soft->sadb_lifetime_len != SADB_8TO64(sizeof (*soft))) { 1760 warnxfp(EFD(file), dgettext(TEXT_DOMAIN, 1761 "WARNING: SOFT lifetime extension length (%u) is bad."), 1762 SADB_64TO8(soft->sadb_lifetime_len)); 1763 } 1764 1765 if (idle != NULL && 1766 idle->sadb_lifetime_len != SADB_8TO64(sizeof (*idle))) { 1767 warnxfp(EFD(file), dgettext(TEXT_DOMAIN, 1768 "WARNING: IDLE lifetime extension length (%u) is bad."), 1769 SADB_64TO8(idle->sadb_lifetime_len)); 1770 } 1771 1772 (void) fprintf(file, " LT: Lifetime information\n"); 1773 1774 if (current != NULL) { 1775 /* Express values as current values. */ 1776 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1777 "%s%" PRIu64 " bytes protected, %u allocations used.\n"), 1778 current_prefix, current->sadb_lifetime_bytes, 1779 current->sadb_lifetime_allocations); 1780 printsatime(file, current->sadb_lifetime_addtime, 1781 dgettext(TEXT_DOMAIN, "%sSA added at time %s\n"), 1782 current_prefix, current_prefix, vflag); 1783 if (current->sadb_lifetime_usetime != 0) { 1784 printsatime(file, current->sadb_lifetime_usetime, 1785 dgettext(TEXT_DOMAIN, 1786 "%sSA first used at time %s\n"), 1787 current_prefix, current_prefix, vflag); 1788 } 1789 printsatime(file, wallclock, dgettext(TEXT_DOMAIN, 1790 "%sTime now is %s\n"), current_prefix, current_prefix, 1791 vflag); 1792 } 1793 1794 if (soft != NULL) { 1795 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1796 "%sSoft lifetime information: "), 1797 soft_prefix); 1798 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1799 "%" PRIu64 " bytes of lifetime, %u " 1800 "allocations.\n"), soft->sadb_lifetime_bytes, 1801 soft->sadb_lifetime_allocations); 1802 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1803 "%s%" PRIu64 " seconds of post-add lifetime.\n"), 1804 soft_prefix, soft->sadb_lifetime_addtime); 1805 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1806 "%s%" PRIu64 " seconds of post-use lifetime.\n"), 1807 soft_prefix, soft->sadb_lifetime_usetime); 1808 /* If possible, express values as time remaining. */ 1809 if (current != NULL) { 1810 if (soft->sadb_lifetime_bytes != 0) 1811 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%s%" 1812 PRIu64 " more bytes can be protected.\n"), 1813 soft_prefix, 1814 (soft->sadb_lifetime_bytes > 1815 current->sadb_lifetime_bytes) ? 1816 (soft->sadb_lifetime_bytes - 1817 current->sadb_lifetime_bytes) : (0)); 1818 if (soft->sadb_lifetime_addtime != 0 || 1819 (soft->sadb_lifetime_usetime != 0 && 1820 current->sadb_lifetime_usetime != 0)) { 1821 int64_t adddelta, usedelta; 1822 1823 if (soft->sadb_lifetime_addtime != 0) { 1824 adddelta = 1825 current->sadb_lifetime_addtime + 1826 soft->sadb_lifetime_addtime - 1827 wallclock; 1828 } else { 1829 adddelta = TIME_MAX; 1830 } 1831 1832 if (soft->sadb_lifetime_usetime != 0 && 1833 current->sadb_lifetime_usetime != 0) { 1834 usedelta = 1835 current->sadb_lifetime_usetime + 1836 soft->sadb_lifetime_usetime - 1837 wallclock; 1838 } else { 1839 usedelta = TIME_MAX; 1840 } 1841 (void) fprintf(file, "%s", soft_prefix); 1842 scratch = MIN(adddelta, usedelta); 1843 if (scratch >= 0) { 1844 (void) fprintf(file, 1845 dgettext(TEXT_DOMAIN, 1846 "Soft expiration occurs in %" 1847 PRId64 " seconds, "), scratch); 1848 } else { 1849 (void) fprintf(file, 1850 dgettext(TEXT_DOMAIN, 1851 "Soft expiration occurred ")); 1852 } 1853 scratch += wallclock; 1854 printsatime(file, scratch, dgettext(TEXT_DOMAIN, 1855 "%sat %s.\n"), "", soft_prefix, vflag); 1856 } 1857 } 1858 } 1859 1860 if (hard != NULL) { 1861 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1862 "%sHard lifetime information: "), hard_prefix); 1863 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1864 "%" PRIu64 " bytes of lifetime, %u allocations.\n"), 1865 hard->sadb_lifetime_bytes, hard->sadb_lifetime_allocations); 1866 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1867 "%s%" PRIu64 " seconds of post-add lifetime.\n"), 1868 hard_prefix, hard->sadb_lifetime_addtime); 1869 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1870 "%s%" PRIu64 " seconds of post-use lifetime.\n"), 1871 hard_prefix, hard->sadb_lifetime_usetime); 1872 /* If possible, express values as time remaining. */ 1873 if (current != NULL) { 1874 if (hard->sadb_lifetime_bytes != 0) 1875 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%s%" 1876 PRIu64 " more bytes can be protected.\n"), 1877 hard_prefix, 1878 (hard->sadb_lifetime_bytes > 1879 current->sadb_lifetime_bytes) ? 1880 (hard->sadb_lifetime_bytes - 1881 current->sadb_lifetime_bytes) : (0)); 1882 if (hard->sadb_lifetime_addtime != 0 || 1883 (hard->sadb_lifetime_usetime != 0 && 1884 current->sadb_lifetime_usetime != 0)) { 1885 int64_t adddelta, usedelta; 1886 1887 if (hard->sadb_lifetime_addtime != 0) { 1888 adddelta = 1889 current->sadb_lifetime_addtime + 1890 hard->sadb_lifetime_addtime - 1891 wallclock; 1892 } else { 1893 adddelta = TIME_MAX; 1894 } 1895 1896 if (hard->sadb_lifetime_usetime != 0 && 1897 current->sadb_lifetime_usetime != 0) { 1898 usedelta = 1899 current->sadb_lifetime_usetime + 1900 hard->sadb_lifetime_usetime - 1901 wallclock; 1902 } else { 1903 usedelta = TIME_MAX; 1904 } 1905 (void) fprintf(file, "%s", hard_prefix); 1906 scratch = MIN(adddelta, usedelta); 1907 if (scratch >= 0) { 1908 (void) fprintf(file, 1909 dgettext(TEXT_DOMAIN, 1910 "Hard expiration occurs in %" 1911 PRId64 " seconds, "), scratch); 1912 } else { 1913 (void) fprintf(file, 1914 dgettext(TEXT_DOMAIN, 1915 "Hard expiration occured ")); 1916 } 1917 scratch += wallclock; 1918 printsatime(file, scratch, dgettext(TEXT_DOMAIN, 1919 "%sat %s.\n"), "", hard_prefix, vflag); 1920 } 1921 } 1922 } 1923 if (idle != NULL) { 1924 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1925 "%sIdle lifetime information: "), idle_prefix); 1926 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1927 "%s%llu seconds of post-add lifetime.\n"), 1928 idle_prefix, idle->sadb_lifetime_addtime); 1929 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1930 "%s%llu seconds of post-use lifetime.\n"), 1931 idle_prefix, idle->sadb_lifetime_usetime); 1932 } 1933 } 1934 1935 /* 1936 * Print an SADB_EXT_ADDRESS_* extension. 1937 */ 1938 void 1939 print_address(FILE *file, char *prefix, struct sadb_address *addr, 1940 boolean_t ignore_nss) 1941 { 1942 struct protoent *pe; 1943 1944 (void) fprintf(file, "%s", prefix); 1945 switch (addr->sadb_address_exttype) { 1946 case SADB_EXT_ADDRESS_SRC: 1947 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Source address ")); 1948 break; 1949 case SADB_X_EXT_ADDRESS_INNER_SRC: 1950 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1951 "Inner source address ")); 1952 break; 1953 case SADB_EXT_ADDRESS_DST: 1954 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1955 "Destination address ")); 1956 break; 1957 case SADB_X_EXT_ADDRESS_INNER_DST: 1958 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1959 "Inner destination address ")); 1960 break; 1961 case SADB_X_EXT_ADDRESS_NATT_LOC: 1962 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1963 "NAT-T local address ")); 1964 break; 1965 case SADB_X_EXT_ADDRESS_NATT_REM: 1966 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1967 "NAT-T remote address ")); 1968 break; 1969 } 1970 1971 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1972 "(proto=%d"), addr->sadb_address_proto); 1973 if (ignore_nss == B_FALSE) { 1974 if (addr->sadb_address_proto == 0) { 1975 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1976 "/<unspecified>")); 1977 } else if ((pe = getprotobynumber(addr->sadb_address_proto)) 1978 != NULL) { 1979 (void) fprintf(file, "/%s", pe->p_name); 1980 } else { 1981 (void) fprintf(file, dgettext(TEXT_DOMAIN, 1982 "/<unknown>")); 1983 } 1984 } 1985 (void) fprintf(file, dgettext(TEXT_DOMAIN, ")\n%s"), prefix); 1986 (void) dump_sockaddr((struct sockaddr *)(addr + 1), 1987 addr->sadb_address_prefixlen, B_FALSE, file, ignore_nss); 1988 } 1989 1990 /* 1991 * Print an SADB_EXT_KEY extension. 1992 */ 1993 void 1994 print_key(FILE *file, char *prefix, struct sadb_key *key) 1995 { 1996 (void) fprintf(file, "%s", prefix); 1997 1998 switch (key->sadb_key_exttype) { 1999 case SADB_EXT_KEY_AUTH: 2000 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Authentication")); 2001 break; 2002 case SADB_EXT_KEY_ENCRYPT: 2003 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Encryption")); 2004 break; 2005 } 2006 2007 (void) fprintf(file, dgettext(TEXT_DOMAIN, " key.\n%s"), prefix); 2008 (void) dump_key((uint8_t *)(key + 1), key->sadb_key_bits, 2009 key->sadb_key_reserved, file, B_TRUE); 2010 (void) fprintf(file, "\n"); 2011 } 2012 2013 /* 2014 * Print an SADB_EXT_IDENTITY_* extension. 2015 */ 2016 void 2017 print_ident(FILE *file, char *prefix, struct sadb_ident *id) 2018 { 2019 boolean_t canprint = B_TRUE; 2020 2021 (void) fprintf(file, "%s", prefix); 2022 switch (id->sadb_ident_exttype) { 2023 case SADB_EXT_IDENTITY_SRC: 2024 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Source")); 2025 break; 2026 case SADB_EXT_IDENTITY_DST: 2027 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Destination")); 2028 break; 2029 } 2030 2031 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2032 " identity, uid=%d, type "), id->sadb_ident_id); 2033 canprint = dump_sadb_idtype(id->sadb_ident_type, file, NULL); 2034 (void) fprintf(file, "\n%s", prefix); 2035 if (canprint) { 2036 (void) fprintf(file, "%s\n", (char *)(id + 1)); 2037 } else { 2038 print_asn1_name(file, (const unsigned char *)(id + 1), 2039 SADB_64TO8(id->sadb_ident_len) - sizeof (sadb_ident_t)); 2040 } 2041 } 2042 2043 /* 2044 * Convert sadb_sens extension into binary security label. 2045 */ 2046 2047 #include <tsol/label.h> 2048 #include <sys/tsol/tndb.h> 2049 #include <sys/tsol/label_macro.h> 2050 2051 void 2052 ipsec_convert_sens_to_bslabel(const struct sadb_sens *sens, bslabel_t *sl) 2053 { 2054 uint64_t *bitmap = (uint64_t *)(sens + 1); 2055 int bitmap_len = SADB_64TO8(sens->sadb_sens_sens_len); 2056 2057 bsllow(sl); 2058 LCLASS_SET((_bslabel_impl_t *)sl, sens->sadb_sens_sens_level); 2059 bcopy(bitmap, &((_bslabel_impl_t *)sl)->compartments, 2060 bitmap_len); 2061 } 2062 2063 void 2064 ipsec_convert_bslabel_to_string(bslabel_t *sl, char **plabel) 2065 { 2066 if (label_to_str(sl, plabel, M_LABEL, DEF_NAMES) != 0) { 2067 *plabel = strdup(dgettext(TEXT_DOMAIN, 2068 "** Label conversion failed **")); 2069 } 2070 } 2071 2072 void 2073 ipsec_convert_bslabel_to_hex(bslabel_t *sl, char **plabel) 2074 { 2075 if (label_to_str(sl, plabel, M_INTERNAL, DEF_NAMES) != 0) { 2076 *plabel = strdup(dgettext(TEXT_DOMAIN, 2077 "** Label conversion failed **")); 2078 } 2079 } 2080 2081 int 2082 ipsec_convert_sl_to_sens(int doi, bslabel_t *sl, sadb_sens_t *sens) 2083 { 2084 uint8_t *bitmap; 2085 int sens_len = sizeof (sadb_sens_t) + _C_LEN * 4; 2086 2087 2088 if (sens == NULL) 2089 return (sens_len); 2090 2091 2092 (void) memset(sens, 0, sens_len); 2093 2094 sens->sadb_sens_exttype = SADB_EXT_SENSITIVITY; 2095 sens->sadb_sens_len = SADB_8TO64(sens_len); 2096 sens->sadb_sens_dpd = doi; 2097 2098 sens->sadb_sens_sens_level = LCLASS(sl); 2099 sens->sadb_sens_integ_level = 0; 2100 sens->sadb_sens_sens_len = _C_LEN >> 1; 2101 sens->sadb_sens_integ_len = 0; 2102 2103 sens->sadb_x_sens_flags = 0; 2104 2105 bitmap = (uint8_t *)(sens + 1); 2106 bcopy(&(((_bslabel_impl_t *)sl)->compartments), bitmap, _C_LEN * 4); 2107 2108 return (sens_len); 2109 } 2110 2111 2112 /* 2113 * Print an SADB_SENSITIVITY extension. 2114 */ 2115 void 2116 print_sens(FILE *file, char *prefix, const struct sadb_sens *sens, 2117 boolean_t ignore_nss) 2118 { 2119 char *plabel; 2120 char *hlabel; 2121 uint64_t *bitmap = (uint64_t *)(sens + 1); 2122 bslabel_t sl; 2123 int i; 2124 int sens_len = sens->sadb_sens_sens_len; 2125 int integ_len = sens->sadb_sens_integ_len; 2126 boolean_t inner = (sens->sadb_sens_exttype == SADB_EXT_SENSITIVITY); 2127 const char *sensname = inner ? 2128 dgettext(TEXT_DOMAIN, "Plaintext Sensitivity") : 2129 dgettext(TEXT_DOMAIN, "Ciphertext Sensitivity"); 2130 2131 ipsec_convert_sens_to_bslabel(sens, &sl); 2132 2133 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2134 "%s%s DPD %d, sens level=%d, integ level=%d, flags=%x\n"), 2135 prefix, sensname, sens->sadb_sens_dpd, sens->sadb_sens_sens_level, 2136 sens->sadb_sens_integ_level, sens->sadb_x_sens_flags); 2137 2138 ipsec_convert_bslabel_to_hex(&sl, &hlabel); 2139 2140 if (ignore_nss) { 2141 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2142 "%s %s Label: %s\n"), prefix, sensname, hlabel); 2143 2144 for (i = 0; i < sens_len; i++, bitmap++) 2145 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2146 "%s %s BM extended word %d 0x%" PRIx64 "\n"), 2147 prefix, sensname, i, *bitmap); 2148 2149 } else { 2150 ipsec_convert_bslabel_to_string(&sl, &plabel); 2151 2152 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2153 "%s %s Label: %s (%s)\n"), 2154 prefix, sensname, plabel, hlabel); 2155 free(plabel); 2156 2157 } 2158 free(hlabel); 2159 2160 bitmap = (uint64_t *)(sens + 1 + sens_len); 2161 2162 for (i = 0; i < integ_len; i++, bitmap++) 2163 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2164 "%s Integrity BM extended word %d 0x%" PRIx64 "\n"), 2165 prefix, i, *bitmap); 2166 } 2167 2168 /* 2169 * Print an SADB_EXT_PROPOSAL extension. 2170 */ 2171 void 2172 print_prop(FILE *file, char *prefix, struct sadb_prop *prop) 2173 { 2174 struct sadb_comb *combs; 2175 int i, numcombs; 2176 2177 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2178 "%sProposal, replay counter = %u.\n"), prefix, 2179 prop->sadb_prop_replay); 2180 2181 numcombs = prop->sadb_prop_len - SADB_8TO64(sizeof (*prop)); 2182 numcombs /= SADB_8TO64(sizeof (*combs)); 2183 2184 combs = (struct sadb_comb *)(prop + 1); 2185 2186 for (i = 0; i < numcombs; i++) { 2187 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2188 "%s Combination #%u "), prefix, i + 1); 2189 if (combs[i].sadb_comb_auth != SADB_AALG_NONE) { 2190 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2191 "Authentication = ")); 2192 (void) dump_aalg(combs[i].sadb_comb_auth, file); 2193 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2194 " minbits=%u, maxbits=%u.\n%s "), 2195 combs[i].sadb_comb_auth_minbits, 2196 combs[i].sadb_comb_auth_maxbits, prefix); 2197 } 2198 2199 if (combs[i].sadb_comb_encrypt != SADB_EALG_NONE) { 2200 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2201 "Encryption = ")); 2202 (void) dump_ealg(combs[i].sadb_comb_encrypt, file); 2203 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2204 " minbits=%u, maxbits=%u.\n%s "), 2205 combs[i].sadb_comb_encrypt_minbits, 2206 combs[i].sadb_comb_encrypt_maxbits, prefix); 2207 } 2208 2209 (void) fprintf(file, dgettext(TEXT_DOMAIN, "HARD: ")); 2210 if (combs[i].sadb_comb_hard_allocations) 2211 (void) fprintf(file, dgettext(TEXT_DOMAIN, "alloc=%u "), 2212 combs[i].sadb_comb_hard_allocations); 2213 if (combs[i].sadb_comb_hard_bytes) 2214 (void) fprintf(file, dgettext(TEXT_DOMAIN, "bytes=%" 2215 PRIu64 " "), combs[i].sadb_comb_hard_bytes); 2216 if (combs[i].sadb_comb_hard_addtime) 2217 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2218 "post-add secs=%" PRIu64 " "), 2219 combs[i].sadb_comb_hard_addtime); 2220 if (combs[i].sadb_comb_hard_usetime) 2221 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2222 "post-use secs=%" PRIu64 ""), 2223 combs[i].sadb_comb_hard_usetime); 2224 2225 (void) fprintf(file, dgettext(TEXT_DOMAIN, "\n%s SOFT: "), 2226 prefix); 2227 if (combs[i].sadb_comb_soft_allocations) 2228 (void) fprintf(file, dgettext(TEXT_DOMAIN, "alloc=%u "), 2229 combs[i].sadb_comb_soft_allocations); 2230 if (combs[i].sadb_comb_soft_bytes) 2231 (void) fprintf(file, dgettext(TEXT_DOMAIN, "bytes=%" 2232 PRIu64 " "), combs[i].sadb_comb_soft_bytes); 2233 if (combs[i].sadb_comb_soft_addtime) 2234 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2235 "post-add secs=%" PRIu64 " "), 2236 combs[i].sadb_comb_soft_addtime); 2237 if (combs[i].sadb_comb_soft_usetime) 2238 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2239 "post-use secs=%" PRIu64 ""), 2240 combs[i].sadb_comb_soft_usetime); 2241 (void) fprintf(file, "\n"); 2242 } 2243 } 2244 2245 /* 2246 * Print an extended proposal (SADB_X_EXT_EPROP). 2247 */ 2248 void 2249 print_eprop(FILE *file, char *prefix, struct sadb_prop *eprop) 2250 { 2251 uint64_t *sofar; 2252 struct sadb_x_ecomb *ecomb; 2253 struct sadb_x_algdesc *algdesc; 2254 int i, j; 2255 2256 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2257 "%sExtended Proposal, replay counter = %u, "), prefix, 2258 eprop->sadb_prop_replay); 2259 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2260 "number of combinations = %u.\n"), eprop->sadb_x_prop_numecombs); 2261 2262 sofar = (uint64_t *)(eprop + 1); 2263 ecomb = (struct sadb_x_ecomb *)sofar; 2264 2265 for (i = 0; i < eprop->sadb_x_prop_numecombs; ) { 2266 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2267 "%s Extended combination #%u:\n"), prefix, ++i); 2268 2269 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%s HARD: "), 2270 prefix); 2271 (void) fprintf(file, dgettext(TEXT_DOMAIN, "alloc=%u, "), 2272 ecomb->sadb_x_ecomb_hard_allocations); 2273 (void) fprintf(file, dgettext(TEXT_DOMAIN, "bytes=%" PRIu64 2274 ", "), ecomb->sadb_x_ecomb_hard_bytes); 2275 (void) fprintf(file, dgettext(TEXT_DOMAIN, "post-add secs=%" 2276 PRIu64 ", "), ecomb->sadb_x_ecomb_hard_addtime); 2277 (void) fprintf(file, dgettext(TEXT_DOMAIN, "post-use secs=%" 2278 PRIu64 "\n"), ecomb->sadb_x_ecomb_hard_usetime); 2279 2280 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%s SOFT: "), 2281 prefix); 2282 (void) fprintf(file, dgettext(TEXT_DOMAIN, "alloc=%u, "), 2283 ecomb->sadb_x_ecomb_soft_allocations); 2284 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2285 "bytes=%" PRIu64 ", "), ecomb->sadb_x_ecomb_soft_bytes); 2286 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2287 "post-add secs=%" PRIu64 ", "), 2288 ecomb->sadb_x_ecomb_soft_addtime); 2289 (void) fprintf(file, dgettext(TEXT_DOMAIN, "post-use secs=%" 2290 PRIu64 "\n"), ecomb->sadb_x_ecomb_soft_usetime); 2291 2292 sofar = (uint64_t *)(ecomb + 1); 2293 algdesc = (struct sadb_x_algdesc *)sofar; 2294 2295 for (j = 0; j < ecomb->sadb_x_ecomb_numalgs; ) { 2296 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2297 "%s Alg #%u "), prefix, ++j); 2298 switch (algdesc->sadb_x_algdesc_satype) { 2299 case SADB_SATYPE_ESP: 2300 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2301 "for ESP ")); 2302 break; 2303 case SADB_SATYPE_AH: 2304 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2305 "for AH ")); 2306 break; 2307 default: 2308 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2309 "for satype=%d "), 2310 algdesc->sadb_x_algdesc_satype); 2311 } 2312 switch (algdesc->sadb_x_algdesc_algtype) { 2313 case SADB_X_ALGTYPE_CRYPT: 2314 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2315 "Encryption = ")); 2316 (void) dump_ealg(algdesc->sadb_x_algdesc_alg, 2317 file); 2318 break; 2319 case SADB_X_ALGTYPE_AUTH: 2320 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2321 "Authentication = ")); 2322 (void) dump_aalg(algdesc->sadb_x_algdesc_alg, 2323 file); 2324 break; 2325 default: 2326 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2327 "algtype(%d) = alg(%d)"), 2328 algdesc->sadb_x_algdesc_algtype, 2329 algdesc->sadb_x_algdesc_alg); 2330 break; 2331 } 2332 2333 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2334 " minbits=%u, maxbits=%u, saltbits=%u\n"), 2335 algdesc->sadb_x_algdesc_minbits, 2336 algdesc->sadb_x_algdesc_maxbits, 2337 algdesc->sadb_x_algdesc_reserved); 2338 2339 sofar = (uint64_t *)(++algdesc); 2340 } 2341 ecomb = (struct sadb_x_ecomb *)sofar; 2342 } 2343 } 2344 2345 /* 2346 * Print an SADB_EXT_SUPPORTED extension. 2347 */ 2348 void 2349 print_supp(FILE *file, char *prefix, struct sadb_supported *supp) 2350 { 2351 struct sadb_alg *algs; 2352 int i, numalgs; 2353 2354 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%sSupported "), prefix); 2355 switch (supp->sadb_supported_exttype) { 2356 case SADB_EXT_SUPPORTED_AUTH: 2357 (void) fprintf(file, dgettext(TEXT_DOMAIN, "authentication")); 2358 break; 2359 case SADB_EXT_SUPPORTED_ENCRYPT: 2360 (void) fprintf(file, dgettext(TEXT_DOMAIN, "encryption")); 2361 break; 2362 } 2363 (void) fprintf(file, dgettext(TEXT_DOMAIN, " algorithms.\n")); 2364 2365 algs = (struct sadb_alg *)(supp + 1); 2366 numalgs = supp->sadb_supported_len - SADB_8TO64(sizeof (*supp)); 2367 numalgs /= SADB_8TO64(sizeof (*algs)); 2368 for (i = 0; i < numalgs; i++) { 2369 uint16_t exttype = supp->sadb_supported_exttype; 2370 2371 (void) fprintf(file, "%s", prefix); 2372 switch (exttype) { 2373 case SADB_EXT_SUPPORTED_AUTH: 2374 (void) dump_aalg(algs[i].sadb_alg_id, file); 2375 break; 2376 case SADB_EXT_SUPPORTED_ENCRYPT: 2377 (void) dump_ealg(algs[i].sadb_alg_id, file); 2378 break; 2379 } 2380 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2381 " minbits=%u, maxbits=%u, ivlen=%u, saltbits=%u"), 2382 algs[i].sadb_alg_minbits, algs[i].sadb_alg_maxbits, 2383 algs[i].sadb_alg_ivlen, algs[i].sadb_x_alg_saltbits); 2384 if (exttype == SADB_EXT_SUPPORTED_ENCRYPT) 2385 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2386 ", increment=%u"), algs[i].sadb_x_alg_increment); 2387 (void) fprintf(file, dgettext(TEXT_DOMAIN, ".\n")); 2388 } 2389 } 2390 2391 /* 2392 * Print an SADB_EXT_SPIRANGE extension. 2393 */ 2394 void 2395 print_spirange(FILE *file, char *prefix, struct sadb_spirange *range) 2396 { 2397 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2398 "%sSPI Range, min=0x%x, max=0x%x\n"), prefix, 2399 htonl(range->sadb_spirange_min), 2400 htonl(range->sadb_spirange_max)); 2401 } 2402 2403 /* 2404 * Print an SADB_X_EXT_KM_COOKIE extension. 2405 */ 2406 2407 void 2408 print_kmc(FILE *file, char *prefix, struct sadb_x_kmc *kmc) 2409 { 2410 char *cookie_label; 2411 2412 if ((cookie_label = kmc_lookup_by_cookie(kmc->sadb_x_kmc_cookie)) == 2413 NULL) 2414 cookie_label = dgettext(TEXT_DOMAIN, "<Label not found.>"); 2415 2416 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2417 "%sProtocol %u, cookie=\"%s\" (%u)\n"), prefix, 2418 kmc->sadb_x_kmc_proto, cookie_label, kmc->sadb_x_kmc_cookie); 2419 } 2420 2421 /* 2422 * Print an SADB_X_EXT_REPLAY_CTR extension. 2423 */ 2424 2425 void 2426 print_replay(FILE *file, char *prefix, sadb_x_replay_ctr_t *repl) 2427 { 2428 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2429 "%sReplay Value "), prefix); 2430 if ((repl->sadb_x_rc_replay32 == 0) && 2431 (repl->sadb_x_rc_replay64 == 0)) { 2432 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2433 "<Value not found.>")); 2434 } 2435 /* 2436 * We currently do not support a 64-bit replay value. 2437 * RFC 4301 will require one, however, and we have a field 2438 * in place when 4301 is built. 2439 */ 2440 (void) fprintf(file, "% " PRIu64 "\n", 2441 ((repl->sadb_x_rc_replay32 == 0) ? 2442 repl->sadb_x_rc_replay64 : repl->sadb_x_rc_replay32)); 2443 } 2444 /* 2445 * Print an SADB_X_EXT_PAIR extension. 2446 */ 2447 static void 2448 print_pair(FILE *file, char *prefix, struct sadb_x_pair *pair) 2449 { 2450 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%sPaired with spi=0x%x\n"), 2451 prefix, ntohl(pair->sadb_x_pair_spi)); 2452 } 2453 2454 /* 2455 * Take a PF_KEY message pointed to buffer and print it. Useful for DUMP 2456 * and GET. 2457 */ 2458 void 2459 print_samsg(FILE *file, uint64_t *buffer, boolean_t want_timestamp, 2460 boolean_t vflag, boolean_t ignore_nss) 2461 { 2462 uint64_t *current; 2463 struct sadb_msg *samsg = (struct sadb_msg *)buffer; 2464 struct sadb_ext *ext; 2465 struct sadb_lifetime *currentlt = NULL, *hardlt = NULL, *softlt = NULL; 2466 struct sadb_lifetime *idlelt = NULL; 2467 int i; 2468 time_t wallclock; 2469 2470 (void) time(&wallclock); 2471 2472 print_sadb_msg(file, samsg, want_timestamp ? wallclock : 0, vflag); 2473 current = (uint64_t *)(samsg + 1); 2474 while (current - buffer < samsg->sadb_msg_len) { 2475 int lenbytes; 2476 2477 ext = (struct sadb_ext *)current; 2478 lenbytes = SADB_64TO8(ext->sadb_ext_len); 2479 switch (ext->sadb_ext_type) { 2480 case SADB_EXT_SA: 2481 print_sa(file, dgettext(TEXT_DOMAIN, 2482 "SA: "), (struct sadb_sa *)current); 2483 break; 2484 /* 2485 * Pluck out lifetimes and print them at the end. This is 2486 * to show relative lifetimes. 2487 */ 2488 case SADB_EXT_LIFETIME_CURRENT: 2489 currentlt = (struct sadb_lifetime *)current; 2490 break; 2491 case SADB_EXT_LIFETIME_HARD: 2492 hardlt = (struct sadb_lifetime *)current; 2493 break; 2494 case SADB_EXT_LIFETIME_SOFT: 2495 softlt = (struct sadb_lifetime *)current; 2496 break; 2497 case SADB_X_EXT_LIFETIME_IDLE: 2498 idlelt = (struct sadb_lifetime *)current; 2499 break; 2500 2501 case SADB_EXT_ADDRESS_SRC: 2502 print_address(file, dgettext(TEXT_DOMAIN, "SRC: "), 2503 (struct sadb_address *)current, ignore_nss); 2504 break; 2505 case SADB_X_EXT_ADDRESS_INNER_SRC: 2506 print_address(file, dgettext(TEXT_DOMAIN, "INS: "), 2507 (struct sadb_address *)current, ignore_nss); 2508 break; 2509 case SADB_EXT_ADDRESS_DST: 2510 print_address(file, dgettext(TEXT_DOMAIN, "DST: "), 2511 (struct sadb_address *)current, ignore_nss); 2512 break; 2513 case SADB_X_EXT_ADDRESS_INNER_DST: 2514 print_address(file, dgettext(TEXT_DOMAIN, "IND: "), 2515 (struct sadb_address *)current, ignore_nss); 2516 break; 2517 case SADB_EXT_KEY_AUTH: 2518 print_key(file, dgettext(TEXT_DOMAIN, 2519 "AKY: "), (struct sadb_key *)current); 2520 break; 2521 case SADB_EXT_KEY_ENCRYPT: 2522 print_key(file, dgettext(TEXT_DOMAIN, 2523 "EKY: "), (struct sadb_key *)current); 2524 break; 2525 case SADB_EXT_IDENTITY_SRC: 2526 print_ident(file, dgettext(TEXT_DOMAIN, "SID: "), 2527 (struct sadb_ident *)current); 2528 break; 2529 case SADB_EXT_IDENTITY_DST: 2530 print_ident(file, dgettext(TEXT_DOMAIN, "DID: "), 2531 (struct sadb_ident *)current); 2532 break; 2533 case SADB_EXT_SENSITIVITY: 2534 print_sens(file, dgettext(TEXT_DOMAIN, "SNS: "), 2535 (struct sadb_sens *)current, ignore_nss); 2536 break; 2537 case SADB_EXT_PROPOSAL: 2538 print_prop(file, dgettext(TEXT_DOMAIN, "PRP: "), 2539 (struct sadb_prop *)current); 2540 break; 2541 case SADB_EXT_SUPPORTED_AUTH: 2542 print_supp(file, dgettext(TEXT_DOMAIN, "SUA: "), 2543 (struct sadb_supported *)current); 2544 break; 2545 case SADB_EXT_SUPPORTED_ENCRYPT: 2546 print_supp(file, dgettext(TEXT_DOMAIN, "SUE: "), 2547 (struct sadb_supported *)current); 2548 break; 2549 case SADB_EXT_SPIRANGE: 2550 print_spirange(file, dgettext(TEXT_DOMAIN, "SPR: "), 2551 (struct sadb_spirange *)current); 2552 break; 2553 case SADB_X_EXT_EPROP: 2554 print_eprop(file, dgettext(TEXT_DOMAIN, "EPR: "), 2555 (struct sadb_prop *)current); 2556 break; 2557 case SADB_X_EXT_KM_COOKIE: 2558 print_kmc(file, dgettext(TEXT_DOMAIN, "KMC: "), 2559 (struct sadb_x_kmc *)current); 2560 break; 2561 case SADB_X_EXT_ADDRESS_NATT_REM: 2562 print_address(file, dgettext(TEXT_DOMAIN, "NRM: "), 2563 (struct sadb_address *)current, ignore_nss); 2564 break; 2565 case SADB_X_EXT_ADDRESS_NATT_LOC: 2566 print_address(file, dgettext(TEXT_DOMAIN, "NLC: "), 2567 (struct sadb_address *)current, ignore_nss); 2568 break; 2569 case SADB_X_EXT_PAIR: 2570 print_pair(file, dgettext(TEXT_DOMAIN, "OTH: "), 2571 (struct sadb_x_pair *)current); 2572 break; 2573 case SADB_X_EXT_OUTER_SENS: 2574 print_sens(file, dgettext(TEXT_DOMAIN, "OSN: "), 2575 (struct sadb_sens *)current, ignore_nss); 2576 break; 2577 case SADB_X_EXT_REPLAY_VALUE: 2578 (void) print_replay(file, dgettext(TEXT_DOMAIN, 2579 "RPL: "), (sadb_x_replay_ctr_t *)current); 2580 break; 2581 default: 2582 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2583 "UNK: Unknown ext. %d, len %d.\n"), 2584 ext->sadb_ext_type, lenbytes); 2585 for (i = 0; i < ext->sadb_ext_len; i++) 2586 (void) fprintf(file, dgettext(TEXT_DOMAIN, 2587 "UNK: 0x%" PRIx64 "\n"), 2588 ((uint64_t *)ext)[i]); 2589 break; 2590 } 2591 current += (lenbytes == 0) ? 2592 SADB_8TO64(sizeof (struct sadb_ext)) : ext->sadb_ext_len; 2593 } 2594 /* 2595 * Print lifetimes NOW. 2596 */ 2597 if (currentlt != NULL || hardlt != NULL || softlt != NULL || 2598 idlelt != NULL) 2599 print_lifetimes(file, wallclock, currentlt, hardlt, 2600 softlt, idlelt, vflag); 2601 2602 if (current - buffer != samsg->sadb_msg_len) { 2603 warnxfp(EFD(file), dgettext(TEXT_DOMAIN, 2604 "WARNING: insufficient buffer space or corrupt message.")); 2605 } 2606 2607 (void) fflush(file); /* Make sure our message is out there. */ 2608 } 2609 2610 /* 2611 * save_XXX functions are used when "saving" the SA tables to either a 2612 * file or standard output. They use the dump_XXX functions where needed, 2613 * but mostly they use the rparseXXX functions. 2614 */ 2615 2616 /* 2617 * Print save information for a lifetime extension. 2618 * 2619 * NOTE : It saves the lifetime in absolute terms. For example, if you 2620 * had a hard_usetime of 60 seconds, you'll save it as 60 seconds, even though 2621 * there may have been 59 seconds burned off the clock. 2622 */ 2623 boolean_t 2624 save_lifetime(struct sadb_lifetime *lifetime, FILE *ofile) 2625 { 2626 char *prefix; 2627 2628 switch (lifetime->sadb_lifetime_exttype) { 2629 case SADB_EXT_LIFETIME_HARD: 2630 prefix = "hard"; 2631 break; 2632 case SADB_EXT_LIFETIME_SOFT: 2633 prefix = "soft"; 2634 break; 2635 case SADB_X_EXT_LIFETIME_IDLE: 2636 prefix = "idle"; 2637 break; 2638 } 2639 2640 if (putc('\t', ofile) == EOF) 2641 return (B_FALSE); 2642 2643 if (lifetime->sadb_lifetime_allocations != 0 && fprintf(ofile, 2644 "%s_alloc %u ", prefix, lifetime->sadb_lifetime_allocations) < 0) 2645 return (B_FALSE); 2646 2647 if (lifetime->sadb_lifetime_bytes != 0 && fprintf(ofile, 2648 "%s_bytes %" PRIu64 " ", prefix, lifetime->sadb_lifetime_bytes) < 0) 2649 return (B_FALSE); 2650 2651 if (lifetime->sadb_lifetime_addtime != 0 && fprintf(ofile, 2652 "%s_addtime %" PRIu64 " ", prefix, 2653 lifetime->sadb_lifetime_addtime) < 0) 2654 return (B_FALSE); 2655 2656 if (lifetime->sadb_lifetime_usetime != 0 && fprintf(ofile, 2657 "%s_usetime %" PRIu64 " ", prefix, 2658 lifetime->sadb_lifetime_usetime) < 0) 2659 return (B_FALSE); 2660 2661 return (B_TRUE); 2662 } 2663 2664 /* 2665 * Print save information for an address extension. 2666 */ 2667 boolean_t 2668 save_address(struct sadb_address *addr, FILE *ofile) 2669 { 2670 char *printable_addr, buf[INET6_ADDRSTRLEN]; 2671 const char *prefix, *pprefix; 2672 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)(addr + 1); 2673 struct sockaddr_in *sin = (struct sockaddr_in *)sin6; 2674 int af = sin->sin_family; 2675 2676 /* 2677 * Address-family reality check. 2678 */ 2679 if (af != AF_INET6 && af != AF_INET) 2680 return (B_FALSE); 2681 2682 switch (addr->sadb_address_exttype) { 2683 case SADB_EXT_ADDRESS_SRC: 2684 prefix = "src"; 2685 pprefix = "sport"; 2686 break; 2687 case SADB_X_EXT_ADDRESS_INNER_SRC: 2688 prefix = "isrc"; 2689 pprefix = "isport"; 2690 break; 2691 case SADB_EXT_ADDRESS_DST: 2692 prefix = "dst"; 2693 pprefix = "dport"; 2694 break; 2695 case SADB_X_EXT_ADDRESS_INNER_DST: 2696 prefix = "idst"; 2697 pprefix = "idport"; 2698 break; 2699 case SADB_X_EXT_ADDRESS_NATT_LOC: 2700 prefix = "nat_loc "; 2701 pprefix = "nat_lport"; 2702 break; 2703 case SADB_X_EXT_ADDRESS_NATT_REM: 2704 prefix = "nat_rem "; 2705 pprefix = "nat_rport"; 2706 break; 2707 } 2708 2709 if (fprintf(ofile, " %s ", prefix) < 0) 2710 return (B_FALSE); 2711 2712 /* 2713 * Do not do address-to-name translation, given that we live in 2714 * an age of names that explode into many addresses. 2715 */ 2716 printable_addr = (char *)inet_ntop(af, 2717 (af == AF_INET) ? (char *)&sin->sin_addr : (char *)&sin6->sin6_addr, 2718 buf, sizeof (buf)); 2719 if (printable_addr == NULL) 2720 printable_addr = "Invalid IP address."; 2721 if (fprintf(ofile, "%s", printable_addr) < 0) 2722 return (B_FALSE); 2723 if (addr->sadb_address_prefixlen != 0 && 2724 !((addr->sadb_address_prefixlen == 32 && af == AF_INET) || 2725 (addr->sadb_address_prefixlen == 128 && af == AF_INET6))) { 2726 if (fprintf(ofile, "/%d", addr->sadb_address_prefixlen) < 0) 2727 return (B_FALSE); 2728 } 2729 2730 /* 2731 * The port is in the same position for struct sockaddr_in and 2732 * struct sockaddr_in6. We exploit that property here. 2733 */ 2734 if ((pprefix != NULL) && (sin->sin_port != 0)) 2735 (void) fprintf(ofile, " %s %d", pprefix, ntohs(sin->sin_port)); 2736 2737 return (B_TRUE); 2738 } 2739 2740 /* 2741 * Print save information for a key extension. Returns whether writing 2742 * to the specified output file was successful or not. 2743 */ 2744 boolean_t 2745 save_key(struct sadb_key *key, FILE *ofile) 2746 { 2747 char *prefix; 2748 2749 if (putc('\t', ofile) == EOF) 2750 return (B_FALSE); 2751 2752 prefix = (key->sadb_key_exttype == SADB_EXT_KEY_AUTH) ? "auth" : "encr"; 2753 2754 if (fprintf(ofile, "%skey ", prefix) < 0) 2755 return (B_FALSE); 2756 2757 if (dump_key((uint8_t *)(key + 1), key->sadb_key_bits, 2758 key->sadb_key_reserved, ofile, B_FALSE) == -1) 2759 return (B_FALSE); 2760 2761 return (B_TRUE); 2762 } 2763 2764 /* 2765 * Print save information for an identity extension. 2766 */ 2767 boolean_t 2768 save_ident(struct sadb_ident *ident, FILE *ofile) 2769 { 2770 char *prefix; 2771 2772 if (putc('\t', ofile) == EOF) 2773 return (B_FALSE); 2774 2775 prefix = (ident->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC) ? "src" : 2776 "dst"; 2777 2778 if (fprintf(ofile, "%sidtype %s ", prefix, 2779 rparseidtype(ident->sadb_ident_type)) < 0) 2780 return (B_FALSE); 2781 2782 if (ident->sadb_ident_type == SADB_X_IDENTTYPE_DN || 2783 ident->sadb_ident_type == SADB_X_IDENTTYPE_GN) { 2784 if (fprintf(ofile, dgettext(TEXT_DOMAIN, 2785 "<can-not-print>")) < 0) 2786 return (B_FALSE); 2787 } else { 2788 if (fprintf(ofile, "%s", (char *)(ident + 1)) < 0) 2789 return (B_FALSE); 2790 } 2791 2792 return (B_TRUE); 2793 } 2794 2795 boolean_t 2796 save_sens(struct sadb_sens *sens, FILE *ofile) 2797 { 2798 char *prefix; 2799 char *hlabel; 2800 bslabel_t sl; 2801 2802 if (putc('\t', ofile) == EOF) 2803 return (B_FALSE); 2804 2805 if (sens->sadb_sens_exttype == SADB_EXT_SENSITIVITY) 2806 prefix = "label"; 2807 else if ((sens->sadb_x_sens_flags & SADB_X_SENS_IMPLICIT) == 0) 2808 prefix = "outer-label"; 2809 else 2810 prefix = "implicit-label"; 2811 2812 ipsec_convert_sens_to_bslabel(sens, &sl); 2813 ipsec_convert_bslabel_to_hex(&sl, &hlabel); 2814 2815 if (fprintf(ofile, "%s %s ", prefix, hlabel) < 0) { 2816 free(hlabel); 2817 return (B_FALSE); 2818 } 2819 free(hlabel); 2820 2821 return (B_TRUE); 2822 } 2823 2824 /* 2825 * "Save" a security association to an output file. 2826 * 2827 * NOTE the lack of calls to dgettext() because I'm outputting parseable stuff. 2828 * ALSO NOTE that if you change keywords (see parsecmd()), you'll have to 2829 * change them here as well. 2830 */ 2831 void 2832 save_assoc(uint64_t *buffer, FILE *ofile) 2833 { 2834 int terrno; 2835 boolean_t seen_proto = B_FALSE, seen_iproto = B_FALSE; 2836 uint64_t *current; 2837 struct sadb_address *addr; 2838 struct sadb_x_replay_ctr *repl; 2839 struct sadb_msg *samsg = (struct sadb_msg *)buffer; 2840 struct sadb_ext *ext; 2841 2842 #define tidyup() \ 2843 terrno = errno; (void) fclose(ofile); errno = terrno; \ 2844 interactive = B_FALSE 2845 2846 #define savenl() if (fputs(" \\\n", ofile) == EOF) \ 2847 { bail(dgettext(TEXT_DOMAIN, "savenl")); } 2848 2849 if (fputs("# begin assoc\n", ofile) == EOF) 2850 bail(dgettext(TEXT_DOMAIN, 2851 "save_assoc: Opening comment of SA")); 2852 if (fprintf(ofile, "add %s ", rparsesatype(samsg->sadb_msg_satype)) < 0) 2853 bail(dgettext(TEXT_DOMAIN, "save_assoc: First line of SA")); 2854 savenl(); 2855 2856 current = (uint64_t *)(samsg + 1); 2857 while (current - buffer < samsg->sadb_msg_len) { 2858 struct sadb_sa *assoc; 2859 2860 ext = (struct sadb_ext *)current; 2861 addr = (struct sadb_address *)ext; /* Just in case... */ 2862 switch (ext->sadb_ext_type) { 2863 case SADB_EXT_SA: 2864 assoc = (struct sadb_sa *)ext; 2865 if (assoc->sadb_sa_state != SADB_SASTATE_MATURE) { 2866 if (fprintf(ofile, "# WARNING: SA was dying " 2867 "or dead.\n") < 0) { 2868 tidyup(); 2869 bail(dgettext(TEXT_DOMAIN, 2870 "save_assoc: fprintf not mature")); 2871 } 2872 } 2873 if (fprintf(ofile, " spi 0x%x ", 2874 ntohl(assoc->sadb_sa_spi)) < 0) { 2875 tidyup(); 2876 bail(dgettext(TEXT_DOMAIN, 2877 "save_assoc: fprintf spi")); 2878 } 2879 if (assoc->sadb_sa_encrypt != SADB_EALG_NONE) { 2880 if (fprintf(ofile, "encr_alg %s ", 2881 rparsealg(assoc->sadb_sa_encrypt, 2882 IPSEC_PROTO_ESP)) < 0) { 2883 tidyup(); 2884 bail(dgettext(TEXT_DOMAIN, 2885 "save_assoc: fprintf encrypt")); 2886 } 2887 } 2888 if (assoc->sadb_sa_auth != SADB_AALG_NONE) { 2889 if (fprintf(ofile, "auth_alg %s ", 2890 rparsealg(assoc->sadb_sa_auth, 2891 IPSEC_PROTO_AH)) < 0) { 2892 tidyup(); 2893 bail(dgettext(TEXT_DOMAIN, 2894 "save_assoc: fprintf auth")); 2895 } 2896 } 2897 if (fprintf(ofile, "replay %d ", 2898 assoc->sadb_sa_replay) < 0) { 2899 tidyup(); 2900 bail(dgettext(TEXT_DOMAIN, 2901 "save_assoc: fprintf replay")); 2902 } 2903 if (assoc->sadb_sa_flags & (SADB_X_SAFLAGS_NATT_LOC | 2904 SADB_X_SAFLAGS_NATT_REM)) { 2905 if (fprintf(ofile, "encap udp") < 0) { 2906 tidyup(); 2907 bail(dgettext(TEXT_DOMAIN, 2908 "save_assoc: fprintf encap")); 2909 } 2910 } 2911 savenl(); 2912 break; 2913 case SADB_EXT_LIFETIME_HARD: 2914 case SADB_EXT_LIFETIME_SOFT: 2915 case SADB_X_EXT_LIFETIME_IDLE: 2916 if (!save_lifetime((struct sadb_lifetime *)ext, 2917 ofile)) { 2918 tidyup(); 2919 bail(dgettext(TEXT_DOMAIN, "save_lifetime")); 2920 } 2921 savenl(); 2922 break; 2923 case SADB_X_EXT_ADDRESS_INNER_SRC: 2924 case SADB_X_EXT_ADDRESS_INNER_DST: 2925 if (!seen_iproto && addr->sadb_address_proto) { 2926 (void) fprintf(ofile, " iproto %d", 2927 addr->sadb_address_proto); 2928 savenl(); 2929 seen_iproto = B_TRUE; 2930 } 2931 goto skip_srcdst; /* Hack to avoid cases below... */ 2932 /* FALLTHRU */ 2933 case SADB_EXT_ADDRESS_SRC: 2934 case SADB_EXT_ADDRESS_DST: 2935 if (!seen_proto && addr->sadb_address_proto) { 2936 (void) fprintf(ofile, " proto %d", 2937 addr->sadb_address_proto); 2938 savenl(); 2939 seen_proto = B_TRUE; 2940 } 2941 /* FALLTHRU */ 2942 case SADB_X_EXT_ADDRESS_NATT_REM: 2943 case SADB_X_EXT_ADDRESS_NATT_LOC: 2944 skip_srcdst: 2945 if (!save_address(addr, ofile)) { 2946 tidyup(); 2947 bail(dgettext(TEXT_DOMAIN, "save_address")); 2948 } 2949 savenl(); 2950 break; 2951 case SADB_EXT_KEY_AUTH: 2952 case SADB_EXT_KEY_ENCRYPT: 2953 if (!save_key((struct sadb_key *)ext, ofile)) { 2954 tidyup(); 2955 bail(dgettext(TEXT_DOMAIN, "save_address")); 2956 } 2957 savenl(); 2958 break; 2959 case SADB_EXT_IDENTITY_SRC: 2960 case SADB_EXT_IDENTITY_DST: 2961 if (!save_ident((struct sadb_ident *)ext, ofile)) { 2962 tidyup(); 2963 bail(dgettext(TEXT_DOMAIN, "save_address")); 2964 } 2965 savenl(); 2966 break; 2967 case SADB_X_EXT_REPLAY_VALUE: 2968 repl = (sadb_x_replay_ctr_t *)ext; 2969 if ((repl->sadb_x_rc_replay32 == 0) && 2970 (repl->sadb_x_rc_replay64 == 0)) { 2971 tidyup(); 2972 bail(dgettext(TEXT_DOMAIN, "Replay Value")); 2973 } 2974 if (fprintf(ofile, "replay_value %" PRIu64 "", 2975 (repl->sadb_x_rc_replay32 == 0 ? 2976 repl->sadb_x_rc_replay64 : 2977 repl->sadb_x_rc_replay32)) < 0) { 2978 tidyup(); 2979 bail(dgettext(TEXT_DOMAIN, 2980 "save_assoc: fprintf replay value")); 2981 } 2982 savenl(); 2983 break; 2984 case SADB_EXT_SENSITIVITY: 2985 case SADB_X_EXT_OUTER_SENS: 2986 if (!save_sens((struct sadb_sens *)ext, ofile)) { 2987 tidyup(); 2988 bail(dgettext(TEXT_DOMAIN, "save_sens")); 2989 } 2990 savenl(); 2991 break; 2992 default: 2993 /* Skip over irrelevant extensions. */ 2994 break; 2995 } 2996 current += ext->sadb_ext_len; 2997 } 2998 2999 if (fputs(dgettext(TEXT_DOMAIN, "\n# end assoc\n\n"), ofile) == EOF) { 3000 tidyup(); 3001 bail(dgettext(TEXT_DOMAIN, "save_assoc: last fputs")); 3002 } 3003 } 3004 3005 /* 3006 * Open the output file for the "save" command. 3007 */ 3008 FILE * 3009 opensavefile(char *filename) 3010 { 3011 int fd; 3012 FILE *retval; 3013 struct stat buf; 3014 3015 /* 3016 * If the user specifies "-" or doesn't give a filename, then 3017 * dump to stdout. Make sure to document the dangers of files 3018 * that are NFS, directing your output to strange places, etc. 3019 */ 3020 if (filename == NULL || strcmp("-", filename) == 0) 3021 return (stdout); 3022 3023 /* 3024 * open the file with the create bits set. Since I check for 3025 * real UID == root in main(), I won't worry about the ownership 3026 * problem. 3027 */ 3028 fd = open(filename, O_WRONLY | O_EXCL | O_CREAT | O_TRUNC, S_IRUSR); 3029 if (fd == -1) { 3030 if (errno != EEXIST) 3031 bail_msg("%s %s: %s", filename, dgettext(TEXT_DOMAIN, 3032 "open error"), 3033 strerror(errno)); 3034 fd = open(filename, O_WRONLY | O_TRUNC, 0); 3035 if (fd == -1) 3036 bail_msg("%s %s: %s", filename, dgettext(TEXT_DOMAIN, 3037 "open error"), strerror(errno)); 3038 if (fstat(fd, &buf) == -1) { 3039 (void) close(fd); 3040 bail_msg("%s fstat: %s", filename, strerror(errno)); 3041 } 3042 if (S_ISREG(buf.st_mode) && 3043 ((buf.st_mode & S_IAMB) != S_IRUSR)) { 3044 warnx(dgettext(TEXT_DOMAIN, 3045 "WARNING: Save file already exists with " 3046 "permission %o."), buf.st_mode & S_IAMB); 3047 warnx(dgettext(TEXT_DOMAIN, 3048 "Normal users may be able to read IPsec " 3049 "keying material.")); 3050 } 3051 } 3052 3053 /* Okay, we have an FD. Assign it to a stdio FILE pointer. */ 3054 retval = fdopen(fd, "w"); 3055 if (retval == NULL) { 3056 (void) close(fd); 3057 bail_msg("%s %s: %s", filename, dgettext(TEXT_DOMAIN, 3058 "fdopen error"), strerror(errno)); 3059 } 3060 return (retval); 3061 } 3062 3063 const char * 3064 do_inet_ntop(const void *addr, char *cp, size_t size) 3065 { 3066 boolean_t isv4; 3067 struct in6_addr *inaddr6 = (struct in6_addr *)addr; 3068 struct in_addr inaddr; 3069 3070 if ((isv4 = IN6_IS_ADDR_V4MAPPED(inaddr6)) == B_TRUE) { 3071 IN6_V4MAPPED_TO_INADDR(inaddr6, &inaddr); 3072 } 3073 3074 return (inet_ntop(isv4 ? AF_INET : AF_INET6, 3075 isv4 ? (void *)&inaddr : inaddr6, cp, size)); 3076 } 3077 3078 char numprint[NBUF_SIZE]; 3079 3080 /* 3081 * Parse and reverse parse a specific SA type (AH, ESP, etc.). 3082 */ 3083 static struct typetable { 3084 char *type; 3085 int token; 3086 } type_table[] = { 3087 {"all", SADB_SATYPE_UNSPEC}, 3088 {"ah", SADB_SATYPE_AH}, 3089 {"esp", SADB_SATYPE_ESP}, 3090 /* PF_KEY NOTE: More to come if net/pfkeyv2.h gets updated. */ 3091 {NULL, 0} /* Token value is irrelevant for this entry. */ 3092 }; 3093 3094 char * 3095 rparsesatype(int type) 3096 { 3097 struct typetable *tt = type_table; 3098 3099 while (tt->type != NULL && type != tt->token) 3100 tt++; 3101 3102 if (tt->type == NULL) { 3103 (void) snprintf(numprint, NBUF_SIZE, "%d", type); 3104 } else { 3105 return (tt->type); 3106 } 3107 3108 return (numprint); 3109 } 3110 3111 3112 /* 3113 * Return a string containing the name of the specified numerical algorithm 3114 * identifier. 3115 */ 3116 char * 3117 rparsealg(uint8_t alg, int proto_num) 3118 { 3119 static struct ipsecalgent *holder = NULL; /* we're single-threaded */ 3120 3121 if (holder != NULL) 3122 freeipsecalgent(holder); 3123 3124 holder = getipsecalgbynum(alg, proto_num, NULL); 3125 if (holder == NULL) { 3126 (void) snprintf(numprint, NBUF_SIZE, "%d", alg); 3127 return (numprint); 3128 } 3129 3130 return (*(holder->a_names)); 3131 } 3132 3133 /* 3134 * Parse and reverse parse out a source/destination ID type. 3135 */ 3136 static struct idtypes { 3137 char *idtype; 3138 uint8_t retval; 3139 } idtypes[] = { 3140 {"prefix", SADB_IDENTTYPE_PREFIX}, 3141 {"fqdn", SADB_IDENTTYPE_FQDN}, 3142 {"domain", SADB_IDENTTYPE_FQDN}, 3143 {"domainname", SADB_IDENTTYPE_FQDN}, 3144 {"user_fqdn", SADB_IDENTTYPE_USER_FQDN}, 3145 {"mailbox", SADB_IDENTTYPE_USER_FQDN}, 3146 {"der_dn", SADB_X_IDENTTYPE_DN}, 3147 {"der_gn", SADB_X_IDENTTYPE_GN}, 3148 {NULL, 0} 3149 }; 3150 3151 char * 3152 rparseidtype(uint16_t type) 3153 { 3154 struct idtypes *idp; 3155 3156 for (idp = idtypes; idp->idtype != NULL; idp++) { 3157 if (type == idp->retval) 3158 return (idp->idtype); 3159 } 3160 3161 (void) snprintf(numprint, NBUF_SIZE, "%d", type); 3162 return (numprint); 3163 } 3164 3165 /* 3166 * This is a general purpose exit function, calling functions can specify an 3167 * error type. If the command calling this function was started by smf(5) the 3168 * error type could be used as a hint to the restarter. In the future this 3169 * function could be used to do something more intelligent with a process that 3170 * encounters an error. If exit() is called with an error code other than those 3171 * defined by smf(5), the program will just get restarted. Unless restarting 3172 * is likely to resolve the error condition, its probably sensible to just 3173 * log the error and keep running. 3174 * 3175 * The SERVICE_* exit_types mean nothing if the command was run from the 3176 * command line, just exit(). There are two special cases: 3177 * 3178 * SERVICE_DEGRADE - Not implemented in smf(5), one day it could hint that 3179 * the service is not running as well is it could. For 3180 * now, don't do anything, just record the error. 3181 * DEBUG_FATAL - Something happened, if the command was being run in debug 3182 * mode, exit() as you really want to know something happened, 3183 * otherwise just keep running. This is ignored when running 3184 * under smf(5). 3185 * 3186 * The function will handle an optional variable args error message, this 3187 * will be written to the error stream, typically a log file or stderr. 3188 */ 3189 void 3190 ipsecutil_exit(exit_type_t type, char *fmri, FILE *fp, const char *fmt, ...) 3191 { 3192 int exit_status; 3193 va_list args; 3194 3195 if (fp == NULL) 3196 fp = stderr; 3197 if (fmt != NULL) { 3198 va_start(args, fmt); 3199 vwarnxfp(fp, fmt, args); 3200 va_end(args); 3201 } 3202 3203 if (fmri == NULL) { 3204 /* Command being run directly from a shell. */ 3205 switch (type) { 3206 case SERVICE_EXIT_OK: 3207 exit_status = 0; 3208 break; 3209 case SERVICE_DEGRADE: 3210 return; 3211 break; 3212 case SERVICE_BADPERM: 3213 case SERVICE_BADCONF: 3214 case SERVICE_MAINTAIN: 3215 case SERVICE_DISABLE: 3216 case SERVICE_FATAL: 3217 case SERVICE_RESTART: 3218 case DEBUG_FATAL: 3219 warnxfp(fp, "Fatal error - exiting."); 3220 exit_status = 1; 3221 break; 3222 } 3223 } else { 3224 /* Command being run as a smf(5) method. */ 3225 switch (type) { 3226 case SERVICE_EXIT_OK: 3227 exit_status = SMF_EXIT_OK; 3228 break; 3229 case SERVICE_DEGRADE: /* Not implemented yet. */ 3230 case DEBUG_FATAL: 3231 /* Keep running, don't exit(). */ 3232 return; 3233 break; 3234 case SERVICE_BADPERM: 3235 warnxfp(fp, dgettext(TEXT_DOMAIN, 3236 "Permission error with %s."), fmri); 3237 exit_status = SMF_EXIT_ERR_PERM; 3238 break; 3239 case SERVICE_BADCONF: 3240 warnxfp(fp, dgettext(TEXT_DOMAIN, 3241 "Bad configuration of service %s."), fmri); 3242 exit_status = SMF_EXIT_ERR_FATAL; 3243 break; 3244 case SERVICE_MAINTAIN: 3245 warnxfp(fp, dgettext(TEXT_DOMAIN, 3246 "Service %s needs maintenance."), fmri); 3247 exit_status = SMF_EXIT_ERR_FATAL; 3248 break; 3249 case SERVICE_DISABLE: 3250 exit_status = SMF_EXIT_ERR_FATAL; 3251 break; 3252 case SERVICE_FATAL: 3253 warnxfp(fp, dgettext(TEXT_DOMAIN, 3254 "Service %s fatal error."), fmri); 3255 exit_status = SMF_EXIT_ERR_FATAL; 3256 break; 3257 case SERVICE_RESTART: 3258 exit_status = 1; 3259 break; 3260 } 3261 } 3262 (void) fflush(fp); 3263 (void) fclose(fp); 3264 exit(exit_status); 3265 } 3266