xref: /illumos-gate/usr/src/lib/libipsecutil/common/ipsec_util.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <sys/sysconf.h>
37 #include <strings.h>
38 #include <ctype.h>
39 #include <errno.h>
40 #include <sys/socket.h>
41 #include <netdb.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <net/pfkeyv2.h>
45 #include <net/pfpolicy.h>
46 #include <libintl.h>
47 #include <setjmp.h>
48 #include <libgen.h>
49 
50 #include "ipsec_util.h"
51 #include "ikedoor.h"
52 
53 /*
54  * This file contains support functions that are shared by the ipsec
55  * utilities including ipseckey(1m) and ikeadm(1m).
56  */
57 
58 /* Set standard default/initial values for globals... */
59 boolean_t pflag = B_FALSE;	/* paranoid w.r.t. printing keying material */
60 boolean_t nflag = B_FALSE;	/* avoid nameservice? */
61 boolean_t interactive = B_FALSE;	/* util not running on cmdline */
62 boolean_t readfile = B_FALSE;	/* cmds are being read from a file */
63 uint_t	lineno = 0;		/* track location if reading cmds from file */
64 jmp_buf	env;		/* for error recovery in interactive/readfile modes */
65 
66 /*
67  * Print errno and exit if cmdline or readfile, reset state if interactive
68  */
69 void
70 bail(char *what)
71 {
72 	if (errno != 0)
73 		warn(what);
74 	else
75 		warnx(gettext("Error: %s"), what);
76 	if (readfile) {
77 		warnx(gettext("System error on line %u."), lineno);
78 	}
79 	if (interactive && !readfile)
80 		longjmp(env, 2);
81 	exit(1);
82 }
83 
84 /*
85  * Print caller-supplied variable-arg error msg, then exit if cmdline or
86  * readfile, or reset state if interactive.
87  */
88 /*PRINTFLIKE1*/
89 void
90 bail_msg(char *fmt, ...)
91 {
92 	va_list	ap;
93 	char	msgbuf[BUFSIZ];
94 
95 	va_start(ap, fmt);
96 	(void) vsnprintf(msgbuf, BUFSIZ, fmt, ap);
97 	va_end(ap);
98 	if (readfile)
99 		warnx(gettext("ERROR on line %u:\n%s\n"), lineno,  msgbuf);
100 	else
101 		warnx(gettext("ERROR: %s\n"), msgbuf);
102 
103 	if (interactive && !readfile)
104 		longjmp(env, 1);
105 
106 	exit(1);
107 }
108 
109 
110 /*
111  * dump_XXX functions produce ASCII output from various structures.
112  *
113  * Because certain errors need to do this to stderr, dump_XXX functions
114  * take a FILE pointer.
115  *
116  * If an error occured while writing to the specified file, these
117  * functions return -1, zero otherwise.
118  */
119 
120 int
121 dump_sockaddr(struct sockaddr *sa, boolean_t addr_only, FILE *where)
122 {
123 	struct sockaddr_in	*sin;
124 	struct sockaddr_in6	*sin6;
125 	char			*printable_addr, *protocol;
126 	uint8_t			*addrptr;
127 	char			storage[INET6_ADDRSTRLEN];
128 	uint16_t		port;
129 	boolean_t		unspec;
130 	struct hostent		*hp;
131 	int			getipnode_errno, addrlen;
132 
133 	switch (sa->sa_family) {
134 	case AF_INET:
135 		/* LINTED E_BAD_PTR_CAST_ALIGN */
136 		sin = (struct sockaddr_in *)sa;
137 		addrptr = (uint8_t *)&sin->sin_addr;
138 		port = sin->sin_port;
139 		protocol = "AF_INET";
140 		unspec = (sin->sin_addr.s_addr == 0);
141 		addrlen = sizeof (sin->sin_addr);
142 		break;
143 	case AF_INET6:
144 		/* LINTED E_BAD_PTR_CAST_ALIGN */
145 		sin6 = (struct sockaddr_in6 *)sa;
146 		addrptr = (uint8_t *)&sin6->sin6_addr;
147 		port = sin6->sin6_port;
148 		protocol = "AF_INET6";
149 		unspec = IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr);
150 		addrlen = sizeof (sin6->sin6_addr);
151 		break;
152 	default:
153 		return (0);
154 	}
155 
156 	if (inet_ntop(sa->sa_family, addrptr, storage, INET6_ADDRSTRLEN) ==
157 	    NULL) {
158 		printable_addr = gettext("<inet_ntop() failed>");
159 	} else {
160 		printable_addr = storage;
161 	}
162 	if (addr_only) {
163 		if (fprintf(where, "%s", printable_addr) < 0)
164 			return (-1);
165 	} else {
166 		if (fprintf(where, gettext("%s: port %d, %s"), protocol,
167 		    ntohs(port), printable_addr) < 0)
168 			return (-1);
169 		if (!nflag) {
170 			/*
171 			 * Do AF_independent reverse hostname lookup here.
172 			 */
173 			if (unspec) {
174 				if (fprintf(where,
175 				    gettext(" <unspecified>")) < 0)
176 					return (-1);
177 			} else {
178 				hp = getipnodebyaddr((char *)addrptr, addrlen,
179 				    sa->sa_family, &getipnode_errno);
180 				if (hp != NULL) {
181 					if (fprintf(where,
182 					    " (%s)", hp->h_name) < 0)
183 						return (-1);
184 					freehostent(hp);
185 				} else {
186 					if (fprintf(where,
187 					    gettext(" <unknown>")) < 0)
188 						return (-1);
189 				}
190 			}
191 		}
192 		if (fputs(".\n", where) == EOF)
193 			return (-1);
194 	}
195 	return (0);
196 }
197 
198 /*
199  * Dump a key and bitlen
200  */
201 int
202 dump_key(uint8_t *keyp, uint_t bitlen, FILE *where)
203 {
204 	int	numbytes;
205 
206 	numbytes = SADB_1TO8(bitlen);
207 	/* The & 0x7 is to check for leftover bits. */
208 	if ((bitlen & 0x7) != 0)
209 		numbytes++;
210 	while (numbytes-- != 0) {
211 		if (pflag) {
212 			/* Print no keys if paranoid */
213 			if (fprintf(where, "XX") < 0)
214 				return (-1);
215 		} else {
216 			if (fprintf(where, "%02x", *keyp++) < 0)
217 				return (-1);
218 		}
219 	}
220 	if (fprintf(where, "/%u", bitlen) < 0)
221 		return (-1);
222 	return (0);
223 }
224 
225 /*
226  * Print an authentication or encryption algorithm
227  */
228 static int
229 dump_generic_alg(uint8_t alg_num, int proto_num, FILE *where)
230 {
231 	struct ipsecalgent *alg;
232 
233 	alg = getipsecalgbynum(alg_num, proto_num, NULL);
234 	if (alg == NULL) {
235 		if (fprintf(where, gettext("<unknown %u>"), alg_num) < 0)
236 			return (-1);
237 		return (0);
238 	}
239 
240 	/*
241 	 * Special-case <none> for backward output compat.
242 	 * Assume that SADB_AALG_NONE == SADB_EALG_NONE.
243 	 */
244 	if (alg_num == SADB_AALG_NONE) {
245 		if (fputs(gettext("<none>"), where) == EOF)
246 			return (-1);
247 	} else {
248 		if (fputs(alg->a_names[0], where) == EOF)
249 			return (-1);
250 	}
251 
252 	freeipsecalgent(alg);
253 	return (0);
254 }
255 
256 int
257 dump_aalg(uint8_t aalg, FILE *where)
258 {
259 	return (dump_generic_alg(aalg, IPSEC_PROTO_AH, where));
260 }
261 
262 int
263 dump_ealg(uint8_t ealg, FILE *where)
264 {
265 	return (dump_generic_alg(ealg, IPSEC_PROTO_ESP, where));
266 }
267 
268 /*
269  * Print an SADB_IDENTTYPE string
270  *
271  * Also return TRUE if the actual ident may be printed, FALSE if not.
272  *
273  * If rc is not NULL, set its value to -1 if an error occured while writing
274  * to the specified file, zero otherwise.
275  */
276 boolean_t
277 dump_sadb_idtype(uint8_t idtype, FILE *where, int *rc)
278 {
279 	boolean_t canprint = B_TRUE;
280 	int rc_val = 0;
281 
282 	switch (idtype) {
283 	case SADB_IDENTTYPE_PREFIX:
284 		if (fputs(gettext("prefix"), where) == EOF)
285 			rc_val = -1;
286 		break;
287 	case SADB_IDENTTYPE_FQDN:
288 		if (fputs(gettext("FQDN"), where) == EOF)
289 			rc_val = -1;
290 		break;
291 	case SADB_IDENTTYPE_USER_FQDN:
292 		if (fputs(gettext("user-FQDN (mbox)"), where) == EOF)
293 			rc_val = -1;
294 		break;
295 	case SADB_X_IDENTTYPE_DN:
296 		if (fputs(gettext("ASN.1 DER Distinguished Name"),
297 		    where) == EOF)
298 			rc_val = -1;
299 		canprint = B_FALSE;
300 		break;
301 	case SADB_X_IDENTTYPE_GN:
302 		if (fputs(gettext("ASN.1 DER Generic Name"), where) == EOF)
303 			rc_val = -1;
304 		canprint = B_FALSE;
305 		break;
306 	case SADB_X_IDENTTYPE_KEY_ID:
307 		if (fputs(gettext("Generic key id"), where) == EOF)
308 			rc_val = -1;
309 		break;
310 	case SADB_X_IDENTTYPE_ADDR_RANGE:
311 		if (fputs(gettext("Address range"), where) == EOF)
312 			rc_val = -1;
313 		break;
314 	default:
315 		if (fprintf(where, gettext("<unknown %u>"), idtype) < 0)
316 			rc_val = -1;
317 		break;
318 	}
319 
320 	if (rc != NULL)
321 		*rc = rc_val;
322 
323 	return (canprint);
324 }
325 
326 /*
327  * Slice an argv/argc vector from an interactive line or a read-file line.
328  */
329 static int
330 create_argv(char *ibuf, int *newargc, char ***thisargv)
331 {
332 	unsigned int argvlen = START_ARG;
333 	char **current;
334 	boolean_t firstchar = B_TRUE;
335 	boolean_t inquotes = B_FALSE;
336 
337 	*thisargv = malloc(sizeof (char *) * argvlen);
338 	if ((*thisargv) == NULL)
339 		return (MEMORY_ALLOCATION);
340 	current = *thisargv;
341 	*current = NULL;
342 
343 	for (; *ibuf != '\0'; ibuf++) {
344 		if (isspace(*ibuf)) {
345 			if (inquotes) {
346 				continue;
347 			}
348 			if (*current != NULL) {
349 				*ibuf = '\0';
350 				current++;
351 				if (*thisargv + argvlen == current) {
352 					/* Regrow ***thisargv. */
353 					if (argvlen == TOO_MANY_ARGS) {
354 						free(*thisargv);
355 						return (TOO_MANY_TOKENS);
356 					}
357 					/* Double the allocation. */
358 					current = realloc(*thisargv,
359 					    sizeof (char *) * (argvlen << 1));
360 					if (current == NULL) {
361 						free(*thisargv);
362 						return (MEMORY_ALLOCATION);
363 					}
364 					*thisargv = current;
365 					current += argvlen;
366 					argvlen <<= 1;	/* Double the size. */
367 				}
368 				*current = NULL;
369 			}
370 		} else {
371 			if (firstchar) {
372 				firstchar = B_FALSE;
373 				if (*ibuf == COMMENT_CHAR) {
374 					free(*thisargv);
375 					return (COMMENT_LINE);
376 				}
377 			}
378 			if (*ibuf == QUOTE_CHAR) {
379 				if (inquotes) {
380 					inquotes = B_FALSE;
381 					*ibuf = '\0';
382 				} else {
383 					inquotes = B_TRUE;
384 				}
385 				continue;
386 			}
387 			if (*current == NULL) {
388 				*current = ibuf;
389 				(*newargc)++;
390 			}
391 		}
392 	}
393 
394 	/*
395 	 * Tricky corner case...
396 	 * I've parsed _exactly_ the amount of args as I have space.  It
397 	 * won't return NULL-terminated, and bad things will happen to
398 	 * the caller.
399 	 */
400 	if (argvlen == *newargc) {
401 		current = realloc(*thisargv, sizeof (char *) * (argvlen + 1));
402 		if (current == NULL) {
403 			free(*thisargv);
404 			return (MEMORY_ALLOCATION);
405 		}
406 		*thisargv = current;
407 		current[argvlen] = NULL;
408 	}
409 
410 	return (SUCCESS);
411 }
412 
413 /*
414  * Enter a mode where commands are read from a file.  Treat stdin special.
415  */
416 void
417 do_interactive(FILE *infile, char *promptstring, parse_cmdln_fn parseit)
418 {
419 	char		ibuf[IBUF_SIZE], holder[IBUF_SIZE];
420 	char		*hptr, **thisargv;
421 	int		thisargc;
422 	boolean_t	continue_in_progress = B_FALSE;
423 
424 	(void) setjmp(env);
425 
426 	interactive = B_TRUE;
427 	bzero(ibuf, IBUF_SIZE);
428 
429 	if (infile == stdin) {
430 		(void) printf("%s", promptstring);
431 		(void) fflush(stdout);
432 	} else {
433 		readfile = B_TRUE;
434 	}
435 
436 	while (fgets(ibuf, IBUF_SIZE, infile) != NULL) {
437 		if (readfile)
438 			lineno++;
439 		thisargc = 0;
440 		thisargv = NULL;
441 
442 		/*
443 		 * Check byte IBUF_SIZE - 2, because byte IBUF_SIZE - 1 will
444 		 * be null-terminated because of fgets().
445 		 */
446 		if (ibuf[IBUF_SIZE - 2] != '\0') {
447 			(void) fprintf(stderr,
448 			    gettext("Line %d too big.\n"), lineno);
449 			exit(1);
450 		}
451 
452 		if (!continue_in_progress) {
453 			/* Use -2 because of \n from fgets. */
454 			if (ibuf[strlen(ibuf) - 2] == CONT_CHAR) {
455 				/*
456 				 * Can use strcpy here, I've checked the
457 				 * length already.
458 				 */
459 				(void) strcpy(holder, ibuf);
460 				hptr = &(holder[strlen(holder)]);
461 
462 				/* Remove the CONT_CHAR from the string. */
463 				hptr[-2] = ' ';
464 
465 				continue_in_progress = B_TRUE;
466 				bzero(ibuf, IBUF_SIZE);
467 				continue;
468 			}
469 		} else {
470 			/* Handle continuations... */
471 			(void) strncpy(hptr, ibuf,
472 			    (size_t)(&(holder[IBUF_SIZE]) - hptr));
473 			if (holder[IBUF_SIZE - 1] != '\0') {
474 				(void) fprintf(stderr,
475 				    gettext("Command buffer overrun.\n"));
476 				exit(1);
477 			}
478 			/* Use - 2 because of \n from fgets. */
479 			if (hptr[strlen(hptr) - 2] == CONT_CHAR) {
480 				bzero(ibuf, IBUF_SIZE);
481 				hptr += strlen(hptr);
482 
483 				/* Remove the CONT_CHAR from the string. */
484 				hptr[-2] = ' ';
485 
486 				continue;
487 			} else {
488 				continue_in_progress = B_FALSE;
489 				/*
490 				 * I've already checked the length...
491 				 */
492 				(void) strcpy(ibuf, holder);
493 			}
494 		}
495 
496 		switch (create_argv(ibuf, &thisargc, &thisargv)) {
497 		case TOO_MANY_TOKENS:
498 			(void) fprintf(stderr,
499 			    gettext("Too many input tokens.\n"));
500 			exit(1);
501 			break;
502 		case MEMORY_ALLOCATION:
503 			(void) fprintf(stderr,
504 			    gettext("Memory allocation error.\n"));
505 			exit(1);
506 			break;
507 		case COMMENT_LINE:
508 			/* Comment line. */
509 			break;
510 		default:
511 			parseit(thisargc, thisargv);
512 			free(thisargv);
513 			if (infile == stdin) {
514 				(void) printf("%s", promptstring);
515 				(void) fflush(stdout);
516 			}
517 			break;
518 		}
519 		bzero(ibuf, IBUF_SIZE);
520 	}
521 	if (!readfile) {
522 		(void) putchar('\n');
523 		(void) fflush(stdout);
524 	}
525 	exit(0);
526 }
527 
528 /*
529  * Functions to parse strings that represent a debug or privilege level.
530  * These functions are copied from main.c and door.c in usr.lib/in.iked/common.
531  * If this file evolves into a common library that may be used by in.iked
532  * as well as the usr.sbin utilities, those duplicate functions should be
533  * deleted.
534  *
535  * A privilege level may be represented by a simple keyword, corresponding
536  * to one of the possible levels.  A debug level may be represented by a
537  * series of keywords, separated by '+' or '-', indicating categories to
538  * be added or removed from the set of categories in the debug level.
539  * For example, +all-op corresponds to level 0xfffffffb (all flags except
540  * for D_OP set); while p1+p2+pfkey corresponds to level 0x38.  Note that
541  * the leading '+' is implicit; the first keyword in the list must be for
542  * a category that is to be added.
543  *
544  * These parsing functions make use of a local version of strtok, strtok_d,
545  * which includes an additional parameter, char *delim.  This param is filled
546  * in with the character which ends the returned token.  In other words,
547  * this version of strtok, in addition to returning the token, also returns
548  * the single character delimiter from the original string which marked the
549  * end of the token.
550  */
551 static char *
552 strtok_d(char *string, const char *sepset, char *delim)
553 {
554 	static char	*lasts;
555 	char		*q, *r;
556 
557 	/* first or subsequent call */
558 	if (string == NULL)
559 		string = lasts;
560 
561 	if (string == 0)		/* return if no tokens remaining */
562 		return (NULL);
563 
564 	q = string + strspn(string, sepset);	/* skip leading separators */
565 
566 	if (*q == '\0')			/* return if no tokens remaining */
567 		return (NULL);
568 
569 	if ((r = strpbrk(q, sepset)) == NULL) {		/* move past token */
570 		lasts = 0;	/* indicate that this is last token */
571 	} else {
572 		*delim = *r;	/* save delimitor */
573 		*r = '\0';
574 		lasts = r + 1;
575 	}
576 	return (q);
577 }
578 
579 static keywdtab_t	privtab[] = {
580 	{ IKE_PRIV_MINIMUM,	"base" },
581 	{ IKE_PRIV_MODKEYS,	"modkeys" },
582 	{ IKE_PRIV_KEYMAT,	"keymat" },
583 	{ IKE_PRIV_MINIMUM,	"0" },
584 };
585 
586 int
587 privstr2num(char *str)
588 {
589 	keywdtab_t	*pp;
590 	char		*endp;
591 	int		 priv;
592 
593 	for (pp = privtab; pp < A_END(privtab); pp++) {
594 		if (strcasecmp(str, pp->kw_str) == 0)
595 			return (pp->kw_tag);
596 	}
597 
598 	priv = strtol(str, &endp, 0);
599 	if (*endp == '\0')
600 		return (priv);
601 
602 	return (-1);
603 }
604 
605 static keywdtab_t	dbgtab[] = {
606 	{ D_CERT,	"cert" },
607 	{ D_KEY,	"key" },
608 	{ D_OP,		"op" },
609 	{ D_P1,		"p1" },
610 	{ D_P1,		"phase1" },
611 	{ D_P2,		"p2" },
612 	{ D_P2,		"phase2" },
613 	{ D_PFKEY,	"pfkey" },
614 	{ D_POL,	"pol" },
615 	{ D_POL,	"policy" },
616 	{ D_PROP,	"prop" },
617 	{ D_DOOR,	"door" },
618 	{ D_CONFIG,	"config" },
619 	{ D_ALL,	"all" },
620 	{ 0,		"0" },
621 };
622 
623 int
624 dbgstr2num(char *str)
625 {
626 	keywdtab_t	*dp;
627 
628 	for (dp = dbgtab; dp < A_END(dbgtab); dp++) {
629 		if (strcasecmp(str, dp->kw_str) == 0)
630 			return (dp->kw_tag);
631 	}
632 	return (D_INVALID);
633 }
634 
635 int
636 parsedbgopts(char *optarg)
637 {
638 	char	*argp, *endp, op, nextop;
639 	int	mask = 0, new;
640 
641 	mask = strtol(optarg, &endp, 0);
642 	if (*endp == '\0')
643 		return (mask);
644 
645 	op = optarg[0];
646 	if (op != '-')
647 		op = '+';
648 	argp = strtok_d(optarg, "+-", &nextop);
649 	do {
650 		new = dbgstr2num(argp);
651 		if (new == D_INVALID) {
652 			/* we encountered an invalid keywd */
653 			return (new);
654 		}
655 		if (op == '+') {
656 			mask |= new;
657 		} else {
658 			mask &= ~new;
659 		}
660 		op = nextop;
661 	} while ((argp = strtok_d(NULL, "+-", &nextop)) != NULL);
662 
663 	return (mask);
664 }
665 
666 
667 /*
668  * functions to manipulate the kmcookie-label mapping file
669  */
670 
671 /*
672  * Open, lockf, fdopen the given file, returning a FILE * on success,
673  * or NULL on failure.
674  */
675 FILE *
676 kmc_open_and_lock(char *name)
677 {
678 	int	fd, rtnerr;
679 	FILE	*fp;
680 
681 	if ((fd = open(name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
682 		return (NULL);
683 	}
684 	if (lockf(fd, F_LOCK, 0) < 0) {
685 		return (NULL);
686 	}
687 	if ((fp = fdopen(fd, "a+")) == NULL) {
688 		return (NULL);
689 	}
690 	if (fseek(fp, 0, SEEK_SET) < 0) {
691 		/* save errno in case fclose changes it */
692 		rtnerr = errno;
693 		(void) fclose(fp);
694 		errno = rtnerr;
695 		return (NULL);
696 	}
697 	return (fp);
698 }
699 
700 /*
701  * Extract an integer cookie and string label from a line from the
702  * kmcookie-label file.  Return -1 on failure, 0 on success.
703  */
704 int
705 kmc_parse_line(char *line, int *cookie, char **label)
706 {
707 	char	*cookiestr;
708 
709 	*cookie = 0;
710 	*label = NULL;
711 
712 	cookiestr = strtok(line, " \t\n");
713 	if (cookiestr == NULL) {
714 		return (-1);
715 	}
716 
717 	/* Everything that follows, up to the newline, is the label. */
718 	*label = strtok(NULL, "\n");
719 	if (*label == NULL) {
720 		return (-1);
721 	}
722 
723 	*cookie = atoi(cookiestr);
724 	return (0);
725 }
726 
727 /*
728  * Insert a mapping into the file (if it's not already there), given the
729  * new label.  Return the assigned cookie, or -1 on error.
730  */
731 int
732 kmc_insert_mapping(char *label)
733 {
734 	FILE	*map;
735 	char	linebuf[MAXLINESIZE];
736 	char	*cur_label;
737 	int	max_cookie = 0, cur_cookie, rtn_cookie;
738 	int	rtnerr = 0;
739 	boolean_t	found = B_FALSE;
740 
741 	/* open and lock the file; will sleep until lock is available */
742 	if ((map = kmc_open_and_lock(KMCFILE)) == NULL) {
743 		/* kmc_open_and_lock() sets errno appropriately */
744 		return (-1);
745 	}
746 
747 	while (fgets(linebuf, sizeof (linebuf), map) != NULL) {
748 
749 		if (kmc_parse_line(linebuf, &cur_cookie, &cur_label) < 0) {
750 			rtnerr = EINVAL;
751 			goto error;
752 		}
753 
754 		if (cur_cookie > max_cookie)
755 			max_cookie = cur_cookie;
756 
757 		if ((!found) && (strcmp(cur_label, label) == 0)) {
758 			found = B_TRUE;
759 			rtn_cookie = cur_cookie;
760 		}
761 	}
762 
763 	if (!found) {
764 		rtn_cookie = ++max_cookie;
765 		if ((fprintf(map, "%u\t%s\n", rtn_cookie, label) < 0) ||
766 		    (fflush(map) < 0)) {
767 			rtnerr = errno;
768 			goto error;
769 		}
770 	}
771 	(void) fclose(map);
772 
773 	return (rtn_cookie);
774 
775 error:
776 	(void) fclose(map);
777 	errno = rtnerr;
778 	return (-1);
779 }
780 
781 /*
782  * Lookup the given cookie and return its corresponding label.  Return
783  * a pointer to the label on success, NULL on error (or if the label is
784  * not found).  Note that the returned label pointer points to a static
785  * string, so the label will be overwritten by a subsequent call to the
786  * function; the function is also not thread-safe as a result.
787  */
788 char *
789 kmc_lookup_by_cookie(int cookie)
790 {
791 	FILE		*map;
792 	static char	linebuf[MAXLINESIZE];
793 	char		*cur_label;
794 	int		cur_cookie;
795 
796 	if ((map = kmc_open_and_lock(KMCFILE)) == NULL) {
797 		return (NULL);
798 	}
799 
800 	while (fgets(linebuf, sizeof (linebuf), map) != NULL) {
801 
802 		if (kmc_parse_line(linebuf, &cur_cookie, &cur_label) < 0) {
803 			(void) fclose(map);
804 			return (NULL);
805 		}
806 
807 		if (cookie == cur_cookie) {
808 			(void) fclose(map);
809 			return (cur_label);
810 		}
811 	}
812 	(void) fclose(map);
813 
814 	return (NULL);
815 }
816 
817 /*
818  * Parse basic extension headers and return in the passed-in pointer vector.
819  * Return values include:
820  *
821  *	KGE_OK	Everything's nice and parsed out.
822  *		If there are no extensions, place NULL in extv[0].
823  *	KGE_DUP	There is a duplicate extension.
824  *		First instance in appropriate bin.  First duplicate in
825  *		extv[0].
826  *	KGE_UNK	Unknown extension type encountered.  extv[0] contains
827  *		unknown header.
828  *	KGE_LEN	Extension length error.
829  *	KGE_CHK	High-level reality check failed on specific extension.
830  *
831  * My apologies for some of the pointer arithmetic in here.  I'm thinking
832  * like an assembly programmer, yet trying to make the compiler happy.
833  */
834 int
835 spdsock_get_ext(spd_ext_t *extv[], spd_msg_t *basehdr, uint_t msgsize,
836     char *diag_buf, uint_t diag_buf_len)
837 {
838 	int i;
839 
840 	if (diag_buf != NULL)
841 		diag_buf[0] = '\0';
842 
843 	for (i = 1; i <= SPD_EXT_MAX; i++)
844 		extv[i] = NULL;
845 
846 	i = 0;
847 	/* Use extv[0] as the "current working pointer". */
848 
849 	extv[0] = (spd_ext_t *)(basehdr + 1);
850 	msgsize = SPD_64TO8(msgsize);
851 
852 	while ((char *)extv[0] < ((char *)basehdr + msgsize)) {
853 		/* Check for unknown headers. */
854 		i++;
855 
856 		if (extv[0]->spd_ext_type == 0 ||
857 		    extv[0]->spd_ext_type > SPD_EXT_MAX) {
858 			if (diag_buf != NULL) {
859 				(void) snprintf(diag_buf, diag_buf_len,
860 				    "spdsock ext 0x%X unknown: 0x%X",
861 				    i, extv[0]->spd_ext_type);
862 			}
863 			return (KGE_UNK);
864 		}
865 
866 		/*
867 		 * Check length.  Use uint64_t because extlen is in units
868 		 * of 64-bit words.  If length goes beyond the msgsize,
869 		 * return an error.  (Zero length also qualifies here.)
870 		 */
871 		if (extv[0]->spd_ext_len == 0 ||
872 		    (uint8_t *)((uint64_t *)extv[0] + extv[0]->spd_ext_len) >
873 		    (uint8_t *)((uint8_t *)basehdr + msgsize))
874 			return (KGE_LEN);
875 
876 		/* Check for redundant headers. */
877 		if (extv[extv[0]->spd_ext_type] != NULL)
878 			return (KGE_DUP);
879 
880 		/* If I make it here, assign the appropriate bin. */
881 		extv[extv[0]->spd_ext_type] = extv[0];
882 
883 		/* Advance pointer (See above for uint64_t ptr reasoning.) */
884 		extv[0] = (spd_ext_t *)
885 		    ((uint64_t *)extv[0] + extv[0]->spd_ext_len);
886 	}
887 
888 	/* Everything's cool. */
889 
890 	/*
891 	 * If extv[0] == NULL, then there are no extension headers in this
892 	 * message.  Ensure that this is the case.
893 	 */
894 	if (extv[0] == (spd_ext_t *)(basehdr + 1))
895 		extv[0] = NULL;
896 
897 	return (KGE_OK);
898 }
899 
900 const char *
901 spdsock_diag(int diagnostic)
902 {
903 	switch (diagnostic) {
904 	case SPD_DIAGNOSTIC_NONE:
905 		return (gettext("no error"));
906 	case SPD_DIAGNOSTIC_UNKNOWN_EXT:
907 		return (gettext("unknown extension"));
908 	case SPD_DIAGNOSTIC_BAD_EXTLEN:
909 		return (gettext("bad extension length"));
910 	case SPD_DIAGNOSTIC_NO_RULE_EXT:
911 		return (gettext("no rule extension"));
912 	case SPD_DIAGNOSTIC_BAD_ADDR_LEN:
913 		return (gettext("bad address len"));
914 	case SPD_DIAGNOSTIC_MIXED_AF:
915 		return (gettext("mixed address family"));
916 	case SPD_DIAGNOSTIC_ADD_NO_MEM:
917 		return (gettext("add: no memory"));
918 	case SPD_DIAGNOSTIC_ADD_WRONG_ACT_COUNT:
919 		return (gettext("add: wrong action count"));
920 	case SPD_DIAGNOSTIC_ADD_BAD_TYPE:
921 		return (gettext("add: bad type"));
922 	case SPD_DIAGNOSTIC_ADD_BAD_FLAGS:
923 		return (gettext("add: bad flags"));
924 	case SPD_DIAGNOSTIC_ADD_INCON_FLAGS:
925 		return (gettext("add: inconsistent flags"));
926 	case SPD_DIAGNOSTIC_MALFORMED_LCLPORT:
927 		return (gettext("malformed local port"));
928 	case SPD_DIAGNOSTIC_DUPLICATE_LCLPORT:
929 		return (gettext("duplicate local port"));
930 	case SPD_DIAGNOSTIC_MALFORMED_REMPORT:
931 		return (gettext("malformed remote port"));
932 	case SPD_DIAGNOSTIC_DUPLICATE_REMPORT:
933 		return (gettext("duplicate remote port"));
934 	case SPD_DIAGNOSTIC_MALFORMED_PROTO:
935 		return (gettext("malformed proto"));
936 	case SPD_DIAGNOSTIC_DUPLICATE_PROTO:
937 		return (gettext("duplicate proto"));
938 	case SPD_DIAGNOSTIC_MALFORMED_LCLADDR:
939 		return (gettext("malformed local address"));
940 	case SPD_DIAGNOSTIC_DUPLICATE_LCLADDR:
941 		return (gettext("duplicate local address"));
942 	case SPD_DIAGNOSTIC_MALFORMED_REMADDR:
943 		return (gettext("malformed remote address"));
944 	case SPD_DIAGNOSTIC_DUPLICATE_REMADDR:
945 		return (gettext("duplicate remote address"));
946 	case SPD_DIAGNOSTIC_MALFORMED_ACTION:
947 		return (gettext("malformed action"));
948 	case SPD_DIAGNOSTIC_DUPLICATE_ACTION:
949 		return (gettext("duplicate action"));
950 	case SPD_DIAGNOSTIC_MALFORMED_RULE:
951 		return (gettext("malformed rule"));
952 	case SPD_DIAGNOSTIC_DUPLICATE_RULE:
953 		return (gettext("duplicate rule"));
954 	case SPD_DIAGNOSTIC_MALFORMED_RULESET:
955 		return (gettext("malformed ruleset"));
956 	case SPD_DIAGNOSTIC_DUPLICATE_RULESET:
957 		return (gettext("duplicate ruleset"));
958 	case SPD_DIAGNOSTIC_INVALID_RULE_INDEX:
959 		return (gettext("invalid rule index"));
960 	case SPD_DIAGNOSTIC_BAD_SPDID:
961 		return (gettext("bad spdid"));
962 	case SPD_DIAGNOSTIC_BAD_MSG_TYPE:
963 		return (gettext("bad message type"));
964 	case SPD_DIAGNOSTIC_UNSUPP_AH_ALG:
965 		return (gettext("unsupported AH algorithm"));
966 	case SPD_DIAGNOSTIC_UNSUPP_ESP_ENCR_ALG:
967 		return (gettext("unsupported ESP encryption algorithm"));
968 	case SPD_DIAGNOSTIC_UNSUPP_ESP_AUTH_ALG:
969 		return (gettext("unsupported ESP authentication algorithm"));
970 	case SPD_DIAGNOSTIC_UNSUPP_AH_KEYSIZE:
971 		return (gettext("unsupported AH key size"));
972 	case SPD_DIAGNOSTIC_UNSUPP_ESP_ENCR_KEYSIZE:
973 		return (gettext("unsupported ESP encryption key size"));
974 	case SPD_DIAGNOSTIC_UNSUPP_ESP_AUTH_KEYSIZE:
975 		return (gettext("unsupported ESP authentication key size"));
976 	case SPD_DIAGNOSTIC_NO_ACTION_EXT:
977 		return (gettext("No ACTION extension"));
978 	case SPD_DIAGNOSTIC_ALG_ID_RANGE:
979 		return (gettext("invalid algorithm identifer"));
980 	case SPD_DIAGNOSTIC_ALG_NUM_KEY_SIZES:
981 		return (gettext("number of key sizes inconsistent"));
982 	case SPD_DIAGNOSTIC_ALG_NUM_BLOCK_SIZES:
983 		return (gettext("number of block sizes inconsistent"));
984 	case SPD_DIAGNOSTIC_ALG_MECH_NAME_LEN:
985 		return (gettext("invalid mechanism name length"));
986 	default:
987 		return (gettext("unknown diagnostic"));
988 	}
989 }
990 
991 /*
992  * PF_KEY Diagnostic table.
993  *
994  * PF_KEY NOTE:  If you change pfkeyv2.h's SADB_X_DIAGNOSTIC_* space, this is
995  * where you need to add new messages.
996  */
997 
998 const char *
999 keysock_diag(int diagnostic)
1000 {
1001 	switch (diagnostic) {
1002 	case  SADB_X_DIAGNOSTIC_NONE:
1003 		return (gettext("No diagnostic"));
1004 	case SADB_X_DIAGNOSTIC_UNKNOWN_MSG:
1005 		return (gettext("Unknown message type"));
1006 	case SADB_X_DIAGNOSTIC_UNKNOWN_EXT:
1007 		return (gettext("Unknown extension type"));
1008 	case SADB_X_DIAGNOSTIC_BAD_EXTLEN:
1009 		return (gettext("Bad extension length"));
1010 	case SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE:
1011 		return (gettext("Unknown Security Association type"));
1012 	case SADB_X_DIAGNOSTIC_SATYPE_NEEDED:
1013 		return (gettext("Specific Security Association type needed"));
1014 	case SADB_X_DIAGNOSTIC_NO_SADBS:
1015 		return (gettext("No Security Association Databases present"));
1016 	case SADB_X_DIAGNOSTIC_NO_EXT:
1017 		return (gettext("No extensions needed for message"));
1018 	case SADB_X_DIAGNOSTIC_BAD_SRC_AF:
1019 		return (gettext("Bad source address family"));
1020 	case SADB_X_DIAGNOSTIC_BAD_DST_AF:
1021 		return (gettext("Bad destination address family"));
1022 	case SADB_X_DIAGNOSTIC_BAD_PROXY_AF:
1023 		return (gettext("Bad proxy address family"));
1024 	case SADB_X_DIAGNOSTIC_AF_MISMATCH:
1025 		return (gettext("Source/destination address family mismatch"));
1026 	case SADB_X_DIAGNOSTIC_BAD_SRC:
1027 		return (gettext("Bad source address value"));
1028 	case SADB_X_DIAGNOSTIC_BAD_DST:
1029 		return (gettext("Bad destination address value"));
1030 	case SADB_X_DIAGNOSTIC_ALLOC_HSERR:
1031 		return (gettext("Soft allocations limit more than hard limit"));
1032 	case SADB_X_DIAGNOSTIC_BYTES_HSERR:
1033 		return (gettext("Soft bytes limit more than hard limit"));
1034 	case SADB_X_DIAGNOSTIC_ADDTIME_HSERR:
1035 		return (gettext("Soft add expiration time later "
1036 		    "than hard expiration time"));
1037 	case SADB_X_DIAGNOSTIC_USETIME_HSERR:
1038 		return (gettext("Soft use expiration time later "
1039 		    "than hard expiration time"));
1040 	case SADB_X_DIAGNOSTIC_MISSING_SRC:
1041 		return (gettext("Missing source address"));
1042 	case SADB_X_DIAGNOSTIC_MISSING_DST:
1043 		return (gettext("Missing destination address"));
1044 	case SADB_X_DIAGNOSTIC_MISSING_SA:
1045 		return (gettext("Missing SA extension"));
1046 	case SADB_X_DIAGNOSTIC_MISSING_EKEY:
1047 		return (gettext("Missing encryption key"));
1048 	case SADB_X_DIAGNOSTIC_MISSING_AKEY:
1049 		return (gettext("Missing authentication key"));
1050 	case SADB_X_DIAGNOSTIC_MISSING_RANGE:
1051 		return (gettext("Missing SPI range"));
1052 	case SADB_X_DIAGNOSTIC_DUPLICATE_SRC:
1053 		return (gettext("Duplicate source address"));
1054 	case SADB_X_DIAGNOSTIC_DUPLICATE_DST:
1055 		return (gettext("Duplicate destination address"));
1056 	case SADB_X_DIAGNOSTIC_DUPLICATE_SA:
1057 		return (gettext("Duplicate SA extension"));
1058 	case SADB_X_DIAGNOSTIC_DUPLICATE_EKEY:
1059 		return (gettext("Duplicate encryption key"));
1060 	case SADB_X_DIAGNOSTIC_DUPLICATE_AKEY:
1061 		return (gettext("Duplicate authentication key"));
1062 	case SADB_X_DIAGNOSTIC_DUPLICATE_RANGE:
1063 		return (gettext("Duplicate SPI range"));
1064 	case SADB_X_DIAGNOSTIC_MALFORMED_SRC:
1065 		return (gettext("Malformed source address"));
1066 	case SADB_X_DIAGNOSTIC_MALFORMED_DST:
1067 		return (gettext("Malformed destination address"));
1068 	case SADB_X_DIAGNOSTIC_MALFORMED_SA:
1069 		return (gettext("Malformed SA extension"));
1070 	case SADB_X_DIAGNOSTIC_MALFORMED_EKEY:
1071 		return (gettext("Malformed encryption key"));
1072 	case SADB_X_DIAGNOSTIC_MALFORMED_AKEY:
1073 		return (gettext("Malformed authentication key"));
1074 	case SADB_X_DIAGNOSTIC_MALFORMED_RANGE:
1075 		return (gettext("Malformed SPI range"));
1076 	case SADB_X_DIAGNOSTIC_AKEY_PRESENT:
1077 		return (gettext("Authentication key not needed"));
1078 	case SADB_X_DIAGNOSTIC_EKEY_PRESENT:
1079 		return (gettext("Encryption key not needed"));
1080 	case SADB_X_DIAGNOSTIC_PROP_PRESENT:
1081 		return (gettext("Proposal extension not needed"));
1082 	case SADB_X_DIAGNOSTIC_SUPP_PRESENT:
1083 		return (gettext("Supported algorithms extension not needed"));
1084 	case SADB_X_DIAGNOSTIC_BAD_AALG:
1085 		return (gettext("Unsupported authentication algorithm"));
1086 	case SADB_X_DIAGNOSTIC_BAD_EALG:
1087 		return (gettext("Unsupported encryption algorithm"));
1088 	case SADB_X_DIAGNOSTIC_BAD_SAFLAGS:
1089 		return (gettext("Invalid SA flags"));
1090 	case SADB_X_DIAGNOSTIC_BAD_SASTATE:
1091 		return (gettext("Invalid SA state"));
1092 	case SADB_X_DIAGNOSTIC_BAD_AKEYBITS:
1093 		return (gettext("Bad number of authentication bits"));
1094 	case SADB_X_DIAGNOSTIC_BAD_EKEYBITS:
1095 		return (gettext("Bad number of encryption bits"));
1096 	case SADB_X_DIAGNOSTIC_ENCR_NOTSUPP:
1097 		return (gettext("Encryption not supported for this SA type"));
1098 	case SADB_X_DIAGNOSTIC_WEAK_EKEY:
1099 		return (gettext("Weak encryption key"));
1100 	case SADB_X_DIAGNOSTIC_WEAK_AKEY:
1101 		return (gettext("Weak authentication key"));
1102 	case SADB_X_DIAGNOSTIC_DUPLICATE_KMP:
1103 		return (gettext("Duplicate key management protocol"));
1104 	case SADB_X_DIAGNOSTIC_DUPLICATE_KMC:
1105 		return (gettext("Duplicate key management cookie"));
1106 	case SADB_X_DIAGNOSTIC_MISSING_NATT_LOC:
1107 		return (gettext("Missing NATT local address"));
1108 	case SADB_X_DIAGNOSTIC_MISSING_NATT_REM:
1109 		return (gettext("Missing NATT remote address"));
1110 	case SADB_X_DIAGNOSTIC_DUPLICATE_NATT_LOC:
1111 		return (gettext("Duplicate NATT local address"));
1112 	case SADB_X_DIAGNOSTIC_DUPLICATE_NATT_REM:
1113 		return (gettext("Duplicate NATT remote address"));
1114 	case SADB_X_DIAGNOSTIC_MALFORMED_NATT_LOC:
1115 		return (gettext("Malformed NATT local address"));
1116 	case SADB_X_DIAGNOSTIC_MALFORMED_NATT_REM:
1117 		return (gettext("Malformed NATT remote address"));
1118 	case SADB_X_DIAGNOSTIC_DUPLICATE_NATT_PORTS:
1119 		return (gettext("Duplicate NATT ports"));
1120 	default:
1121 		return (gettext("Unknown diagnostic code"));
1122 	}
1123 }
1124