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