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