xref: /titanic_41/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c (revision 17169044f903cb92234f23d0ba0ce43449614a4d)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * NOTE:I'm trying to use "struct sadb_foo" instead of "sadb_foo_t"
28  *	as a maximal PF_KEY portability test.
29  *
30  *	Also, this is a deliberately single-threaded app, also for portability
31  *	to systems without POSIX threads.
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/socket.h>
39 #include <sys/sysmacros.h>
40 #include <sys/fcntl.h>
41 #include <net/pfkeyv2.h>
42 #include <arpa/inet.h>
43 #include <netinet/in.h>
44 #include <sys/uio.h>
45 
46 #include <syslog.h>
47 #include <signal.h>
48 #include <unistd.h>
49 #include <limits.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <stdarg.h>
53 #include <netdb.h>
54 #include <pwd.h>
55 #include <errno.h>
56 #include <libintl.h>
57 #include <locale.h>
58 #include <fcntl.h>
59 #include <strings.h>
60 #include <ctype.h>
61 
62 #include <ipsec_util.h>
63 
64 static int keysock;
65 static uint32_t seq;
66 static pid_t mypid;
67 static boolean_t vflag = B_FALSE;	/* Verbose? */
68 static boolean_t cflag = B_FALSE;	/* Check Only */
69 
70 char *my_fmri = NULL;
71 FILE *debugfile = stdout;
72 
73 #define	MAX_GET_SIZE	1024
74 /*
75  * WARN() and ERROR() do the same thing really, with ERROR() the function
76  * that prints the error buffer needs to be called at the end of a code block
77  * This will print out all accumulated errors before bailing. The WARN()
78  * macro calls handle_errors() in such a way that it prints the message
79  * then continues.
80  * If the FATAL() macro used call handle_errors() immediately.
81  */
82 #define	ERROR(x, y, z)  x = record_error(x, y, z)
83 #define	ERROR1(w, x, y, z)  w = record_error(w, x, y, z)
84 #define	ERROR2(v, w, x, y, z)  v = record_error(v, w, x, y, z)
85 #define	WARN(x, y, z) ERROR(x, y, z);\
86 	handle_errors(x, NULL, B_FALSE, B_FALSE); x = NULL
87 #define	WARN1(w, x, y, z) ERROR1(w, x, y, z);\
88 	handle_errors(w, NULL, B_FALSE, B_FALSE); w = NULL
89 #define	WARN2(v, w, x, y, z) ERROR2(v, w, x, y, z);\
90 	handle_errors(v, NULL, B_FALSE, B_FALSE); v = NULL
91 #define	FATAL(x, y, z) ERROR(x, y, z);\
92 	handle_errors(x, y, B_TRUE, B_TRUE)
93 #define	FATAL1(w, x, y, z) ERROR1(w, x, y, z);\
94 	handle_errors(w, x, B_TRUE, B_TRUE)
95 
96 /* Defined as a uint64_t array for alignment purposes. */
97 static uint64_t get_buffer[MAX_GET_SIZE];
98 
99 /*
100  * Create/Grow a buffer large enough to hold error messages. If *ebuf
101  * is not NULL then it will contain a copy of the command line that
102  * triggered the error/warning, copy this into a new buffer or
103  * append new messages to the existing buffer.
104  */
105 /*PRINTFLIKE1*/
106 char *
107 record_error(char *ep, char *ebuf, char *fmt, ...)
108 {
109 	char *err_ptr;
110 	char tmp_buff[1024];
111 	va_list ap;
112 	int length = 0;
113 	err_ptr = ep;
114 
115 	va_start(ap, fmt);
116 	length = vsnprintf(tmp_buff, sizeof (tmp_buff), fmt, ap);
117 	va_end(ap);
118 
119 	/* There is a new line character */
120 	length++;
121 
122 	if (ep == NULL) {
123 		if (ebuf != NULL)
124 			length += strlen(ebuf);
125 	} else  {
126 		length += strlen(ep);
127 	}
128 
129 	if (err_ptr == NULL)
130 		err_ptr = calloc(length, sizeof (char));
131 	else
132 		err_ptr = realloc(err_ptr, length);
133 
134 	if (err_ptr == NULL)
135 		Bail("realloc() failure");
136 
137 	/*
138 	 * If (ep == NULL) then this is the first error to record,
139 	 * copy in the command line that triggered this error/warning.
140 	 */
141 	if (ep == NULL && ebuf != NULL)
142 		(void) strlcpy(err_ptr, ebuf, length);
143 
144 	/*
145 	 * Now the actual error.
146 	 */
147 	(void) strlcat(err_ptr, tmp_buff, length);
148 	return (err_ptr);
149 }
150 
151 /*
152  * Print usage message.
153  */
154 static void
155 usage(void)
156 {
157 	if (!interactive) {
158 		(void) fprintf(stderr, gettext("Usage:\t"
159 		    "ipseckey [ -nvp ] | cmd [sa_type] [extfield value]*\n"));
160 		(void) fprintf(stderr,
161 		    gettext("\tipseckey [ -nvp ] -f infile\n"));
162 		(void) fprintf(stderr,
163 		    gettext("\tipseckey [ -nvp ] -s outfile\n"));
164 	}
165 	EXIT_FATAL(NULL);
166 }
167 
168 
169 /*
170  * Print out any errors, tidy up as required.
171  * error pointer ep will be free()'d
172  */
173 void
174 handle_errors(char *ep, char *ebuf, boolean_t fatal, boolean_t done)
175 {
176 	if (ep != NULL) {
177 		if (my_fmri == NULL) {
178 			/*
179 			 * For now suppress the errors when run from smf(5)
180 			 * because potentially sensitive information could
181 			 * end up in a publicly readable logfile.
182 			 */
183 			(void) fprintf(stdout, "%s\n", ep);
184 			(void) fflush(stdout);
185 		}
186 		free(ep);
187 		if (fatal) {
188 			if (ebuf != NULL) {
189 				free(ebuf);
190 			}
191 			/* reset command buffer */
192 			if (interactive)
193 				longjmp(env, 1);
194 		} else {
195 			return;
196 		}
197 	} else {
198 		/*
199 		 * No errors, if this is the last time that this function
200 		 * is called, free(ebuf) and reset command buffer.
201 		 */
202 		if (done) {
203 			if (ebuf != NULL) {
204 				free(ebuf);
205 			}
206 			/* reset command buffer */
207 			if (interactive)
208 				longjmp(env, 1);
209 		}
210 		return;
211 	}
212 	EXIT_FATAL(NULL);
213 }
214 
215 /*
216  * Initialize a PF_KEY base message.
217  */
218 static void
219 msg_init(struct sadb_msg *msg, uint8_t type, uint8_t satype)
220 {
221 	msg->sadb_msg_version = PF_KEY_V2;
222 	msg->sadb_msg_type = type;
223 	msg->sadb_msg_errno = 0;
224 	msg->sadb_msg_satype = satype;
225 	/* For starters... */
226 	msg->sadb_msg_len = SADB_8TO64(sizeof (*msg));
227 	msg->sadb_msg_reserved = 0;
228 	msg->sadb_msg_seq = ++seq;
229 	msg->sadb_msg_pid = mypid;
230 }
231 
232 /*
233  * parseXXX and rparseXXX commands parse input and convert them to PF_KEY
234  * field values, or do the reverse for the purposes of saving the SA tables.
235  * (See the save_XXX functions.)
236  */
237 
238 #define	CMD_NONE	0
239 #define	CMD_UPDATE	2
240 #define	CMD_UPDATE_PAIR	3
241 #define	CMD_ADD		4
242 #define	CMD_DELETE	5
243 #define	CMD_DELETE_PAIR	6
244 #define	CMD_GET		7
245 #define	CMD_FLUSH	9
246 #define	CMD_DUMP	10
247 #define	CMD_MONITOR	11
248 #define	CMD_PMONITOR	12
249 #define	CMD_QUIT	13
250 #define	CMD_SAVE	14
251 #define	CMD_HELP	15
252 
253 /*
254  * Parse the command.
255  */
256 static int
257 parsecmd(char *cmdstr)
258 {
259 	static struct cmdtable {
260 		char *cmd;
261 		int token;
262 	} table[] = {
263 		/*
264 		 * Q: Do we want to do GETSPI?
265 		 * A: No, it's for automated key mgmt. only.  Either that,
266 		 *    or it isn't relevant until we support non IPsec SA types.
267 		 */
268 		{"update",		CMD_UPDATE},
269 		{"update-pair",		CMD_UPDATE_PAIR},
270 		{"add",			CMD_ADD},
271 		{"delete", 		CMD_DELETE},
272 		{"delete-pair",		CMD_DELETE_PAIR},
273 		{"get", 		CMD_GET},
274 		/*
275 		 * Q: And ACQUIRE and REGISTER and EXPIRE?
276 		 * A: not until we support non IPsec SA types.
277 		 */
278 		{"flush",		CMD_FLUSH},
279 		{"dump",		CMD_DUMP},
280 		{"monitor",		CMD_MONITOR},
281 		{"passive_monitor",	CMD_PMONITOR},
282 		{"pmonitor",		CMD_PMONITOR},
283 		{"quit",		CMD_QUIT},
284 		{"exit",		CMD_QUIT},
285 		{"save",		CMD_SAVE},
286 		{"help",		CMD_HELP},
287 		{"?",			CMD_HELP},
288 		{NULL,			CMD_NONE}
289 	};
290 	struct cmdtable *ct = table;
291 
292 	while (ct->cmd != NULL && strcmp(ct->cmd, cmdstr) != 0)
293 		ct++;
294 	return (ct->token);
295 }
296 
297 /*
298  * Convert a number from a command line.  I picked "u_longlong_t" for the
299  * number because we need the largest number available.  Also, the strto<num>
300  * calls don't deal in units of uintNN_t.
301  */
302 static u_longlong_t
303 parsenum(char *num, boolean_t bail, char *ebuf)
304 {
305 	u_longlong_t rc = 0;
306 	char *end = NULL;
307 	char *ep = NULL;
308 
309 	if (num == NULL) {
310 		FATAL(ep, ebuf, gettext("Unexpected end of command line,"
311 		    " was expecting a number.\n"));
312 		/* NOTREACHED */
313 	}
314 
315 	errno = 0;
316 	rc = strtoull(num, &end, 0);
317 	if (errno != 0 || end == num || *end != '\0') {
318 		if (bail) {
319 			FATAL1(ep, ebuf, gettext(
320 			"Expecting a number, not \"%s\"!\n"), num);
321 		} else {
322 			/*
323 			 * -1, while not optimal, is sufficiently out of range
324 			 * for most of this function's applications when
325 			 * we don't just bail.
326 			 */
327 			return ((u_longlong_t)-1);
328 		}
329 	}
330 	handle_errors(ep, NULL, B_FALSE, B_FALSE);
331 	return (rc);
332 }
333 
334 /*
335  * Parse and reverse parse a specific SA type (AH, ESP, etc.).
336  */
337 static struct typetable {
338 	char *type;
339 	int token;
340 } type_table[] = {
341 	{"all",	SADB_SATYPE_UNSPEC},
342 	{"ah",	SADB_SATYPE_AH},
343 	{"esp",	SADB_SATYPE_ESP},
344 	/* PF_KEY NOTE:  More to come if net/pfkeyv2.h gets updated. */
345 	{NULL,	0}	/* Token value is irrelevant for this entry. */
346 };
347 
348 
349 static int
350 parsesatype(char *type, char *ebuf)
351 {
352 	struct typetable *tt = type_table;
353 	char *ep = NULL;
354 
355 	if (type == NULL)
356 		return (SADB_SATYPE_UNSPEC);
357 
358 	while (tt->type != NULL && strcasecmp(tt->type, type) != 0)
359 		tt++;
360 
361 	/*
362 	 * New SA types (including ones keysock maintains for user-land
363 	 * protocols) may be added, so parse a numeric value if possible.
364 	 */
365 	if (tt->type == NULL) {
366 		tt->token = (int)parsenum(type, B_FALSE, ebuf);
367 		if (tt->token == -1) {
368 			ERROR1(ep, ebuf, gettext(
369 			    "Unknown SA type (%s).\n"), type);
370 			tt->token = SADB_SATYPE_UNSPEC;
371 		}
372 	}
373 	handle_errors(ep, NULL, B_FALSE, B_FALSE);
374 	return (tt->token);
375 }
376 
377 #define	NEXTEOF		0
378 #define	NEXTNONE	1
379 #define	NEXTNUM		2
380 #define	NEXTSTR		3
381 #define	NEXTNUMSTR	4
382 #define	NEXTADDR	5
383 #define	NEXTHEX		6
384 #define	NEXTIDENT	7
385 #define	NEXTADDR4	8
386 #define	NEXTADDR6	9
387 
388 #define	TOK_EOF			0
389 #define	TOK_UNKNOWN		1
390 #define	TOK_SPI			2
391 #define	TOK_REPLAY		3
392 #define	TOK_STATE		4
393 #define	TOK_AUTHALG		5
394 #define	TOK_ENCRALG		6
395 #define	TOK_FLAGS		7
396 #define	TOK_SOFT_ALLOC		8
397 #define	TOK_SOFT_BYTES		9
398 #define	TOK_SOFT_ADDTIME	10
399 #define	TOK_SOFT_USETIME	11
400 #define	TOK_HARD_ALLOC		12
401 #define	TOK_HARD_BYTES		13
402 #define	TOK_HARD_ADDTIME	14
403 #define	TOK_HARD_USETIME	15
404 #define	TOK_CURRENT_ALLOC	16
405 #define	TOK_CURRENT_BYTES	17
406 #define	TOK_CURRENT_ADDTIME	18
407 #define	TOK_CURRENT_USETIME	19
408 #define	TOK_SRCADDR		20
409 #define	TOK_DSTADDR		21
410 #define	TOK_PROXYADDR		22
411 #define	TOK_AUTHKEY		23
412 #define	TOK_ENCRKEY		24
413 #define	TOK_SRCIDTYPE		25
414 #define	TOK_DSTIDTYPE		26
415 #define	TOK_DPD			27
416 #define	TOK_SENS_LEVEL		28
417 #define	TOK_SENS_MAP		29
418 #define	TOK_INTEG_LEVEL		30
419 #define	TOK_INTEG_MAP		31
420 #define	TOK_SRCADDR6		32
421 #define	TOK_DSTADDR6		33
422 #define	TOK_PROXYADDR6		34
423 #define	TOK_SRCPORT		35
424 #define	TOK_DSTPORT		36
425 #define	TOK_PROTO		37
426 #define	TOK_ENCAP		38
427 #define	TOK_NATLOC		39
428 #define	TOK_NATREM		40
429 #define	TOK_NATLPORT		41
430 #define	TOK_NATRPORT		42
431 #define	TOK_IPROTO		43
432 #define	TOK_IDSTADDR		44
433 #define	TOK_IDSTADDR6		45
434 #define	TOK_ISRCPORT		46
435 #define	TOK_IDSTPORT		47
436 #define	TOK_PAIR_SPI		48
437 #define	TOK_FLAG_INBOUND	49
438 #define	TOK_FLAG_OUTBOUND	50
439 
440 static struct toktable {
441 	char *string;
442 	int token;
443 	int next;
444 } tokens[] = {
445 	/* "String",		token value,		next arg is */
446 	{"spi",			TOK_SPI,		NEXTNUM},
447 	{"pair-spi",		TOK_PAIR_SPI,		NEXTNUM},
448 	{"replay",		TOK_REPLAY,		NEXTNUM},
449 	{"state",		TOK_STATE,		NEXTNUMSTR},
450 	{"auth_alg",		TOK_AUTHALG,		NEXTNUMSTR},
451 	{"authalg",		TOK_AUTHALG,		NEXTNUMSTR},
452 	{"encr_alg",		TOK_ENCRALG,		NEXTNUMSTR},
453 	{"encralg",		TOK_ENCRALG,		NEXTNUMSTR},
454 	{"flags",		TOK_FLAGS,		NEXTNUM},
455 	{"soft_alloc",		TOK_SOFT_ALLOC,		NEXTNUM},
456 	{"soft_bytes",		TOK_SOFT_BYTES,		NEXTNUM},
457 	{"soft_addtime",	TOK_SOFT_ADDTIME,	NEXTNUM},
458 	{"soft_usetime",	TOK_SOFT_USETIME,	NEXTNUM},
459 	{"hard_alloc",		TOK_HARD_ALLOC,		NEXTNUM},
460 	{"hard_bytes",		TOK_HARD_BYTES,		NEXTNUM},
461 	{"hard_addtime",	TOK_HARD_ADDTIME,	NEXTNUM},
462 	{"hard_usetime",	TOK_HARD_USETIME,	NEXTNUM},
463 	{"current_alloc",	TOK_CURRENT_ALLOC,	NEXTNUM},
464 	{"current_bytes",	TOK_CURRENT_BYTES,	NEXTNUM},
465 	{"current_addtime",	TOK_CURRENT_ADDTIME,	NEXTNUM},
466 	{"current_usetime",	TOK_CURRENT_USETIME,	NEXTNUM},
467 
468 	{"saddr",		TOK_SRCADDR,		NEXTADDR},
469 	{"srcaddr",		TOK_SRCADDR,		NEXTADDR},
470 	{"src",			TOK_SRCADDR,		NEXTADDR},
471 	{"daddr",		TOK_DSTADDR,		NEXTADDR},
472 	{"dstaddr",		TOK_DSTADDR,		NEXTADDR},
473 	{"dst",			TOK_DSTADDR,		NEXTADDR},
474 	{"proxyaddr",		TOK_PROXYADDR,		NEXTADDR},
475 	{"proxy",		TOK_PROXYADDR,		NEXTADDR},
476 	{"innersrc",		TOK_PROXYADDR,		NEXTADDR},
477 	{"isrc",		TOK_PROXYADDR,		NEXTADDR},
478 	{"innerdst",		TOK_IDSTADDR,		NEXTADDR},
479 	{"idst",		TOK_IDSTADDR,		NEXTADDR},
480 
481 	{"sport",		TOK_SRCPORT,		NEXTNUM},
482 	{"dport",		TOK_DSTPORT,		NEXTNUM},
483 	{"innersport",		TOK_ISRCPORT,		NEXTNUM},
484 	{"isport",		TOK_ISRCPORT,		NEXTNUM},
485 	{"innerdport",		TOK_IDSTPORT,		NEXTNUM},
486 	{"idport",		TOK_IDSTPORT,		NEXTNUM},
487 	{"proto",		TOK_PROTO,		NEXTNUM},
488 	{"ulp",			TOK_PROTO,		NEXTNUM},
489 	{"iproto",		TOK_IPROTO,		NEXTNUM},
490 	{"iulp",		TOK_IPROTO,		NEXTNUM},
491 
492 	{"saddr6",		TOK_SRCADDR6,		NEXTADDR},
493 	{"srcaddr6",		TOK_SRCADDR6,		NEXTADDR},
494 	{"src6",		TOK_SRCADDR6,		NEXTADDR},
495 	{"daddr6",		TOK_DSTADDR6,		NEXTADDR},
496 	{"dstaddr6",		TOK_DSTADDR6,		NEXTADDR},
497 	{"dst6",		TOK_DSTADDR6,		NEXTADDR},
498 	{"proxyaddr6",		TOK_PROXYADDR6,		NEXTADDR},
499 	{"proxy6",		TOK_PROXYADDR6,		NEXTADDR},
500 	{"innersrc6",		TOK_PROXYADDR6,		NEXTADDR},
501 	{"isrc6",		TOK_PROXYADDR6,		NEXTADDR},
502 	{"innerdst6",		TOK_IDSTADDR6,		NEXTADDR},
503 	{"idst6",		TOK_IDSTADDR6,		NEXTADDR},
504 
505 	{"authkey",		TOK_AUTHKEY,		NEXTHEX},
506 	{"encrkey",		TOK_ENCRKEY,		NEXTHEX},
507 	{"srcidtype",		TOK_SRCIDTYPE,		NEXTIDENT},
508 	{"dstidtype",		TOK_DSTIDTYPE,		NEXTIDENT},
509 	{"dpd",			TOK_DPD,		NEXTNUM},
510 	{"sens_level",		TOK_SENS_LEVEL,		NEXTNUM},
511 	{"sens_map",		TOK_SENS_MAP,		NEXTHEX},
512 	{"integ_level",		TOK_INTEG_LEVEL,	NEXTNUM},
513 	{"integ_map",		TOK_INTEG_MAP,		NEXTHEX},
514 	{"nat_loc",		TOK_NATLOC,		NEXTADDR},
515 	{"nat_rem",		TOK_NATREM,		NEXTADDR},
516 	{"nat_lport",		TOK_NATLPORT,		NEXTNUM},
517 	{"nat_rport",		TOK_NATRPORT,		NEXTNUM},
518 	{"encap",		TOK_ENCAP,		NEXTNUMSTR},
519 
520 	{"outbound",		TOK_FLAG_OUTBOUND,	NULL},
521 	{"inbound",		TOK_FLAG_INBOUND,	NULL},
522 	{NULL,			TOK_UNKNOWN,		NEXTEOF}
523 };
524 
525 /*
526  * Q:	Do I need stuff for proposals, combinations, supported algorithms,
527  *	or SPI ranges?
528  *
529  * A:	Probably not, but you never know.
530  *
531  * Parse out extension header type values.
532  */
533 static int
534 parseextval(char *value, int *next)
535 {
536 	struct toktable *tp;
537 
538 	if (value == NULL)
539 		return (TOK_EOF);
540 
541 	for (tp = tokens; tp->string != NULL; tp++)
542 		if (strcmp(value, tp->string) == 0)
543 			break;
544 
545 	/*
546 	 * Since the OS controls what extensions are available, we don't have
547 	 * to parse numeric values here.
548 	 */
549 
550 	*next = tp->next;
551 	return (tp->token);
552 }
553 
554 /*
555  * Parse possible state values.
556  */
557 static uint8_t
558 parsestate(char *state, char *ebuf)
559 {
560 	struct states {
561 		char *state;
562 		uint8_t retval;
563 	} states[] = {
564 		{"larval",	SADB_SASTATE_LARVAL},
565 		{"mature",	SADB_SASTATE_MATURE},
566 		{"dying",	SADB_SASTATE_DYING},
567 		{"dead",	SADB_SASTATE_DEAD},
568 		{NULL,		0}
569 	};
570 	struct states *sp;
571 	char *ep = NULL;
572 
573 	if (state == NULL) {
574 		FATAL(ep, ebuf, "Unexpected end of command line "
575 		    "was expecting a state.\n");
576 	}
577 
578 	for (sp = states; sp->state != NULL; sp++) {
579 		if (strcmp(sp->state, state) == 0)
580 			return (sp->retval);
581 	}
582 	ERROR1(ep, ebuf, gettext("Unknown state type \"%s\"\n"), state);
583 	handle_errors(ep, NULL, B_FALSE, B_FALSE);
584 	return (0);
585 }
586 
587 /*
588  * Return the numerical algorithm identifier corresponding to the specified
589  * algorithm name.
590  */
591 static uint8_t
592 parsealg(char *alg, int proto_num, char *ebuf)
593 {
594 	u_longlong_t invalue;
595 	struct ipsecalgent *algent;
596 	char *ep = NULL;
597 
598 	if (alg == NULL) {
599 		FATAL(ep, ebuf, gettext("Unexpected end of command line, "
600 		    "was expecting an algorithm name.\n"));
601 	}
602 
603 	algent = getipsecalgbyname(alg, proto_num, NULL);
604 	if (algent != NULL) {
605 		uint8_t alg_num;
606 
607 		alg_num = algent->a_alg_num;
608 		freeipsecalgent(algent);
609 
610 		return (alg_num);
611 	}
612 
613 	/*
614 	 * Since algorithms can be loaded during kernel run-time, check for
615 	 * numeric algorithm values too.  PF_KEY can catch bad ones with EINVAL.
616 	 */
617 	invalue = parsenum(alg, B_FALSE, ebuf);
618 	if (invalue != (u_longlong_t)-1 &&
619 	    (u_longlong_t)(invalue & (u_longlong_t)0xff) == invalue)
620 		return ((uint8_t)invalue);
621 
622 	if (proto_num == IPSEC_PROTO_ESP) {
623 		ERROR1(ep, ebuf, gettext(
624 		    "Unknown encryption algorithm type \"%s\"\n"), alg);
625 	} else {
626 		ERROR1(ep, ebuf, gettext(
627 		    "Unknown authentication algorithm type \"%s\"\n"), alg);
628 	}
629 	handle_errors(ep, NULL, B_FALSE, B_FALSE);
630 	return (0);
631 }
632 
633 /*
634  * Parse and reverse parse out a source/destination ID type.
635  */
636 static struct idtypes {
637 	char *idtype;
638 	uint8_t retval;
639 } idtypes[] = {
640 	{"prefix",	SADB_IDENTTYPE_PREFIX},
641 	{"fqdn",	SADB_IDENTTYPE_FQDN},
642 	{"domain",	SADB_IDENTTYPE_FQDN},
643 	{"domainname",	SADB_IDENTTYPE_FQDN},
644 	{"user_fqdn",	SADB_IDENTTYPE_USER_FQDN},
645 	{"mailbox",	SADB_IDENTTYPE_USER_FQDN},
646 	{"der_dn",	SADB_X_IDENTTYPE_DN},
647 	{"der_gn",	SADB_X_IDENTTYPE_GN},
648 	{NULL,		0}
649 };
650 
651 static uint16_t
652 parseidtype(char *type, char *ebuf)
653 {
654 	struct idtypes *idp;
655 	u_longlong_t invalue;
656 	char *ep = NULL;
657 
658 	if (type == NULL) {
659 		/* Shouldn't reach here, see callers for why. */
660 		FATAL(ep, ebuf, gettext("Unexpected end of command line, "
661 		    "was expecting a type.\n"));
662 	}
663 
664 	for (idp = idtypes; idp->idtype != NULL; idp++) {
665 		if (strcasecmp(idp->idtype, type) == 0)
666 			return (idp->retval);
667 	}
668 	/*
669 	 * Since identity types are almost arbitrary, check for numeric
670 	 * algorithm values too.  PF_KEY can catch bad ones with EINVAL.
671 	 */
672 	invalue = parsenum(type, B_FALSE, ebuf);
673 	if (invalue != (u_longlong_t)-1 &&
674 	    (u_longlong_t)(invalue & (u_longlong_t)0xffff) == invalue)
675 		return ((uint16_t)invalue);
676 
677 
678 	ERROR1(ep, ebuf, gettext("Unknown identity type \"%s\"\n"), type);
679 
680 	handle_errors(ep, NULL, B_FALSE, B_FALSE);
681 	return (0);
682 }
683 
684 /*
685  * Parse an address off the command line.  Return length of sockaddr,
686  * and either return a hostent pointer (caller frees).  The new
687  * getipnodebyname() call does the Right Thing (TM), even with
688  * raw addresses (colon-separated IPv6 or dotted decimal IPv4).
689  */
690 
691 static struct {
692 	struct hostent he;
693 	char *addtl[2];
694 	} dummy;
695 static union {
696 	struct in6_addr ipv6;
697 	struct in_addr ipv4;
698 	uint64_t aligner;
699 } addr1;
700 
701 static int
702 parseaddr(char *addr, struct hostent **hpp, boolean_t v6only, char *ebuf)
703 {
704 	int hp_errno;
705 	struct hostent *hp = NULL;
706 	char *ep = NULL;
707 
708 	if (addr == NULL) {
709 		FATAL(ep, ebuf, gettext("Unexpected end of command line, "
710 		    "was expecting an address.\n"));
711 	}
712 
713 	if (!nflag) {
714 		/*
715 		 * Try name->address first.  Assume AF_INET6, and
716 		 * get IPv4's, plus IPv6's if and only if IPv6 is configured.
717 		 * This means to add IPv6 SAs, you must have IPv6
718 		 * up-and-running.  (AI_DEFAULT works here.)
719 		 */
720 		hp = getipnodebyname(addr, AF_INET6,
721 		    (v6only ? AI_ADDRCONFIG : (AI_DEFAULT | AI_ALL)),
722 		    &hp_errno);
723 	} else {
724 		/*
725 		 * Try a normal address conversion only.  Use "dummy"
726 		 * to construct a fake hostent.  Caller will know not
727 		 * to free this one.
728 		 */
729 		if (inet_pton(AF_INET6, addr, &addr1) == 1) {
730 			dummy.he.h_addr_list = dummy.addtl;
731 			dummy.addtl[0] = (char *)&addr1;
732 			dummy.addtl[1] = NULL;
733 			hp = &dummy.he;
734 			dummy.he.h_addrtype = AF_INET6;
735 			dummy.he.h_length = sizeof (struct in6_addr);
736 		} else if (inet_pton(AF_INET, addr, &addr1) == 1) {
737 			/*
738 			 * Remap to AF_INET6 anyway.
739 			 */
740 			dummy.he.h_addr_list = dummy.addtl;
741 			dummy.addtl[0] = (char *)&addr1;
742 			dummy.addtl[1] = NULL;
743 			hp = &dummy.he;
744 			dummy.he.h_addrtype = AF_INET6;
745 			dummy.he.h_length = sizeof (struct in6_addr);
746 			/*
747 			 * NOTE:  If macro changes to disallow in-place
748 			 * conversion, rewhack this.
749 			 */
750 			IN6_INADDR_TO_V4MAPPED(&addr1.ipv4, &addr1.ipv6);
751 		} else {
752 			hp = NULL;
753 		}
754 	}
755 
756 	if (hp == NULL)
757 		WARN1(ep, ebuf, gettext("Unknown address %s."), addr);
758 
759 	*hpp = hp;
760 	/* Always return sockaddr_in6 for now. */
761 	handle_errors(ep, NULL, B_FALSE, B_FALSE);
762 	return (sizeof (struct sockaddr_in6));
763 }
764 
765 /*
766  * Parse a hex character for a key.  A string will take the form:
767  *	xxxxxxxxx/nn
768  * where
769  *	xxxxxxxxx == a string of hex characters ([0-9][a-f][A-F])
770  *	nn == an optional decimal "mask".  If it is not present, it
771  *	is assumed that the hex string will be rounded to the nearest
772  *	byte, where odd nibbles, like 123 will become 0x0123.
773  *
774  * NOTE:Unlike the expression of IP addresses, I will not allow an
775  *	excessive "mask".  For example 2112/50 is very illegal.
776  * NOTE2:	This key should be in canonical order.  Consult your man
777  *		pages per algorithm about said order.
778  */
779 
780 #define	hd2num(hd) (((hd) >= '0' && (hd) <= '9') ? ((hd) - '0') : \
781 	(((hd) >= 'a' && (hd) <= 'f') ? ((hd) - 'a' + 10) : ((hd) - 'A' + 10)))
782 
783 static struct sadb_key *
784 parsekey(char *input, char *ebuf)
785 {
786 	struct sadb_key *retval;
787 	uint_t i, hexlen = 0, bits, alloclen;
788 	uint8_t *key;
789 	char *ep = NULL;
790 
791 	if (input == NULL) {
792 		FATAL(ep, ebuf, gettext("Unexpected end of command line, "
793 		    "was expecting a key.\n"));
794 	}
795 	/* Allow hex values prepended with 0x convention */
796 	if ((strnlen(input, sizeof (hexlen)) > 2) &&
797 	    (strncasecmp(input, "0x", 2) == 0))
798 		input += 2;
799 
800 	for (i = 0; input[i] != '\0' && input[i] != '/'; i++)
801 		hexlen++;
802 
803 	if (input[i] == '\0') {
804 		bits = 0;
805 	} else {
806 		/* Have /nn. */
807 		input[i] = '\0';
808 		if (sscanf((input + i + 1), "%u", &bits) != 1) {
809 			FATAL1(ep, ebuf, gettext(
810 			    "\"%s\" is not a bit specifier.\n"),
811 			    (input + i + 1));
812 		}
813 		/* hexlen in nibbles */
814 		if (((bits + 3) >> 2) > hexlen) {
815 			ERROR2(ep, ebuf, gettext(
816 			    "bit length %d is too big for %s.\n"), bits, input);
817 		}
818 		/*
819 		 * Adjust hexlen down if user gave us too small of a bit
820 		 * count.
821 		 */
822 		if ((hexlen << 2) > bits + 3) {
823 			WARN2(ep, ebuf, gettext(
824 			    "WARNING: Lower bits will be truncated "
825 			    "for:\n\t%s/%d.\n"), input, bits);
826 			hexlen = (bits + 3) >> 2;
827 			input[hexlen] = '\0';
828 		}
829 	}
830 
831 	/*
832 	 * Allocate.  Remember, hexlen is in nibbles.
833 	 */
834 
835 	alloclen = sizeof (*retval) + roundup((hexlen/2 + (hexlen & 0x1)), 8);
836 	retval = malloc(alloclen);
837 
838 	if (retval == NULL)
839 		Bail("malloc(parsekey)");
840 	retval->sadb_key_len = SADB_8TO64(alloclen);
841 	retval->sadb_key_reserved = 0;
842 	if (bits == 0)
843 		retval->sadb_key_bits = (hexlen + (hexlen & 0x1)) << 2;
844 	else
845 		retval->sadb_key_bits = bits;
846 
847 	/*
848 	 * Read in nibbles.  Read in odd-numbered as shifted high.
849 	 * (e.g. 123 becomes 0x1230).
850 	 */
851 
852 	key = (uint8_t *)(retval + 1);
853 	for (i = 0; input[i] != '\0'; i += 2) {
854 		boolean_t second = (input[i + 1] != '\0');
855 
856 		if (!isxdigit(input[i]) ||
857 		    (!isxdigit(input[i + 1]) && second)) {
858 			ERROR1(ep, ebuf, gettext(
859 			    "string '%s' not a hex value.\n"), input);
860 			free(retval);
861 			retval = NULL;
862 			break;
863 		}
864 		*key = (hd2num(input[i]) << 4);
865 		if (second)
866 			*key |= hd2num(input[i + 1]);
867 		else
868 			break;	/* out of for loop. */
869 		key++;
870 	}
871 
872 	/* bzero the remaining bits if we're a non-octet amount. */
873 	if (bits & 0x7)
874 		*((input[i] == '\0') ? key - 1 : key) &=
875 		    0xff << (8 - (bits & 0x7));
876 
877 	handle_errors(ep, NULL, B_FALSE, B_FALSE);
878 	return (retval);
879 }
880 
881 /*
882  * Write a message to the PF_KEY socket.  If verbose, print the message
883  * heading into the kernel.
884  */
885 static int
886 key_write(int fd, void *msg, size_t len)
887 {
888 	if (vflag) {
889 		(void) printf(
890 		    gettext("VERBOSE ON:  Message to kernel looks like:\n"));
891 		(void) printf("==========================================\n");
892 		print_samsg(stdout, msg, B_FALSE, vflag, nflag);
893 		(void) printf("==========================================\n");
894 	}
895 
896 	return (write(fd, msg, len));
897 }
898 
899 /*
900  * SIGALRM handler for time_critical_enter.
901  */
902 static void
903 time_critical_catch(int signal)
904 {
905 	if (signal == SIGALRM) {
906 		errx(1, gettext("Reply message from PF_KEY timed out."));
907 	} else {
908 		errx(1, gettext("Caught signal %d while trying to receive"
909 		    "PF_KEY reply message"), signal);
910 	}
911 	/* errx() calls exit. */
912 }
913 
914 #define	TIME_CRITICAL_TIME 10	/* In seconds */
915 
916 /*
917  * Enter a "time critical" section where key is waiting for a return message.
918  */
919 static void
920 time_critical_enter(void)
921 {
922 	(void) signal(SIGALRM, time_critical_catch);
923 	(void) alarm(TIME_CRITICAL_TIME);
924 }
925 
926 /*
927  * Exit the "time critical" section after getting an appropriate return
928  * message.
929  */
930 static void
931 time_critical_exit(void)
932 {
933 	(void) alarm(0);
934 	(void) signal(SIGALRM, SIG_DFL);
935 }
936 
937 /*
938  * Construct a PF_KEY FLUSH message for the SA type specified.
939  */
940 static void
941 doflush(int satype)
942 {
943 	struct sadb_msg msg;
944 	int rc;
945 
946 	msg_init(&msg, SADB_FLUSH, (uint8_t)satype);
947 	rc = key_write(keysock, &msg, sizeof (msg));
948 	if (rc == -1)
949 		Bail("write() to PF_KEY socket failed (in doflush)");
950 
951 	time_critical_enter();
952 	do {
953 		rc = read(keysock, &msg, sizeof (msg));
954 		if (rc == -1)
955 			Bail("read (in doflush)");
956 	} while (msg.sadb_msg_seq != seq || msg.sadb_msg_pid != mypid);
957 	time_critical_exit();
958 
959 	/*
960 	 * I should _never_ hit the following unless:
961 	 *
962 	 * 1. There is a kernel bug.
963 	 * 2. There is another process filling in its pid with mine, and
964 	 *    issuing a different message that would cause a different result.
965 	 */
966 	if (msg.sadb_msg_type != SADB_FLUSH ||
967 	    msg.sadb_msg_satype != (uint8_t)satype) {
968 		syslog((LOG_NOTICE|LOG_AUTH),
969 		    gettext("doflush: Return message not of type SADB_FLUSH!"));
970 		Bail("doflush: Return message not of type SADB_FLUSH!");
971 	}
972 
973 	if (msg.sadb_msg_errno != 0) {
974 		errno = msg.sadb_msg_errno;
975 		if (errno == EINVAL) {
976 			print_diagnostic(stderr, msg.sadb_x_msg_diagnostic);
977 			warnx(gettext("Cannot flush SA type %d."), satype);
978 		}
979 		Bail("return message (in doflush)");
980 	}
981 }
982 
983 /*
984  * save_XXX functions are used when "saving" the SA tables to either a
985  * file or standard output.  They use the dump_XXX functions where needed,
986  * but mostly they use the rparseXXX functions.
987  */
988 
989 /*
990  * Because "save" and "dump" both use the SADB_DUMP message, fold both
991  * into the same function.
992  */
993 static void
994 dodump(int satype, FILE *ofile)
995 {
996 	struct sadb_msg *msg = (struct sadb_msg *)get_buffer;
997 	int rc;
998 
999 	if (ofile != NULL) {
1000 		(void) fprintf(ofile,
1001 		    gettext("# This key file was generated by the"));
1002 		(void) fprintf(ofile,
1003 		    gettext(" ipseckey(1m) command's 'save' feature.\n\n"));
1004 	}
1005 	msg_init(msg, SADB_DUMP, (uint8_t)satype);
1006 	rc = key_write(keysock, msg, sizeof (*msg));
1007 	if (rc == -1)
1008 		Bail("write to PF_KEY socket failed (in dodump)");
1009 
1010 	do {
1011 		/*
1012 		 * For DUMP, do only the read as a time critical section.
1013 		 */
1014 		time_critical_enter();
1015 		rc = read(keysock, get_buffer, sizeof (get_buffer));
1016 		time_critical_exit();
1017 		if (rc == -1)
1018 			Bail("read (in dodump)");
1019 		if (msg->sadb_msg_pid == mypid &&
1020 		    msg->sadb_msg_type == SADB_DUMP &&
1021 		    msg->sadb_msg_seq != 0 &&
1022 		    msg->sadb_msg_errno == 0) {
1023 			if (ofile == NULL) {
1024 				print_samsg(stdout, get_buffer, B_FALSE, vflag,
1025 				    nflag);
1026 				(void) putchar('\n');
1027 			} else {
1028 				save_assoc(get_buffer, ofile);
1029 			}
1030 		}
1031 	} while (msg->sadb_msg_pid != mypid ||
1032 	    (msg->sadb_msg_errno == 0 && msg->sadb_msg_seq != 0));
1033 
1034 	if (ofile != NULL && ofile != stdout)
1035 		(void) fclose(ofile);
1036 
1037 	if (msg->sadb_msg_errno == 0) {
1038 		if (ofile == NULL)
1039 			(void) printf(
1040 			    gettext("Dump succeeded for SA type %d.\n"),
1041 			    satype);
1042 	} else {
1043 		print_diagnostic(stderr, msg->sadb_x_msg_diagnostic);
1044 		errno = msg->sadb_msg_errno;
1045 		Bail("Dump failed");
1046 	}
1047 }
1048 
1049 #define	SCOPE_UNSPEC 0
1050 #define	SCOPE_LINKLOCAL 1
1051 #define	SCOPE_SITELOCAL 2
1052 #define	SCOPE_GLOBAL 3
1053 #define	SCOPE_V4COMPAT 4
1054 #define	SCOPE_LOOPBACK 5	/* Pedantic, yes, but necessary. */
1055 
1056 static int
1057 ipv6_addr_scope(struct in6_addr *addr)
1058 {
1059 	/* Don't return anything regarding multicast for now... */
1060 
1061 	if (IN6_IS_ADDR_UNSPECIFIED(addr))
1062 		return (SCOPE_UNSPEC);
1063 
1064 	if (IN6_IS_ADDR_LINKLOCAL(addr))
1065 		return (SCOPE_LINKLOCAL);
1066 
1067 	if (IN6_IS_ADDR_SITELOCAL(addr))
1068 		return (SCOPE_SITELOCAL);
1069 
1070 	if (IN6_IS_ADDR_V4COMPAT(addr))
1071 		return (SCOPE_V4COMPAT);
1072 
1073 	if (IN6_IS_ADDR_LOOPBACK(addr))
1074 		return (SCOPE_LOOPBACK);
1075 
1076 	/* For now, return global by default. */
1077 	return (SCOPE_GLOBAL);
1078 }
1079 
1080 /*
1081  * doaddresses():
1082  *
1083  * Used by doaddup() and dodelget() to create new SA's based on the
1084  * provided source and destination addresses hostent.
1085  *
1086  * sadb_msg_type: expected PF_KEY reply message type
1087  * sadb_msg_satype: expected PF_KEY reply satype
1088  * cmd: user command
1089  * srchp: hostent for the source address(es)
1090  * dsthp: hostent for the destination address(es)
1091  * src: points to the SADB source address extension
1092  * dst: points to the SADB destination address extension
1093  * unspec_src: indicates an unspecified source address.
1094  * buffer: pointer to the SADB buffer to use with PF_KEY
1095  * buffer_size: size of buffer
1096  * spi: spi for this message (set by caller)
1097  * srcport: source port if specified
1098  * dstport: destination port if specified
1099  * proto: IP protocol number if specified
1100  * iproto: Inner (tunnel mode) IP protocol number if specified
1101  * NATT note: we are going to assume a semi-sane world where NAT
1102  * boxen don't explode to multiple addresses.
1103  */
1104 static void
1105 doaddresses(uint8_t sadb_msg_type, uint8_t sadb_msg_satype, int cmd,
1106     struct hostent *srchp, struct hostent *dsthp,
1107     struct sadb_address *src, struct sadb_address *dst,
1108     boolean_t unspec_src, uint64_t *buffer, int buffer_size, uint32_t spi,
1109     char *ebuf)
1110 {
1111 	boolean_t single_dst;
1112 	struct sockaddr_in6 *sin6;
1113 	struct sadb_msg *msgp;
1114 	int i, rc;
1115 	char **walker;	/* For the SRC and PROXY walking functions. */
1116 	char *first_match;
1117 	uint64_t savebuf[MAX_GET_SIZE];
1118 	uint16_t srcport = 0, dstport = 0;
1119 	char *ep = NULL;
1120 
1121 	/*
1122 	 * Okay, now we have "src", "dst", and maybe "proxy" reassigned
1123 	 * to point into the buffer to be written to PF_KEY, we can do
1124 	 * potentially several writes based on destination address.
1125 	 *
1126 	 * First, obtain port numbers from passed-in extensions.
1127 	 */
1128 
1129 	if (src != NULL) {
1130 		sin6 = (struct sockaddr_in6 *)(src + 1);
1131 		srcport = ntohs(sin6->sin6_port);
1132 	}
1133 	if (dst != NULL) {
1134 		sin6 = (struct sockaddr_in6 *)(dst + 1);
1135 		dstport = ntohs(sin6->sin6_port);
1136 	}
1137 
1138 	/*
1139 	 * The rules for ADD, GET, and UPDATE: (NOTE:  This assumes IPsec.
1140 	 * If other consumers of PF_KEY happen, this will have to be
1141 	 * rewhacked.):
1142 	 *
1143 	 *	Do a message for every possible DST address.
1144 	 *
1145 	 *	If a source or proxy address explodes, keep unspecified
1146 	 *	(and mention unspecified).
1147 	 *
1148 	 * If dsthp is == dummy.he, then go through the loop once.
1149 	 * If any other hp is == dummy.he, then you don't have to apply any
1150 	 * silly rules.
1151 	 *
1152 	 * DELETE is different, because you can leave either "src" or "dst"
1153 	 * blank!  You need to explode if one of them is full, and not assume
1154 	 * that the other is set.
1155 	 */
1156 
1157 	if (dsthp == NULL) {
1158 		/*
1159 		 * No destination address specified.
1160 		 * With extended diagnostics, we don't have to bail the
1161 		 * non-DELETE cases here.  The EINVAL diagnostics will be
1162 		 * enough to inform the user(s) what happened.
1163 		 */
1164 		i = 0;
1165 		do {
1166 			if (srchp == &dummy.he) {
1167 				/* Just to be sure... */
1168 				srchp->h_addr_list[1] = NULL;
1169 			} else if (srchp != NULL) {
1170 				/* Degenerate case, h_addr_list[0] == NULL. */
1171 				if (srchp->h_addr_list[i] == NULL)
1172 					Bail("Empty source address list");
1173 
1174 				/*
1175 				 * Fill in the src sockaddr.
1176 				 */
1177 				sin6 = (struct sockaddr_in6 *)(src + 1);
1178 				bzero(sin6, sizeof (*sin6));
1179 				bcopy(srchp->h_addr_list[i], &sin6->sin6_addr,
1180 				    sizeof (struct in6_addr));
1181 				sin6->sin6_family = AF_INET6;
1182 				sin6->sin6_port = htons(srcport);
1183 			}
1184 
1185 			/* Save off a copy for later writing... */
1186 			msgp = (struct sadb_msg *)buffer;
1187 			bcopy(buffer, savebuf, SADB_64TO8(msgp->sadb_msg_len));
1188 
1189 			rc = key_write(keysock, buffer,
1190 			    SADB_64TO8(msgp->sadb_msg_len));
1191 			if (rc == -1)
1192 				Bail("write() to PF_KEY socket "
1193 				    "(in doaddresses)");
1194 
1195 			time_critical_enter();
1196 			do {
1197 				rc = read(keysock, buffer, buffer_size);
1198 				if (rc == -1)
1199 					Bail("read (in doaddresses)");
1200 			} while (msgp->sadb_msg_seq != seq ||
1201 			    msgp->sadb_msg_pid != mypid);
1202 			time_critical_exit();
1203 
1204 			if (msgp->sadb_msg_type != sadb_msg_type ||
1205 			    msgp->sadb_msg_satype != sadb_msg_satype) {
1206 				syslog((LOG_NOTICE|LOG_AUTH), gettext(
1207 				    "doaddresses: Unexpected returned message "
1208 				    "(%d exp %d)\n"), msgp->sadb_msg_type,
1209 				    sadb_msg_type);
1210 				Bail("doaddresses: Unexpected returned "
1211 				    "message");
1212 			}
1213 
1214 			errno = msgp->sadb_msg_errno;
1215 			if (errno != 0) {
1216 				if (errno == EINVAL) {
1217 					WARN(ep, ebuf, gettext(
1218 					    "One of the entered "
1219 					    "values is incorrect."));
1220 					print_diagnostic(stderr,
1221 					    msgp->sadb_x_msg_diagnostic);
1222 				} else {
1223 					Bail("return message (in doaddresses)");
1224 				}
1225 			}
1226 
1227 			/* ...and then restore the saved buffer. */
1228 			msgp = (struct sadb_msg *)savebuf;
1229 			bcopy(savebuf, buffer, SADB_64TO8(msgp->sadb_msg_len));
1230 		} while (srchp != NULL && srchp->h_addr_list[++i] != NULL);
1231 		return;
1232 	}
1233 
1234 	single_dst = (dsthp == &dummy.he || dsthp->h_addr_list[1] == NULL);
1235 
1236 	for (i = 0; dsthp->h_addr_list[i] != NULL; i++) {
1237 		if (dsthp == &dummy.he) {
1238 			/* Just to be sure... */
1239 			dsthp->h_addr_list[1] = NULL;
1240 		} else {
1241 			/*
1242 			 * Fill in the dst sockaddr.
1243 			 */
1244 			sin6 = (struct sockaddr_in6 *)(dst + 1);
1245 			bzero(sin6, sizeof (*sin6));
1246 			bcopy(dsthp->h_addr_list[i], &sin6->sin6_addr,
1247 			    sizeof (struct in6_addr));
1248 			sin6->sin6_family = AF_INET6;
1249 			sin6->sin6_port = htons(dstport);
1250 		}
1251 
1252 		/*
1253 		 * Try and assign src, if there's any ambiguity.
1254 		 */
1255 		if (!unspec_src && srchp != &dummy.he) {
1256 			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1257 				/*
1258 				 * IPv4 address.  Find an IPv4 address, then
1259 				 * keep looking for a second one.  If a second
1260 				 * exists, print a message, and fill in the
1261 				 * unspecified address.
1262 				 */
1263 				first_match = NULL;
1264 
1265 				for (walker = srchp->h_addr_list;
1266 				    *walker != NULL; walker++) {
1267 					/* LINTED E_BAD_PTR_CAST_ALIGN */
1268 					if (IN6_IS_ADDR_V4MAPPED(
1269 					    (struct in6_addr *)*walker)) {
1270 						if (first_match != NULL)
1271 							break;
1272 						else
1273 							first_match = *walker;
1274 					}
1275 				}
1276 				sin6 = (struct sockaddr_in6 *)(src + 1);
1277 				bzero(sin6, sizeof (*sin6));
1278 
1279 				if (first_match == NULL) {
1280 					/*
1281 					 * No IPv4 hits.  Is this a single
1282 					 * dest?
1283 					 */
1284 					WARN1(ep, ebuf, gettext(
1285 					    "No IPv4 source address "
1286 					    "for name %s.\n"), srchp->h_name);
1287 					if (single_dst) {
1288 						ERROR(ep, ebuf, gettext(
1289 						    "Only single destination "
1290 						    "IP address.\n"));
1291 					} else {
1292 						/* Continue, but do I print? */
1293 						continue;  /* for loop */
1294 					}
1295 
1296 					/* I should never reach here. */
1297 				}
1298 
1299 				sin6->sin6_family = AF_INET6;
1300 				sin6->sin6_port = htons(srcport);
1301 				if (*walker != NULL) {
1302 					/*
1303 					 * Early loop exit.  It must've been
1304 					 * multiple hits...
1305 					 *
1306 					 * Issue a null-source warning?
1307 					 */
1308 					WARN1(ep, ebuf, gettext(
1309 					    "Multiple IPv4 source addresses "
1310 					    "for %s, using unspecified source "
1311 					    "instead."), srchp->h_name);
1312 				} else {
1313 					/*
1314 					 * If I reach here w/o hitting the
1315 					 * previous if statements, I have a
1316 					 * single source address for this
1317 					 * destination.
1318 					 */
1319 					bcopy(first_match, &sin6->sin6_addr,
1320 					    sizeof (struct in6_addr));
1321 				}
1322 			} else {
1323 				/*
1324 				 * IPv6 address.  Find an IPv6 address.
1325 				 * Unlike IPv4 addresses, things can get a
1326 				 * little more sticky with scopes, etc.
1327 				 */
1328 				int dst_scope, src_scope;
1329 
1330 				dst_scope = ipv6_addr_scope(&sin6->sin6_addr);
1331 
1332 				first_match = NULL;
1333 				for (walker = srchp->h_addr_list;
1334 				    *walker != NULL; walker++) {
1335 					/* LINTED E_BAD_PTR_CAST_ALIGN */
1336 					if (!IN6_IS_ADDR_V4MAPPED(
1337 					    (struct in6_addr *)*walker)) {
1338 						/*
1339 						 * Set first-match, etc.
1340 						 * Take into account scopes,
1341 						 * and other IPv6 thingies.
1342 						 */
1343 						src_scope = ipv6_addr_scope(
1344 						    /* LINTED E_BAD_PTR_CAST */
1345 						    (struct in6_addr *)*walker);
1346 						if (src_scope == SCOPE_UNSPEC ||
1347 						    src_scope == dst_scope) {
1348 							if (first_match !=
1349 							    NULL)
1350 								break;
1351 							else
1352 								first_match =
1353 								    *walker;
1354 						}
1355 					}
1356 				}
1357 
1358 				sin6 = (struct sockaddr_in6 *)(src + 1);
1359 				bzero(sin6, sizeof (*sin6));
1360 				sin6->sin6_port = htons(srcport);
1361 				if (first_match == NULL) {
1362 					/*
1363 					 * No IPv6 hits.  Is this a single
1364 					 * dest?
1365 					 */
1366 					WARN1(ep, ebuf, gettext(
1367 					    "No IPv6 source address of "
1368 					    "matching scope for name %s.\n"),
1369 					    srchp->h_name);
1370 					if (single_dst) {
1371 						ERROR(ep, ebuf, gettext(
1372 						    "Only a single IPV6 "
1373 						    "destination "
1374 						    "address.\n"));
1375 					} else {
1376 						/* Continue, but do I print? */
1377 						continue;  /* for loop */
1378 					}
1379 
1380 					/* I should never reach here. */
1381 				}
1382 				sin6->sin6_family = AF_INET6;
1383 				if (*walker != NULL) {
1384 					/*
1385 					 * Early loop exit.  Issue a
1386 					 * null-source warning?
1387 					 */
1388 					WARN1(ep, ebuf, gettext(
1389 					    "Multiple IPv6 source addresses "
1390 					    "for %s of the same scope, using "
1391 					    "unspecified source instead.\n"),
1392 					    srchp->h_name);
1393 				} else {
1394 					/*
1395 					 * If I reach here w/o hitting the
1396 					 * previous if statements, I have a
1397 					 * single source address for this
1398 					 * destination.
1399 					 */
1400 					bcopy(first_match, &sin6->sin6_addr,
1401 					    sizeof (struct in6_addr));
1402 				}
1403 			}
1404 		}
1405 
1406 		/*
1407 		 * If there are errors at this point there is no
1408 		 * point sending anything to PF_KEY.
1409 		 */
1410 		handle_errors(ep, ebuf, B_TRUE, B_FALSE);
1411 
1412 		/* Save off a copy for later writing... */
1413 		msgp = (struct sadb_msg *)buffer;
1414 		bcopy(buffer, savebuf, SADB_64TO8(msgp->sadb_msg_len));
1415 
1416 		rc = key_write(keysock, buffer, SADB_64TO8(msgp->sadb_msg_len));
1417 		if (rc == -1)
1418 			Bail("write() to PF_KEY socket (in doaddresses)");
1419 
1420 		/* Blank the key for paranoia's sake. */
1421 		bzero(buffer, buffer_size);
1422 		time_critical_enter();
1423 		do {
1424 			rc = read(keysock, buffer, buffer_size);
1425 			if (rc == -1)
1426 				Bail("read (in doaddresses)");
1427 		} while (msgp->sadb_msg_seq != seq ||
1428 		    msgp->sadb_msg_pid != mypid);
1429 		time_critical_exit();
1430 
1431 		/*
1432 		 * I should _never_ hit the following unless:
1433 		 *
1434 		 * 1. There is a kernel bug.
1435 		 * 2. Another process is mistakenly using my pid in a PF_KEY
1436 		 *    message.
1437 		 */
1438 		if (msgp->sadb_msg_type != sadb_msg_type ||
1439 		    msgp->sadb_msg_satype != sadb_msg_satype) {
1440 			syslog((LOG_NOTICE|LOG_AUTH), gettext(
1441 			    "doaddresses: Unexpected returned message "
1442 			    "(%d exp %d)\n"), msgp->sadb_msg_type,
1443 			    sadb_msg_type);
1444 			Bail("doaddresses: Unexpected returned message");
1445 		}
1446 
1447 		if (msgp->sadb_msg_errno != 0) {
1448 			char addrprint[INET6_ADDRSTRLEN];
1449 			int on_errno = 0;
1450 			char *on_errno_msg;
1451 
1452 			/*
1453 			 * Print different error messages depending
1454 			 * on the SADB message type being processed.
1455 			 * If we get a ESRCH error for a GET/DELETE
1456 			 * messages, we report that the SA does not
1457 			 * exist. If we get a EEXIST error for a
1458 			 * ADD/UPDATE message, we report that the
1459 			 * SA already exists.
1460 			 */
1461 			if (sadb_msg_type == SADB_GET ||
1462 			    sadb_msg_type == SADB_DELETE) {
1463 				on_errno = ESRCH;
1464 				on_errno_msg = "does not exist";
1465 			} else if (sadb_msg_type == SADB_ADD ||
1466 			    sadb_msg_type == SADB_UPDATE) {
1467 				on_errno = EEXIST;
1468 				on_errno_msg = "already exists";
1469 			}
1470 
1471 			errno = msgp->sadb_msg_errno;
1472 			if (errno == on_errno) {
1473 				ERROR2(ep, ebuf, gettext(
1474 				    "Association (type = %s) "
1475 				    "with spi 0x%x and addr\n"),
1476 				    rparsesatype(msgp->sadb_msg_satype),
1477 				    ntohl(spi));
1478 				ERROR2(ep, ebuf, "%s %s.\n",
1479 				    do_inet_ntop(dsthp->h_addr_list[i],
1480 				    addrprint, sizeof (addrprint)),
1481 				    on_errno_msg);
1482 				msgp = (struct sadb_msg *)savebuf;
1483 				bcopy(savebuf, buffer,
1484 				    SADB_64TO8(msgp->sadb_msg_len));
1485 				continue;
1486 			} else {
1487 				if (errno == EINVAL || errno == ESRCH) {
1488 					ERROR2(ep, ebuf, gettext(
1489 					    "PF_KEY Diagnostic code %u: %s.\n"),
1490 					    msgp->sadb_x_msg_diagnostic,
1491 					    keysock_diag(
1492 					    msgp->sadb_x_msg_diagnostic));
1493 				} else {
1494 					Bail("return message (in doaddresses)");
1495 				}
1496 			}
1497 		}
1498 
1499 		if (cmd == CMD_GET) {
1500 			if (msgp->sadb_msg_len > MAX_GET_SIZE) {
1501 				WARN1(ep, ebuf, gettext("WARNING:  "
1502 				    "SA information bigger than %d bytes.\n"),
1503 				    SADB_64TO8(MAX_GET_SIZE));
1504 			}
1505 			print_samsg(stdout, buffer, B_FALSE, vflag, nflag);
1506 		}
1507 
1508 		handle_errors(ep, ebuf, B_TRUE, B_FALSE);
1509 
1510 		/* ...and then restore the saved buffer. */
1511 		msgp = (struct sadb_msg *)savebuf;
1512 		bcopy(savebuf, buffer, SADB_64TO8(msgp->sadb_msg_len));
1513 		lines_added++;
1514 	}
1515 
1516 	/* Degenerate case, h_addr_list[0] == NULL. */
1517 	if (i == 0)
1518 		Bail("Empty destination address list");
1519 
1520 	/*
1521 	 * free(ebuf) even if there are no errors.
1522 	 * handle_errors() won't return here.
1523 	 */
1524 	handle_errors(ep, ebuf, B_TRUE, B_TRUE);
1525 }
1526 
1527 /*
1528  * Perform an add or an update.  ADD and UPDATE are similar in the extensions
1529  * they need.
1530  */
1531 static void
1532 doaddup(int cmd, int satype, char *argv[], char *ebuf)
1533 {
1534 	uint64_t *buffer, *nexthdr;
1535 	struct sadb_msg msg;
1536 	struct sadb_sa *assoc = NULL;
1537 	struct sadb_x_pair *sadb_pair = NULL;
1538 	struct sadb_address *src = NULL, *dst = NULL;
1539 	struct sadb_address *isrc = NULL, *idst = NULL;
1540 	struct sadb_address *natt_local = NULL, *natt_remote = NULL;
1541 	struct sadb_key *encrypt = NULL, *auth = NULL;
1542 	struct sadb_ident *srcid = NULL, *dstid = NULL;
1543 	struct sadb_lifetime *hard = NULL, *soft = NULL;  /* Current? */
1544 	struct sockaddr_in6 *sin6;
1545 	/* MLS TODO:  Need sensitivity eventually. */
1546 	int next, token, sa_len, alloclen, totallen = sizeof (msg), prefix;
1547 	uint32_t spi = 0;
1548 	uint8_t	sadb_msg_type;
1549 	char *thiscmd, *pstr;
1550 	boolean_t readstate = B_FALSE, unspec_src = B_FALSE;
1551 	boolean_t alloc_inner = B_FALSE, use_natt = B_FALSE;
1552 	struct hostent *srchp = NULL, *dsthp = NULL, *isrchp = NULL,
1553 	    *idsthp = NULL;
1554 	struct hostent *natt_lhp = NULL, *natt_rhp = NULL;
1555 	uint16_t srcport = 0, dstport = 0, natt_lport = 0, natt_rport = 0,
1556 	    isrcport = 0, idstport = 0;
1557 	uint8_t proto = 0, iproto = 0;
1558 	char *ep = NULL;
1559 
1560 	switch (cmd) {
1561 	case CMD_ADD:
1562 		thiscmd = "add";
1563 		sadb_msg_type = SADB_ADD;
1564 		break;
1565 	case CMD_UPDATE:
1566 		thiscmd = "update";
1567 		sadb_msg_type = SADB_UPDATE;
1568 		break;
1569 	case CMD_UPDATE_PAIR:
1570 		thiscmd = "update-pair";
1571 		sadb_msg_type = SADB_X_UPDATEPAIR;
1572 		break;
1573 	}
1574 
1575 	msg_init(&msg, sadb_msg_type, (uint8_t)satype);
1576 	/* Assume last element in argv is set to NULL. */
1577 	do {
1578 		token = parseextval(*argv, &next);
1579 		argv++;
1580 		switch (token) {
1581 		case TOK_EOF:
1582 			/* Do nothing, I'm done. */
1583 			break;
1584 		case TOK_UNKNOWN:
1585 			ERROR1(ep, ebuf, gettext(
1586 			    "Unknown extension field \"%s\" \n"), *(argv - 1));
1587 			break;
1588 		case TOK_SPI:
1589 		case TOK_PAIR_SPI:
1590 		case TOK_REPLAY:
1591 		case TOK_STATE:
1592 		case TOK_AUTHALG:
1593 		case TOK_ENCRALG:
1594 		case TOK_ENCAP:
1595 			/*
1596 			 * May want to place this chunk of code in a function.
1597 			 *
1598 			 * This code checks for duplicate entries on a command
1599 			 * line.
1600 			 */
1601 
1602 			/* Allocate the SADB_EXT_SA extension. */
1603 			if (assoc == NULL) {
1604 				assoc = malloc(sizeof (*assoc));
1605 				if (assoc == NULL)
1606 					Bail("malloc(assoc)");
1607 				bzero(assoc, sizeof (*assoc));
1608 				assoc->sadb_sa_exttype = SADB_EXT_SA;
1609 				assoc->sadb_sa_len =
1610 				    SADB_8TO64(sizeof (*assoc));
1611 				totallen += sizeof (*assoc);
1612 			}
1613 			switch (token) {
1614 			case TOK_SPI:
1615 				/*
1616 				 * If some cretin types in "spi 0" then he/she
1617 				 * can type in another SPI.
1618 				 */
1619 				if (assoc->sadb_sa_spi != 0) {
1620 					ERROR(ep, ebuf, gettext(
1621 					    "Can only specify "
1622 					    "single SPI value.\n"));
1623 					break;
1624 				}
1625 				/* Must convert SPI to network order! */
1626 				assoc->sadb_sa_spi =
1627 				    htonl((uint32_t)parsenum(*argv, B_TRUE,
1628 				    ebuf));
1629 				if (assoc->sadb_sa_spi == 0) {
1630 					ERROR(ep, ebuf, gettext(
1631 					    "Invalid SPI value \"0\" .\n"));
1632 				}
1633 				break;
1634 			case TOK_PAIR_SPI:
1635 				if (cmd == CMD_UPDATE_PAIR) {
1636 					ERROR(ep, ebuf, gettext(
1637 					    "pair-spi can not be used with the "
1638 					    "\"update-pair\" command.\n"));
1639 				}
1640 				if (sadb_pair == NULL) {
1641 					sadb_pair = malloc(sizeof (*sadb_pair));
1642 					if (assoc == NULL)
1643 						Bail("malloc(assoc)");
1644 					bzero(sadb_pair, sizeof (*sadb_pair));
1645 					totallen += sizeof (*sadb_pair);
1646 				}
1647 				if (sadb_pair->sadb_x_pair_spi != 0) {
1648 					ERROR(ep, ebuf, gettext(
1649 					    "Can only specify "
1650 					    "single pair SPI value.\n"));
1651 					break;
1652 				}
1653 				/* Must convert SPI to network order! */
1654 				sadb_pair->sadb_x_pair_len =
1655 				    SADB_8TO64(sizeof (*sadb_pair));
1656 				sadb_pair->sadb_x_pair_exttype =
1657 				    SADB_X_EXT_PAIR;
1658 				sadb_pair->sadb_x_pair_spi =
1659 				    htonl((uint32_t)parsenum(*argv, B_TRUE,
1660 				    ebuf));
1661 				if (sadb_pair->sadb_x_pair_spi == 0) {
1662 					ERROR(ep, ebuf, gettext(
1663 					    "Invalid SPI value \"0\" .\n"));
1664 				}
1665 				assoc->sadb_sa_flags |=
1666 				    SADB_X_SAFLAGS_PAIRED;
1667 				break;
1668 			case TOK_REPLAY:
1669 				/*
1670 				 * That same cretin can do the same with
1671 				 * replay.
1672 				 */
1673 				if (assoc->sadb_sa_replay != 0) {
1674 					ERROR(ep, ebuf, gettext(
1675 					    "Can only specify "
1676 					    "single replay window size.\n"));
1677 					break;
1678 				}
1679 				assoc->sadb_sa_replay =
1680 				    (uint8_t)parsenum(*argv, B_TRUE, ebuf);
1681 				if (assoc->sadb_sa_replay != 0) {
1682 					WARN(ep, ebuf, gettext(
1683 					    "WARNING:  Replay with manual"
1684 					    " keying considered harmful.\n"));
1685 				}
1686 				break;
1687 			case TOK_STATE:
1688 				/*
1689 				 * 0 is an actual state value, LARVAL.  This
1690 				 * means that one can type in the larval state
1691 				 * and then type in another state on the same
1692 				 * command line.
1693 				 */
1694 				if (assoc->sadb_sa_state != 0) {
1695 					ERROR(ep, ebuf, gettext(
1696 					    "Can only specify "
1697 					    "single SA state.\n"));
1698 					break;
1699 				}
1700 				assoc->sadb_sa_state = parsestate(*argv,
1701 				    ebuf);
1702 				readstate = B_TRUE;
1703 				break;
1704 			case TOK_AUTHALG:
1705 				if (assoc->sadb_sa_auth != 0) {
1706 					ERROR(ep, ebuf, gettext(
1707 					    "Can only specify "
1708 					    "single auth algorithm.\n"));
1709 					break;
1710 				}
1711 				assoc->sadb_sa_auth = parsealg(*argv,
1712 				    IPSEC_PROTO_AH, ebuf);
1713 				break;
1714 			case TOK_ENCRALG:
1715 				if (satype == SADB_SATYPE_AH) {
1716 					ERROR(ep, ebuf, gettext("Cannot specify"
1717 					    " encryption with SA type ah.\n"));
1718 					break;
1719 				}
1720 				if (assoc->sadb_sa_encrypt != 0) {
1721 					ERROR(ep, ebuf, gettext(
1722 					    "Can only specify "
1723 					    "single encryption algorithm.\n"));
1724 					break;
1725 				}
1726 				assoc->sadb_sa_encrypt = parsealg(*argv,
1727 				    IPSEC_PROTO_ESP, ebuf);
1728 				break;
1729 			case TOK_ENCAP:
1730 				if (use_natt) {
1731 					ERROR(ep, ebuf, gettext(
1732 					    "Can only specify single"
1733 					    " encapsulation.\n"));
1734 					break;
1735 				}
1736 				if (strncmp(*argv, "udp", 3)) {
1737 					ERROR(ep, ebuf, gettext(
1738 					    "Can only specify udp"
1739 					    " encapsulation.\n"));
1740 					break;
1741 				}
1742 				use_natt = B_TRUE;
1743 				/* set assoc flags later */
1744 				break;
1745 			}
1746 			argv++;
1747 			break;
1748 		case TOK_SRCPORT:
1749 			if (srcport != 0) {
1750 				ERROR(ep, ebuf,  gettext("Can only specify "
1751 				    "single source port.\n"));
1752 				break;
1753 			}
1754 			srcport = parsenum(*argv, B_TRUE, ebuf);
1755 			argv++;
1756 			break;
1757 		case TOK_DSTPORT:
1758 			if (dstport != 0) {
1759 				ERROR(ep, ebuf, gettext("Can only specify "
1760 				    "single destination port.\n"));
1761 				break;
1762 			}
1763 			dstport = parsenum(*argv, B_TRUE, ebuf);
1764 			argv++;
1765 			break;
1766 		case TOK_ISRCPORT:
1767 			alloc_inner = B_TRUE;
1768 			if (isrcport != 0) {
1769 				ERROR(ep, ebuf, gettext(
1770 				    "Can only specify "
1771 				    "single inner-source port.\n"));
1772 				break;
1773 			}
1774 			isrcport = parsenum(*argv, B_TRUE, ebuf);
1775 			argv++;
1776 			break;
1777 		case TOK_IDSTPORT:
1778 			alloc_inner = B_TRUE;
1779 			if (idstport != 0) {
1780 				ERROR(ep, ebuf, gettext(
1781 				    "Can only specify "
1782 				    "single inner-destination port.\n"));
1783 				break;
1784 			}
1785 			idstport = parsenum(*argv, B_TRUE, ebuf);
1786 			argv++;
1787 			break;
1788 		case TOK_NATLPORT:
1789 			if (natt_lport != 0) {
1790 				ERROR(ep, ebuf, gettext(
1791 				    "Can only specify "
1792 				    "single NAT-T local port.\n"));
1793 				break;
1794 			}
1795 			natt_lport = parsenum(*argv, B_TRUE, ebuf);
1796 			argv++;
1797 			break;
1798 		case TOK_NATRPORT:
1799 			if (natt_rport != 0) {
1800 				ERROR(ep, ebuf, gettext(
1801 				    "Can only specify "
1802 				    "single NAT-T remote port.\n"));
1803 				break;
1804 			}
1805 			natt_rport = parsenum(*argv, B_TRUE, ebuf);
1806 			argv++;
1807 			break;
1808 
1809 		case TOK_PROTO:
1810 			if (proto != 0) {
1811 				ERROR(ep, ebuf, gettext(
1812 				    "Can only specify "
1813 				    "single protocol.\n"));
1814 				break;
1815 			}
1816 			proto = parsenum(*argv, B_TRUE, ebuf);
1817 			argv++;
1818 			break;
1819 		case TOK_IPROTO:
1820 			alloc_inner = B_TRUE;
1821 			if (iproto != 0) {
1822 				ERROR(ep, ebuf, gettext(
1823 				    "Can only specify "
1824 				    "single inner protocol.\n"));
1825 				break;
1826 			}
1827 			iproto = parsenum(*argv, B_TRUE, ebuf);
1828 			argv++;
1829 			break;
1830 		case TOK_SRCADDR:
1831 		case TOK_SRCADDR6:
1832 			if (src != NULL) {
1833 				ERROR(ep, ebuf, gettext(
1834 				    "Can only specify "
1835 				    "single source address.\n"));
1836 				break;
1837 			}
1838 			sa_len = parseaddr(*argv, &srchp,
1839 			    (token == TOK_SRCADDR6), ebuf);
1840 			if (srchp == NULL) {
1841 				ERROR1(ep, ebuf, gettext(
1842 				    "Unknown src address \"%s\"\n"), *argv);
1843 				break;
1844 			}
1845 			argv++;
1846 			/*
1847 			 * Round of the sockaddr length to an 8 byte
1848 			 * boundary to make PF_KEY happy.
1849 			 */
1850 			alloclen = sizeof (*src) + roundup(sa_len, 8);
1851 			src = malloc(alloclen);
1852 			if (src == NULL)
1853 				Bail("malloc(src)");
1854 			totallen += alloclen;
1855 			src->sadb_address_len = SADB_8TO64(alloclen);
1856 			src->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
1857 			src->sadb_address_reserved = 0;
1858 			src->sadb_address_prefixlen = 0;
1859 			src->sadb_address_proto = 0;
1860 			if (srchp == &dummy.he) {
1861 				/*
1862 				 * Single address with -n flag.
1863 				 */
1864 				sin6 = (struct sockaddr_in6 *)(src + 1);
1865 				bzero(sin6, sizeof (*sin6));
1866 				sin6->sin6_family = AF_INET6;
1867 				bcopy(srchp->h_addr_list[0], &sin6->sin6_addr,
1868 				    sizeof (struct in6_addr));
1869 			}
1870 			break;
1871 		case TOK_DSTADDR:
1872 		case TOK_DSTADDR6:
1873 			if (dst != NULL) {
1874 				ERROR(ep, ebuf, gettext(
1875 				    "Can only specify single "
1876 				    "destination address.\n"));
1877 				break;
1878 			}
1879 			sa_len = parseaddr(*argv, &dsthp,
1880 			    (token == TOK_DSTADDR6), ebuf);
1881 			if (dsthp == NULL) {
1882 				ERROR1(ep, ebuf, gettext(
1883 				    "Unknown dst address \"%s\"\n"), *argv);
1884 				break;
1885 			}
1886 			argv++;
1887 			alloclen = sizeof (*dst) + roundup(sa_len, 8);
1888 			dst = malloc(alloclen);
1889 			if (dst == NULL)
1890 				Bail("malloc(dst)");
1891 			totallen += alloclen;
1892 			dst->sadb_address_len = SADB_8TO64(alloclen);
1893 			dst->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
1894 			dst->sadb_address_reserved = 0;
1895 			dst->sadb_address_prefixlen = 0;
1896 			dst->sadb_address_proto = 0;
1897 			if (dsthp == &dummy.he) {
1898 				/*
1899 				 * Single address with -n flag.
1900 				 */
1901 				sin6 = (struct sockaddr_in6 *)(dst + 1);
1902 				bzero(sin6, sizeof (*sin6));
1903 				sin6->sin6_family = AF_INET6;
1904 				bcopy(dsthp->h_addr_list[0], &sin6->sin6_addr,
1905 				    sizeof (struct in6_addr));
1906 			}
1907 			break;
1908 		case TOK_PROXYADDR:
1909 		case TOK_PROXYADDR6:
1910 			if (isrc != NULL) {
1911 				ERROR(ep, ebuf, gettext(
1912 				    "Can only specify single "
1913 				    "proxy/inner-source address.\n"));
1914 				break;
1915 			}
1916 			if ((pstr = strchr(*argv, '/')) != NULL) {
1917 				/* Parse out the prefix. */
1918 				errno = 0;
1919 				prefix = strtol(pstr + 1, NULL, 10);
1920 				if (errno != 0) {
1921 					ERROR1(ep, ebuf, gettext(
1922 					    "Invalid prefix %s."), pstr);
1923 					break;
1924 				}
1925 				/* Recycle pstr */
1926 				alloclen = (int)(pstr - *argv);
1927 				pstr = malloc(alloclen + 1);
1928 				if (pstr == NULL) {
1929 					Bail("malloc(pstr)");
1930 				}
1931 				(void) strlcpy(pstr, *argv, alloclen + 1);
1932 			} else {
1933 				pstr = *argv;
1934 				/*
1935 				 * Assume mapping to AF_INET6, and we're a host.
1936 				 * XXX some miscreants may still make classful
1937 				 * assumptions.  If this is a problem, fix it
1938 				 * here.
1939 				 */
1940 				prefix = 128;
1941 			}
1942 			sa_len = parseaddr(pstr, &isrchp,
1943 			    (token == TOK_PROXYADDR6), ebuf);
1944 			if (isrchp == NULL) {
1945 				ERROR1(ep, ebuf, gettext(
1946 				    "Unknown proxy/inner-source address "
1947 				    "\"%s\"\n"), *argv);
1948 				break;
1949 			}
1950 			if (pstr != *argv)
1951 				free(pstr);
1952 			argv++;
1953 			alloclen = sizeof (*isrc) + roundup(sa_len, 8);
1954 			isrc = malloc(alloclen);
1955 			if (isrc == NULL)
1956 				Bail("malloc(isrc)");
1957 			totallen += alloclen;
1958 			isrc->sadb_address_len = SADB_8TO64(alloclen);
1959 			isrc->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
1960 			isrc->sadb_address_reserved = 0;
1961 			isrc->sadb_address_prefixlen = prefix;
1962 			isrc->sadb_address_proto = 0;
1963 			if (isrchp == &dummy.he ||
1964 			    isrchp->h_addr_list[1] == NULL) {
1965 				/*
1966 				 * Single address with -n flag or single name.
1967 				 */
1968 				sin6 = (struct sockaddr_in6 *)(isrc + 1);
1969 				bzero(sin6, sizeof (*sin6));
1970 				sin6->sin6_family = AF_INET6;
1971 				bcopy(isrchp->h_addr_list[0], &sin6->sin6_addr,
1972 				    sizeof (struct in6_addr));
1973 				/*
1974 				 * normalize prefixlen for IPv4-mapped
1975 				 * addresses.
1976 				 */
1977 				if (prefix <= 32 &&
1978 				    IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
1979 					isrc->sadb_address_prefixlen += 96;
1980 				alloc_inner = B_TRUE;
1981 			} else {
1982 				/*
1983 				 * If the proxy/isrc address is vague, don't
1984 				 * bother.
1985 				 */
1986 				totallen -= alloclen;
1987 				free(isrc);
1988 				isrc = NULL;
1989 				WARN1(ep, ebuf, gettext(
1990 				    "Proxy/inner-source address %s "
1991 				    "is vague, not using.\n"), isrchp->h_name);
1992 				freehostent(isrchp);
1993 				isrchp = NULL;
1994 				break;
1995 			}
1996 			break;
1997 		case TOK_IDSTADDR:
1998 		case TOK_IDSTADDR6:
1999 			if (idst != NULL) {
2000 				ERROR(ep, ebuf, gettext(
2001 				    "Can only specify single "
2002 				    "inner-destination address.\n"));
2003 				break;
2004 			}
2005 			if ((pstr = strchr(*argv, '/')) != NULL) {
2006 				/* Parse out the prefix. */
2007 				errno = 0;
2008 				prefix = strtol(pstr + 1, NULL, 10);
2009 				if (errno != 0) {
2010 					ERROR1(ep, ebuf, gettext(
2011 					    "Invalid prefix %s.\n"), pstr);
2012 					break;
2013 				}
2014 				/* Recycle pstr */
2015 				alloclen = (int)(pstr - *argv);
2016 				pstr = malloc(alloclen + 1);
2017 				if (pstr == NULL) {
2018 					Bail("malloc(pstr)");
2019 				}
2020 				(void) strlcpy(pstr, *argv, alloclen + 1);
2021 			} else {
2022 				pstr = *argv;
2023 				/*
2024 				 * Assume mapping to AF_INET6, and we're a host.
2025 				 * XXX some miscreants may still make classful
2026 				 * assumptions.  If this is a problem, fix it
2027 				 * here.
2028 				 */
2029 				prefix = 128;
2030 			}
2031 			sa_len = parseaddr(pstr, &idsthp,
2032 			    (token == TOK_IDSTADDR6), ebuf);
2033 			if (idsthp == NULL) {
2034 				ERROR1(ep, ebuf, gettext(
2035 				    "Unknown Inner Src address "
2036 				    " \"%s\"\n"), *argv);
2037 				break;
2038 			}
2039 			if (pstr != *argv)
2040 				free(pstr);
2041 			argv++;
2042 			alloclen = sizeof (*idst) + roundup(sa_len, 8);
2043 			idst = malloc(alloclen);
2044 			if (idst == NULL)
2045 				Bail("malloc(idst)");
2046 			totallen += alloclen;
2047 			idst->sadb_address_len = SADB_8TO64(alloclen);
2048 			idst->sadb_address_exttype =
2049 			    SADB_X_EXT_ADDRESS_INNER_DST;
2050 			idst->sadb_address_reserved = 0;
2051 			idst->sadb_address_prefixlen = prefix;
2052 			idst->sadb_address_proto = 0;
2053 			if (idsthp == &dummy.he ||
2054 			    idsthp->h_addr_list[1] == NULL) {
2055 				/*
2056 				 * Single address with -n flag or single name.
2057 				 */
2058 				sin6 = (struct sockaddr_in6 *)(idst + 1);
2059 				bzero(sin6, sizeof (*sin6));
2060 				sin6->sin6_family = AF_INET6;
2061 				bcopy(idsthp->h_addr_list[0], &sin6->sin6_addr,
2062 				    sizeof (struct in6_addr));
2063 				/*
2064 				 * normalize prefixlen for IPv4-mapped
2065 				 * addresses.
2066 				 */
2067 				if (prefix <= 32 &&
2068 				    IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
2069 					idst->sadb_address_prefixlen += 96;
2070 				alloc_inner = B_TRUE;
2071 			} else {
2072 				/*
2073 				 * If the idst address is vague, don't bother.
2074 				 */
2075 				totallen -= alloclen;
2076 				free(idst);
2077 				idst = NULL;
2078 				WARN1(ep, ebuf, gettext(
2079 				    "Inner destination address %s "
2080 				    "is vague, not using.\n"), idsthp->h_name);
2081 				freehostent(idsthp);
2082 				idsthp = NULL;
2083 				break;
2084 			}
2085 			break;
2086 		case TOK_NATLOC:
2087 			if (natt_local != NULL) {
2088 				ERROR(ep, ebuf, gettext(
2089 				    "Can only specify "
2090 				    "single NAT-T local address.\n"));
2091 				break;
2092 			}
2093 			sa_len = parseaddr(*argv, &natt_lhp, 0, ebuf);
2094 			if (natt_lhp == NULL) {
2095 				ERROR1(ep, ebuf, gettext(
2096 				    "Unknown NAT-T local address \"%s\"\n"),
2097 				    *argv);
2098 				break;
2099 			}
2100 			argv++;
2101 			/*
2102 			 * Round of the sockaddr length to an 8 byte
2103 			 * boundary to make PF_KEY happy.
2104 			 */
2105 			alloclen = sizeof (*natt_local) + roundup(sa_len, 8);
2106 			natt_local = malloc(alloclen);
2107 			if (natt_local == NULL)
2108 				Bail("malloc(natt_local)");
2109 			totallen += alloclen;
2110 			natt_local->sadb_address_len = SADB_8TO64(alloclen);
2111 			natt_local->sadb_address_exttype =
2112 			    SADB_X_EXT_ADDRESS_NATT_LOC;
2113 			natt_local->sadb_address_reserved = 0;
2114 			natt_local->sadb_address_prefixlen = 0;
2115 			natt_local->sadb_address_proto = 0;
2116 			if (natt_lhp == &dummy.he ||
2117 			    natt_lhp->h_addr_list[1] == NULL) {
2118 				/*
2119 				 * Single address with -n flag or single name.
2120 				 */
2121 				sin6 = (struct sockaddr_in6 *)(natt_local + 1);
2122 				bzero(sin6, sizeof (*sin6));
2123 				sin6->sin6_family = AF_INET6;
2124 				bcopy(natt_lhp->h_addr_list[0],
2125 				    &sin6->sin6_addr, sizeof (struct in6_addr));
2126 			} else {
2127 				/*
2128 				 * If the nat-local address is vague, don't
2129 				 * bother.
2130 				 */
2131 				totallen -= alloclen;
2132 				free(natt_local);
2133 				natt_local = NULL;
2134 				WARN1(ep, ebuf, gettext(
2135 				    "NAT-T local address %s "
2136 				    "is vague, not using.\n"),
2137 				    natt_lhp->h_name);
2138 				freehostent(natt_lhp);
2139 				natt_lhp = NULL;
2140 				break;
2141 			}
2142 			break;
2143 		case TOK_NATREM:
2144 			if (natt_remote != NULL) {
2145 				ERROR(ep, ebuf, gettext(
2146 				    "Can only specify "
2147 				    "single NAT-T remote address.\n"));
2148 				break;
2149 			}
2150 			sa_len = parseaddr(*argv, &natt_rhp, 0, ebuf);
2151 			if (natt_rhp == NULL) {
2152 				ERROR1(ep, ebuf, gettext(
2153 				    "Unknown NAT-T remote address \"%s\"\n"),
2154 				    *argv);
2155 				break;
2156 			}
2157 			argv++;
2158 			/*
2159 			 * Round of the sockaddr length to an 8 byte
2160 			 * boundary to make PF_KEY happy.
2161 			 */
2162 			alloclen = sizeof (*natt_remote) + roundup(sa_len, 8);
2163 			natt_remote = malloc(alloclen);
2164 			if (natt_remote == NULL)
2165 				Bail("malloc(natt_remote)");
2166 			totallen += alloclen;
2167 			natt_remote->sadb_address_len = SADB_8TO64(alloclen);
2168 			natt_remote->sadb_address_exttype =
2169 			    SADB_X_EXT_ADDRESS_NATT_REM;
2170 			natt_remote->sadb_address_reserved = 0;
2171 			natt_remote->sadb_address_prefixlen = 0;
2172 			natt_remote->sadb_address_proto = 0;
2173 			if (natt_rhp == &dummy.he ||
2174 			    natt_rhp->h_addr_list[1] == NULL) {
2175 				/*
2176 				 * Single address with -n flag or single name.
2177 				 */
2178 				sin6 = (struct sockaddr_in6 *)(natt_remote + 1);
2179 				bzero(sin6, sizeof (*sin6));
2180 				sin6->sin6_family = AF_INET6;
2181 				bcopy(natt_rhp->h_addr_list[0],
2182 				    &sin6->sin6_addr, sizeof (struct in6_addr));
2183 			} else {
2184 				/*
2185 				 * If the nat-renote address is vague, don't
2186 				 * bother.
2187 				 */
2188 				totallen -= alloclen;
2189 				free(natt_remote);
2190 				natt_remote = NULL;
2191 				WARN1(ep, ebuf, gettext(
2192 				    "NAT-T remote address %s "
2193 				    "is vague, not using.\n"),
2194 				    natt_rhp->h_name);
2195 				freehostent(natt_rhp);
2196 				natt_rhp = NULL;
2197 				break;
2198 			}
2199 			break;
2200 		case TOK_ENCRKEY:
2201 			if (encrypt != NULL) {
2202 				ERROR(ep, ebuf, gettext(
2203 				    "Can only specify "
2204 				    "single encryption key.\n"));
2205 				break;
2206 			}
2207 			if (assoc != NULL &&
2208 			    assoc->sadb_sa_encrypt == SADB_EALG_NULL) {
2209 				FATAL(ep, ebuf, gettext(
2210 				    "Cannot specify a key with NULL "
2211 				    "encryption algorithm.\n"));
2212 				break;
2213 			}
2214 			encrypt = parsekey(*argv, ebuf);
2215 			argv++;
2216 			if (encrypt == NULL) {
2217 				ERROR(ep, ebuf, gettext(
2218 				    "Invalid encryption key.\n"));
2219 				break;
2220 			}
2221 			totallen += SADB_64TO8(encrypt->sadb_key_len);
2222 			encrypt->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
2223 			break;
2224 		case TOK_AUTHKEY:
2225 			if (auth != NULL) {
2226 				ERROR(ep, ebuf, gettext(
2227 				    "Can only specify single"
2228 				    " authentication key.\n"));
2229 				break;
2230 			}
2231 			auth = parsekey(*argv, ebuf);
2232 			argv++;
2233 			if (auth == NULL) {
2234 				ERROR(ep, ebuf, gettext(
2235 				    "Invalid authentication key.\n"));
2236 				break;
2237 			}
2238 			totallen += SADB_64TO8(auth->sadb_key_len);
2239 			auth->sadb_key_exttype = SADB_EXT_KEY_AUTH;
2240 			break;
2241 		case TOK_SRCIDTYPE:
2242 			if (*argv == NULL || *(argv + 1) == NULL) {
2243 				FATAL(ep, ebuf, gettext(
2244 				    "Unexpected end of command "
2245 				    "line - Expecting Src Type.\n"));
2246 				/* NOTREACHED */
2247 				break;
2248 			}
2249 			if (srcid != NULL) {
2250 				ERROR(ep, ebuf, gettext(
2251 				    "Can only specify single"
2252 				    " source certificate identity.\n"));
2253 				break;
2254 			}
2255 			alloclen = sizeof (*srcid) +
2256 			    roundup(strlen(*(argv + 1)) + 1, 8);
2257 			srcid = malloc(alloclen);
2258 			if (srcid == NULL)
2259 				Bail("malloc(srcid)");
2260 			totallen += alloclen;
2261 			srcid->sadb_ident_type = parseidtype(*argv, ebuf);
2262 			argv++;
2263 			srcid->sadb_ident_len = SADB_8TO64(alloclen);
2264 			srcid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
2265 			srcid->sadb_ident_reserved = 0;
2266 			srcid->sadb_ident_id = 0;  /* Not useful here. */
2267 			(void) strlcpy((char *)(srcid + 1), *argv, alloclen);
2268 			argv++;
2269 			break;
2270 		case TOK_DSTIDTYPE:
2271 			if (*argv == NULL || *(argv + 1) == NULL) {
2272 				ERROR(ep, ebuf, gettext(
2273 				    "Unexpected end of command"
2274 				    " line - expecting dst type.\n"));
2275 				break;
2276 			}
2277 			if (dstid != NULL) {
2278 				ERROR(ep, ebuf, gettext(
2279 				    "Can only specify single destination "
2280 				    "certificate identity.\n"));
2281 				break;
2282 			}
2283 			alloclen = sizeof (*dstid) +
2284 			    roundup(strlen(*(argv + 1)) + 1, 8);
2285 			dstid = malloc(alloclen);
2286 			if (dstid == NULL)
2287 				Bail("malloc(dstid)");
2288 			totallen += alloclen;
2289 			dstid->sadb_ident_type = parseidtype(*argv, ebuf);
2290 			argv++;
2291 			dstid->sadb_ident_len = SADB_8TO64(alloclen);
2292 			dstid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
2293 			dstid->sadb_ident_reserved = 0;
2294 			dstid->sadb_ident_id = 0;  /* Not useful here. */
2295 			(void) strlcpy((char *)(dstid + 1), *argv, alloclen);
2296 			argv++;
2297 			break;
2298 		case TOK_HARD_ALLOC:
2299 		case TOK_HARD_BYTES:
2300 		case TOK_HARD_ADDTIME:
2301 		case TOK_HARD_USETIME:
2302 			if (hard == NULL) {
2303 				hard = malloc(sizeof (*hard));
2304 				if (hard == NULL)
2305 					Bail("malloc(hard_lifetime)");
2306 				bzero(hard, sizeof (*hard));
2307 				hard->sadb_lifetime_exttype =
2308 				    SADB_EXT_LIFETIME_HARD;
2309 				hard->sadb_lifetime_len =
2310 				    SADB_8TO64(sizeof (*hard));
2311 				totallen += sizeof (*hard);
2312 			}
2313 			switch (token) {
2314 			case TOK_HARD_ALLOC:
2315 				if (hard->sadb_lifetime_allocations != 0) {
2316 					ERROR(ep, ebuf, gettext(
2317 					    "Can only specify single"
2318 					    " hard allocation limit.\n"));
2319 					break;
2320 				}
2321 				hard->sadb_lifetime_allocations =
2322 				    (uint32_t)parsenum(*argv, B_TRUE, ebuf);
2323 				break;
2324 			case TOK_HARD_BYTES:
2325 				if (hard->sadb_lifetime_bytes != 0) {
2326 					ERROR(ep, ebuf, gettext(
2327 					    "Can only specify "
2328 					    "single hard byte limit.\n"));
2329 					break;
2330 				}
2331 				hard->sadb_lifetime_bytes = parsenum(*argv,
2332 				    B_TRUE, ebuf);
2333 				break;
2334 			case TOK_HARD_ADDTIME:
2335 				if (hard->sadb_lifetime_addtime != 0) {
2336 					ERROR(ep, ebuf, gettext(
2337 					    "Can only specify "
2338 					    "single past-add lifetime.\n"));
2339 					break;
2340 				}
2341 				hard->sadb_lifetime_addtime = parsenum(*argv,
2342 				    B_TRUE, ebuf);
2343 				break;
2344 			case TOK_HARD_USETIME:
2345 				if (hard->sadb_lifetime_usetime != 0) {
2346 					ERROR(ep, ebuf, gettext(
2347 					    "Can only specify "
2348 					    "single past-use lifetime.\n"));
2349 					break;
2350 				}
2351 				hard->sadb_lifetime_usetime = parsenum(*argv,
2352 				    B_TRUE, ebuf);
2353 				break;
2354 			}
2355 			argv++;
2356 			break;
2357 		case TOK_SOFT_ALLOC:
2358 		case TOK_SOFT_BYTES:
2359 		case TOK_SOFT_ADDTIME:
2360 		case TOK_SOFT_USETIME:
2361 			if (soft == NULL) {
2362 				soft = malloc(sizeof (*soft));
2363 				if (soft == NULL)
2364 					Bail("malloc(soft_lifetime)");
2365 				bzero(soft, sizeof (*soft));
2366 				soft->sadb_lifetime_exttype =
2367 				    SADB_EXT_LIFETIME_SOFT;
2368 				soft->sadb_lifetime_len =
2369 				    SADB_8TO64(sizeof (*soft));
2370 				totallen += sizeof (*soft);
2371 			}
2372 			switch (token) {
2373 			case TOK_SOFT_ALLOC:
2374 				if (soft->sadb_lifetime_allocations != 0) {
2375 					ERROR(ep, ebuf, gettext(
2376 					    "Can only specify single"
2377 					    " soft allocation limit.\n"));
2378 					break;
2379 				}
2380 				soft->sadb_lifetime_allocations =
2381 				    (uint32_t)parsenum(*argv, B_TRUE, ebuf);
2382 				break;
2383 			case TOK_SOFT_BYTES:
2384 				if (soft->sadb_lifetime_bytes != 0) {
2385 					ERROR(ep, ebuf, gettext(
2386 					    "Can only specify single"
2387 					    " soft byte limit.\n"));
2388 					break;
2389 				}
2390 				soft->sadb_lifetime_bytes = parsenum(*argv,
2391 				    B_TRUE, ebuf);
2392 				break;
2393 			case TOK_SOFT_ADDTIME:
2394 				if (soft->sadb_lifetime_addtime != 0) {
2395 					ERROR(ep, ebuf, gettext(
2396 					    "Can only specify single"
2397 					    " past-add lifetime.\n"));
2398 					break;
2399 				}
2400 				soft->sadb_lifetime_addtime = parsenum(*argv,
2401 				    B_TRUE, ebuf);
2402 				break;
2403 			case TOK_SOFT_USETIME:
2404 				if (soft->sadb_lifetime_usetime != 0) {
2405 					ERROR(ep, ebuf, gettext(
2406 					    "Can only specify single"
2407 					    " past-use lifetime.\n"));
2408 					break;
2409 				}
2410 				soft->sadb_lifetime_usetime = parsenum(*argv,
2411 				    B_TRUE, ebuf);
2412 				break;
2413 			}
2414 			argv++;
2415 			break;
2416 		case TOK_FLAG_INBOUND:
2417 			assoc->sadb_sa_flags |= SADB_X_SAFLAGS_INBOUND;
2418 			break;
2419 		case TOK_FLAG_OUTBOUND:
2420 			assoc->sadb_sa_flags |= SADB_X_SAFLAGS_OUTBOUND;
2421 			break;
2422 		default:
2423 			ERROR1(ep, ebuf, gettext(
2424 			    "Don't use extension %s for add/update.\n"),
2425 			    *(argv - 1));
2426 			break;
2427 		}
2428 	} while (token != TOK_EOF);
2429 
2430 	handle_errors(ep, ebuf, B_TRUE, B_FALSE);
2431 
2432 #define	PORT_ONLY_ALLOCATE(af, socktype, exttype, extvar, port) {  \
2433 	alloclen = sizeof (sadb_address_t) + roundup(sizeof (socktype), 8); \
2434 	(extvar) = calloc(1, alloclen); \
2435 	if ((extvar) == NULL) { \
2436 		Bail("malloc(implicit port)"); \
2437 	} \
2438 	totallen += alloclen; \
2439 	(extvar)->sadb_address_len = SADB_8TO64(alloclen); \
2440 	(extvar)->sadb_address_exttype = (exttype); \
2441 	/* sin/sin6 has equivalent offsets for ports! */ \
2442 	sin6 = (struct sockaddr_in6 *)((extvar) + 1); \
2443 	sin6->sin6_family = (af); \
2444 	sin6->sin6_port = (port); \
2445 	}
2446 
2447 	/*
2448 	 * If we specify inner ports or NAT ports w/o addresses, we still need
2449 	 * to allocate.  Also, if we have one inner address, we need the
2450 	 * other, even if we don't specify anything.
2451 	 */
2452 	if (use_natt) {
2453 		if (natt_lport != 0 && natt_local == NULL) {
2454 			PORT_ONLY_ALLOCATE(AF_INET, struct sockaddr_in,
2455 			    SADB_X_EXT_ADDRESS_NATT_LOC, natt_local,
2456 			    natt_lport);
2457 		}
2458 
2459 		if (natt_rport != 0 && natt_remote == NULL) {
2460 			PORT_ONLY_ALLOCATE(AF_INET, struct sockaddr_in,
2461 			    SADB_X_EXT_ADDRESS_NATT_REM, natt_remote,
2462 			    natt_rport);
2463 		}
2464 	} else {
2465 		if (natt_lport != 0 || natt_rport != 0) {
2466 			ERROR(ep, ebuf, gettext("Must specify 'encap udp' "
2467 			    "with any NAT-T port.\n"));
2468 		} else if (natt_local != NULL || natt_remote != NULL) {
2469 			ERROR(ep, ebuf, gettext("Must specify 'encap udp' "
2470 			    "with any NAT-T address.\n"));
2471 		}
2472 	}
2473 
2474 	if (alloc_inner && idst == NULL) {
2475 		PORT_ONLY_ALLOCATE(AF_INET6, struct sockaddr_in6,
2476 		    SADB_X_EXT_ADDRESS_INNER_DST, idst, 0);
2477 	}
2478 
2479 	if (alloc_inner && isrc == NULL) {
2480 		PORT_ONLY_ALLOCATE(AF_INET6, struct sockaddr_in6,
2481 		    SADB_X_EXT_ADDRESS_INNER_SRC, isrc, 0);
2482 	}
2483 #undef PORT_ONLY_ALLOCATE
2484 
2485 	/*
2486 	 * Okay, so now I have all of the potential extensions!
2487 	 * Allocate a single contiguous buffer.  Keep in mind that it'll
2488 	 * be enough because the key itself will be yanked.
2489 	 */
2490 
2491 	if (src == NULL && dst != NULL) {
2492 		/*
2493 		 * Set explicit unspecified source address.
2494 		 */
2495 		size_t lenbytes = SADB_64TO8(dst->sadb_address_len);
2496 
2497 		unspec_src = B_TRUE;
2498 		totallen += lenbytes;
2499 		src = malloc(lenbytes);
2500 		if (src == NULL)
2501 			Bail("malloc(implicit src)");
2502 		/* Confusing, but we're copying from DST to SRC.  :) */
2503 		bcopy(dst, src, lenbytes);
2504 		src->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
2505 		sin6 = (struct sockaddr_in6 *)(src + 1);
2506 		bzero(sin6, sizeof (*sin6));
2507 		sin6->sin6_family = AF_INET6;
2508 	}
2509 
2510 	msg.sadb_msg_len = SADB_8TO64(totallen);
2511 
2512 	buffer = malloc(totallen);
2513 	nexthdr = buffer;
2514 	bcopy(&msg, nexthdr, sizeof (msg));
2515 	nexthdr += SADB_8TO64(sizeof (msg));
2516 	if (assoc != NULL) {
2517 		if (assoc->sadb_sa_spi == 0) {
2518 			ERROR1(ep, ebuf, gettext(
2519 			    "The SPI value is missing for "
2520 			    "the association you wish to %s.\n"), thiscmd);
2521 		}
2522 		if (assoc->sadb_sa_auth == 0 && assoc->sadb_sa_encrypt == 0 &&
2523 		    cmd == CMD_ADD) {
2524 			free(assoc);
2525 			FATAL(ep, ebuf, gettext(
2526 			    "Select at least one algorithm "
2527 			    "for this add.\n"));
2528 		}
2529 
2530 		/* Hack to let user specify NULL ESP implicitly. */
2531 		if (msg.sadb_msg_satype == SADB_SATYPE_ESP &&
2532 		    assoc->sadb_sa_encrypt == 0)
2533 			assoc->sadb_sa_encrypt = SADB_EALG_NULL;
2534 
2535 		/* 0 is an actual value.  Print a warning if it was entered. */
2536 		if (assoc->sadb_sa_state == 0) {
2537 			if (readstate) {
2538 				ERROR(ep, ebuf, gettext(
2539 				    "WARNING: Cannot set LARVAL SA state.\n"));
2540 			}
2541 			assoc->sadb_sa_state = SADB_SASTATE_MATURE;
2542 		}
2543 
2544 		if (use_natt) {
2545 			if (natt_remote != NULL)
2546 				assoc->sadb_sa_flags |= SADB_X_SAFLAGS_NATT_REM;
2547 			if (natt_local != NULL)
2548 				assoc->sadb_sa_flags |= SADB_X_SAFLAGS_NATT_LOC;
2549 		}
2550 
2551 		if (alloc_inner) {
2552 			/*
2553 			 * For now, assume RFC 3884's dream of transport-mode
2554 			 * SAs with inner IP address selectors will not
2555 			 * happen.
2556 			 */
2557 			assoc->sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL;
2558 			if (proto != 0 && proto != IPPROTO_ENCAP &&
2559 			    proto != IPPROTO_IPV6) {
2560 				ERROR1(ep, ebuf, gettext(
2561 				    "WARNING: Protocol type %d not "
2562 				    "for use with Tunnel-Mode SA.\n"), proto);
2563 				/* Continue and let PF_KEY scream... */
2564 			}
2565 		}
2566 
2567 		bcopy(assoc, nexthdr, SADB_64TO8(assoc->sadb_sa_len));
2568 		nexthdr += assoc->sadb_sa_len;
2569 		/* Save the SPI for the case of an error. */
2570 		spi = assoc->sadb_sa_spi;
2571 		free(assoc);
2572 	} else {
2573 		if (spi == 0)
2574 			ERROR1(ep, ebuf, gettext(
2575 			    "Need to define SPI for %s.\n"), thiscmd);
2576 		ERROR1(ep, ebuf, gettext(
2577 		    "Need SA parameters for %s.\n"), thiscmd);
2578 	}
2579 
2580 	if (sadb_pair != NULL) {
2581 		if (sadb_pair->sadb_x_pair_spi == 0) {
2582 			ERROR1(ep, ebuf, gettext(
2583 			    "The SPI value is missing for the "
2584 			    "association you wish to %s.\n"), thiscmd);
2585 		}
2586 		bcopy(sadb_pair, nexthdr,
2587 		    SADB_64TO8(sadb_pair->sadb_x_pair_len));
2588 		nexthdr += sadb_pair->sadb_x_pair_len;
2589 		free(sadb_pair);
2590 	}
2591 
2592 	if (hard != NULL) {
2593 		bcopy(hard, nexthdr, SADB_64TO8(hard->sadb_lifetime_len));
2594 		nexthdr += hard->sadb_lifetime_len;
2595 		free(hard);
2596 	}
2597 
2598 	if (soft != NULL) {
2599 		bcopy(soft, nexthdr, SADB_64TO8(soft->sadb_lifetime_len));
2600 		nexthdr += soft->sadb_lifetime_len;
2601 		free(soft);
2602 	}
2603 
2604 	if (encrypt == NULL && auth == NULL && cmd == CMD_ADD) {
2605 		ERROR(ep, ebuf, gettext(
2606 		    "Must have at least one key for an add.\n"));
2607 	}
2608 
2609 	if (encrypt != NULL) {
2610 		bcopy(encrypt, nexthdr, SADB_64TO8(encrypt->sadb_key_len));
2611 		nexthdr += encrypt->sadb_key_len;
2612 		bzero(encrypt, SADB_64TO8(encrypt->sadb_key_len));
2613 		free(encrypt);
2614 	}
2615 
2616 	if (auth != NULL) {
2617 		bcopy(auth, nexthdr, SADB_64TO8(auth->sadb_key_len));
2618 		nexthdr += auth->sadb_key_len;
2619 		bzero(auth, SADB_64TO8(auth->sadb_key_len));
2620 		free(auth);
2621 	}
2622 
2623 	if (srcid != NULL) {
2624 		bcopy(srcid, nexthdr, SADB_64TO8(srcid->sadb_ident_len));
2625 		nexthdr += srcid->sadb_ident_len;
2626 		free(srcid);
2627 	}
2628 
2629 	if (dstid != NULL) {
2630 		bcopy(dstid, nexthdr, SADB_64TO8(dstid->sadb_ident_len));
2631 		nexthdr += dstid->sadb_ident_len;
2632 		free(dstid);
2633 	}
2634 
2635 	if (dst != NULL) {
2636 		bcopy(dst, nexthdr, SADB_64TO8(dst->sadb_address_len));
2637 		free(dst);
2638 		dst = (struct sadb_address *)nexthdr;
2639 		dst->sadb_address_proto = proto;
2640 		((struct sockaddr_in6 *)(dst + 1))->sin6_port = htons(dstport);
2641 		nexthdr += dst->sadb_address_len;
2642 	} else {
2643 		FATAL1(ep, ebuf, gettext(
2644 		    "Need destination address for %s.\n"), thiscmd);
2645 	}
2646 
2647 	if (use_natt) {
2648 		if (natt_remote == NULL && natt_local == NULL) {
2649 			ERROR(ep, ebuf, gettext(
2650 			    "Must specify NAT-T remote or local address "
2651 			    "for UDP encapsulation.\n"));
2652 		}
2653 
2654 		if (natt_remote != NULL) {
2655 			bcopy(natt_remote, nexthdr,
2656 			    SADB_64TO8(natt_remote->sadb_address_len));
2657 			free(natt_remote);
2658 			natt_remote = (struct sadb_address *)nexthdr;
2659 			nexthdr += natt_remote->sadb_address_len;
2660 			((struct sockaddr_in6 *)(natt_remote + 1))->sin6_port =
2661 			    htons(natt_rport);
2662 		}
2663 
2664 		if (natt_local != NULL) {
2665 			bcopy(natt_local, nexthdr,
2666 			    SADB_64TO8(natt_local->sadb_address_len));
2667 			free(natt_local);
2668 			natt_local = (struct sadb_address *)nexthdr;
2669 			nexthdr += natt_local->sadb_address_len;
2670 			((struct sockaddr_in6 *)(natt_local + 1))->sin6_port =
2671 			    htons(natt_lport);
2672 		}
2673 	}
2674 
2675 	handle_errors(ep, ebuf, B_TRUE, B_FALSE);
2676 
2677 	/*
2678 	 * PF_KEY requires a source address extension, even if the source
2679 	 * address itself is unspecified. (See "Set explicit unspecified..."
2680 	 * code fragment above. Destination reality check was above.)
2681 	 */
2682 	bcopy(src, nexthdr, SADB_64TO8(src->sadb_address_len));
2683 	free(src);
2684 	src = (struct sadb_address *)nexthdr;
2685 	src->sadb_address_proto = proto;
2686 	((struct sockaddr_in6 *)(src + 1))->sin6_port = htons(srcport);
2687 	nexthdr += src->sadb_address_len;
2688 
2689 	if (isrc != NULL) {
2690 		bcopy(isrc, nexthdr, SADB_64TO8(isrc->sadb_address_len));
2691 		free(isrc);
2692 		isrc = (struct sadb_address *)nexthdr;
2693 		isrc->sadb_address_proto = iproto;
2694 		((struct sockaddr_in6 *)(isrc + 1))->sin6_port =
2695 		    htons(isrcport);
2696 		nexthdr += isrc->sadb_address_len;
2697 	}
2698 
2699 	if (idst != NULL) {
2700 		bcopy(idst, nexthdr, SADB_64TO8(idst->sadb_address_len));
2701 		free(idst);
2702 		idst = (struct sadb_address *)nexthdr;
2703 		idst->sadb_address_proto = iproto;
2704 		((struct sockaddr_in6 *)(idst + 1))->sin6_port =
2705 		    htons(idstport);
2706 		nexthdr += idst->sadb_address_len;
2707 	}
2708 
2709 	if (cflag) {
2710 		/*
2711 		 * Assume the checked cmd would have worked if it was actually
2712 		 * used. doaddresses() will increment lines_added if it
2713 		 * succeeds.
2714 		 */
2715 		lines_added++;
2716 	} else {
2717 		doaddresses(sadb_msg_type, satype,
2718 		    cmd, srchp, dsthp, src, dst, unspec_src, buffer, totallen,
2719 		    spi, ebuf);
2720 	}
2721 
2722 	if (isrchp != NULL && isrchp != &dummy.he)
2723 		freehostent(isrchp);
2724 	if (idsthp != NULL && idsthp != &dummy.he)
2725 		freehostent(idsthp);
2726 	if (srchp != NULL && srchp != &dummy.he)
2727 		freehostent(srchp);
2728 	if (dsthp != NULL && dsthp != &dummy.he)
2729 		freehostent(dsthp);
2730 	if (natt_lhp != NULL && natt_lhp != &dummy.he)
2731 		freehostent(natt_lhp);
2732 	if (natt_rhp != NULL && natt_rhp != &dummy.he)
2733 		freehostent(natt_rhp);
2734 
2735 	free(ebuf);
2736 	free(buffer);
2737 }
2738 
2739 /*
2740  * DELETE and GET are similar, in that they only need the extensions
2741  * required to _find_ an SA, and then either delete it or obtain its
2742  * information.
2743  */
2744 static void
2745 dodelget(int cmd, int satype, char *argv[], char *ebuf)
2746 {
2747 	struct sadb_msg *msg = (struct sadb_msg *)get_buffer;
2748 	uint64_t *nextext;
2749 	struct sadb_sa *assoc = NULL;
2750 	struct sadb_address *src = NULL, *dst = NULL;
2751 	int next, token, sa_len;
2752 	char *thiscmd;
2753 	uint32_t spi;
2754 	uint8_t	sadb_msg_type;
2755 	struct hostent *srchp = NULL, *dsthp = NULL;
2756 	struct sockaddr_in6 *sin6;
2757 	boolean_t unspec_src = B_TRUE;
2758 	uint16_t srcport = 0, dstport = 0;
2759 	uint8_t proto = 0;
2760 	char *ep = NULL;
2761 
2762 	/* Set the first extension header to right past the base message. */
2763 	nextext = (uint64_t *)(msg + 1);
2764 	bzero(nextext, sizeof (get_buffer) - sizeof (*msg));
2765 
2766 	switch (cmd) {
2767 	case CMD_GET:
2768 		thiscmd = "get";
2769 		sadb_msg_type = SADB_GET;
2770 		break;
2771 	case CMD_DELETE:
2772 		thiscmd = "delete";
2773 		sadb_msg_type = SADB_DELETE;
2774 		break;
2775 	case CMD_DELETE_PAIR:
2776 		thiscmd = "delete-pair";
2777 		sadb_msg_type = SADB_X_DELPAIR;
2778 		break;
2779 	}
2780 
2781 	msg_init(msg, sadb_msg_type, (uint8_t)satype);
2782 
2783 #define	ALLOC_ADDR_EXT(ext, exttype)			\
2784 	(ext) = (struct sadb_address *)nextext;		\
2785 	nextext = (uint64_t *)((ext) + 1);		\
2786 	nextext += SADB_8TO64(roundup(sa_len, 8));	\
2787 	(ext)->sadb_address_exttype = exttype;		\
2788 	(ext)->sadb_address_len = nextext - ((uint64_t *)ext);
2789 
2790 	/* Assume last element in argv is set to NULL. */
2791 	do {
2792 		token = parseextval(*argv, &next);
2793 		argv++;
2794 		switch (token) {
2795 		case TOK_EOF:
2796 			/* Do nothing, I'm done. */
2797 			break;
2798 		case TOK_UNKNOWN:
2799 			ERROR1(ep, ebuf, gettext(
2800 			    "Unknown extension field \"%s\"\n"), *(argv - 1));
2801 			break;
2802 		case TOK_SPI:
2803 			if (assoc != NULL) {
2804 				ERROR(ep, ebuf, gettext(
2805 				    "Can only specify single SPI value.\n"));
2806 				break;
2807 			}
2808 			assoc = (struct sadb_sa *)nextext;
2809 			nextext = (uint64_t *)(assoc + 1);
2810 			assoc->sadb_sa_len = SADB_8TO64(sizeof (*assoc));
2811 			assoc->sadb_sa_exttype = SADB_EXT_SA;
2812 			assoc->sadb_sa_spi = htonl((uint32_t)parsenum(*argv,
2813 			    B_TRUE, ebuf));
2814 			spi = assoc->sadb_sa_spi;
2815 			argv++;
2816 			break;
2817 		case TOK_SRCPORT:
2818 			if (srcport != 0) {
2819 				ERROR(ep, ebuf, gettext(
2820 				    "Can only specify single source port.\n"));
2821 				break;
2822 			}
2823 			srcport = parsenum(*argv, B_TRUE, ebuf);
2824 			argv++;
2825 			break;
2826 		case TOK_DSTPORT:
2827 			if (dstport != 0) {
2828 				ERROR(ep, ebuf, gettext(
2829 				    "Can only "
2830 				    "specify single destination port.\n"));
2831 				break;
2832 			}
2833 			dstport = parsenum(*argv, B_TRUE, ebuf);
2834 			argv++;
2835 			break;
2836 		case TOK_PROTO:
2837 			if (proto != 0) {
2838 				ERROR(ep, ebuf, gettext(
2839 				    "Can only specify single protocol.\n"));
2840 				break;
2841 			}
2842 			proto = parsenum(*argv, B_TRUE, ebuf);
2843 			argv++;
2844 			break;
2845 		case TOK_SRCADDR:
2846 		case TOK_SRCADDR6:
2847 			if (src != NULL) {
2848 				ERROR(ep, ebuf, gettext(
2849 				    "Can only specify single source addr.\n"));
2850 				break;
2851 			}
2852 			sa_len = parseaddr(*argv, &srchp,
2853 			    (token == TOK_SRCADDR6), ebuf);
2854 			if (srchp == NULL) {
2855 				ERROR1(ep, ebuf, gettext(
2856 				    "Unknown source address \"%s\"\n"), *argv);
2857 				break;
2858 			}
2859 			argv++;
2860 
2861 			unspec_src = B_FALSE;
2862 
2863 			ALLOC_ADDR_EXT(src, SADB_EXT_ADDRESS_SRC);
2864 
2865 			if (srchp == &dummy.he) {
2866 				/*
2867 				 * Single address with -n flag.
2868 				 */
2869 				sin6 = (struct sockaddr_in6 *)(src + 1);
2870 				bzero(sin6, sizeof (*sin6));
2871 				sin6->sin6_family = AF_INET6;
2872 				bcopy(srchp->h_addr_list[0], &sin6->sin6_addr,
2873 				    sizeof (struct in6_addr));
2874 			}
2875 			/* The rest is pre-bzeroed for us. */
2876 			break;
2877 		case TOK_DSTADDR:
2878 		case TOK_DSTADDR6:
2879 			if (dst != NULL) {
2880 				ERROR(ep, ebuf, gettext(
2881 				    "Can only specify single destination "
2882 				    "address.\n"));
2883 				break;
2884 			}
2885 			sa_len = parseaddr(*argv, &dsthp,
2886 			    (token == TOK_SRCADDR6), ebuf);
2887 			if (dsthp == NULL) {
2888 				ERROR1(ep, ebuf, gettext(
2889 				    "Unknown destination address \"%s\"\n"),
2890 				    *argv);
2891 				break;
2892 			}
2893 			argv++;
2894 
2895 			ALLOC_ADDR_EXT(dst, SADB_EXT_ADDRESS_DST);
2896 
2897 			if (dsthp == &dummy.he) {
2898 				/*
2899 				 * Single address with -n flag.
2900 				 */
2901 				sin6 = (struct sockaddr_in6 *)(dst + 1);
2902 				bzero(sin6, sizeof (*sin6));
2903 				sin6->sin6_family = AF_INET6;
2904 				bcopy(dsthp->h_addr_list[0], &sin6->sin6_addr,
2905 				    sizeof (struct in6_addr));
2906 			}
2907 			/* The rest is pre-bzeroed for us. */
2908 			break;
2909 		case TOK_FLAG_INBOUND:
2910 			assoc->sadb_sa_flags |= SADB_X_SAFLAGS_INBOUND;
2911 			break;
2912 		case TOK_FLAG_OUTBOUND:
2913 			assoc->sadb_sa_flags |= SADB_X_SAFLAGS_OUTBOUND;
2914 			break;
2915 		default:
2916 			ERROR2(ep, ebuf, gettext(
2917 			    "Don't use extension %s for '%s' command.\n"),
2918 			    *(argv - 1), thiscmd);
2919 			break;
2920 		}
2921 	} while (token != TOK_EOF);
2922 
2923 	handle_errors(ep, ebuf, B_TRUE, B_FALSE);
2924 
2925 	if ((srcport != 0) && (src == NULL)) {
2926 		ALLOC_ADDR_EXT(src, SADB_EXT_ADDRESS_SRC);
2927 		sin6 = (struct sockaddr_in6 *)(src + 1);
2928 		src->sadb_address_proto = proto;
2929 		bzero(sin6, sizeof (*sin6));
2930 		sin6->sin6_family = AF_INET6;
2931 		sin6->sin6_port = htons(srcport);
2932 	}
2933 
2934 	if ((dstport != 0) && (dst == NULL)) {
2935 		ALLOC_ADDR_EXT(dst, SADB_EXT_ADDRESS_DST);
2936 		sin6 = (struct sockaddr_in6 *)(dst + 1);
2937 		src->sadb_address_proto = proto;
2938 		bzero(sin6, sizeof (*sin6));
2939 		sin6->sin6_family = AF_INET6;
2940 		sin6->sin6_port = htons(dstport);
2941 	}
2942 
2943 	/* So I have enough of the message to send it down! */
2944 	msg->sadb_msg_len = nextext - get_buffer;
2945 
2946 	if (assoc == NULL) {
2947 		FATAL1(ep, ebuf, gettext(
2948 		    "Need SA parameters for %s.\n"), thiscmd);
2949 	}
2950 
2951 	if (cflag) {
2952 		/*
2953 		 * Assume the checked cmd would have worked if it was actually
2954 		 * used. doaddresses() will increment lines_added if it
2955 		 * succeeds.
2956 		 */
2957 		lines_added++;
2958 	} else {
2959 		doaddresses(sadb_msg_type, satype,
2960 		    cmd, srchp, dsthp, src, dst, unspec_src, get_buffer,
2961 		    sizeof (get_buffer), spi, NULL);
2962 	}
2963 
2964 	if (srchp != NULL && srchp != &dummy.he)
2965 		freehostent(srchp);
2966 	if (dsthp != NULL && dsthp != &dummy.he)
2967 		freehostent(dsthp);
2968 }
2969 
2970 /*
2971  * "ipseckey monitor" should exit very gracefully if ^C is tapped.
2972  */
2973 static void
2974 monitor_catch(int signal)
2975 {
2976 	errx(signal, gettext("Bailing on signal %d."), signal);
2977 }
2978 
2979 /*
2980  * Loop forever, listening on PF_KEY messages.
2981  */
2982 static void
2983 domonitor(boolean_t passive)
2984 {
2985 	struct sadb_msg *samsg;
2986 	int rc;
2987 
2988 	/* Catch ^C. */
2989 	(void) signal(SIGINT, monitor_catch);
2990 
2991 	samsg = (struct sadb_msg *)get_buffer;
2992 	if (!passive) {
2993 		(void) printf(gettext("Actively"));
2994 		msg_init(samsg, SADB_X_PROMISC, 1);	/* Turn ON promisc. */
2995 		rc = key_write(keysock, samsg, sizeof (*samsg));
2996 		if (rc == -1)
2997 			Bail("write (SADB_X_PROMISC)");
2998 	} else {
2999 		(void) printf(gettext("Passively"));
3000 	}
3001 	(void) printf(gettext(" monitoring the PF_KEY socket.\n"));
3002 
3003 	for (; ; ) {
3004 		/*
3005 		 * I assume that read() is non-blocking, and will never
3006 		 * return 0.
3007 		 */
3008 		rc = read(keysock, samsg, sizeof (get_buffer));
3009 		if (rc == -1)
3010 			Bail("read (in domonitor)");
3011 		(void) printf(gettext("Read %d bytes.\n"), rc);
3012 		/*
3013 		 * Q:  Should I use the same method of printing as GET does?
3014 		 * A:  For now, yes.
3015 		 */
3016 		print_samsg(stdout, get_buffer, B_TRUE, vflag, nflag);
3017 		(void) putchar('\n');
3018 	}
3019 }
3020 
3021 /*
3022  * Either mask or unmask all relevant signals.
3023  */
3024 static void
3025 mask_signals(boolean_t unmask)
3026 {
3027 	sigset_t set;
3028 	static sigset_t oset;
3029 
3030 	if (unmask) {
3031 		(void) sigprocmask(SIG_SETMASK, &oset, NULL);
3032 	} else {
3033 		(void) sigfillset(&set);
3034 		(void) sigprocmask(SIG_SETMASK, &set, &oset);
3035 	}
3036 }
3037 
3038 /*
3039  * Assorted functions to print help text.
3040  */
3041 #define	puts_tr(s) (void) puts(gettext(s))
3042 
3043 static void
3044 doattrhelp()
3045 {
3046 	int i;
3047 
3048 	puts_tr("\nSA attributes:");
3049 
3050 	for (i = 0; tokens[i].string != NULL; i++) {
3051 		if (i%3 == 0)
3052 			(void) printf("\n");
3053 		(void) printf("    %-15.15s", tokens[i].string);
3054 	}
3055 	(void) printf("\n");
3056 }
3057 
3058 static void
3059 dohelpcmd(char *cmds)
3060 {
3061 	int cmd;
3062 
3063 	if (strcmp(cmds, "attr") == 0) {
3064 		doattrhelp();
3065 		return;
3066 	}
3067 
3068 	cmd = parsecmd(cmds);
3069 	switch (cmd) {
3070 	case CMD_UPDATE:
3071 		puts_tr("update	 - Update an existing SA");
3072 		break;
3073 	case CMD_UPDATE_PAIR:
3074 		puts_tr("update-pair - Update an existing pair of SA's");
3075 		break;
3076 	case CMD_ADD:
3077 		puts_tr("add	 - Add a new security association (SA)");
3078 		break;
3079 	case CMD_DELETE:
3080 		puts_tr("delete - Delete an SA");
3081 		break;
3082 	case CMD_DELETE_PAIR:
3083 		puts_tr("delete-pair - Delete a pair of SA's");
3084 		break;
3085 	case CMD_GET:
3086 		puts_tr("get - Display an SA");
3087 		break;
3088 	case CMD_FLUSH:
3089 		puts_tr("flush - Delete all SAs");
3090 		break;
3091 	case CMD_DUMP:
3092 		puts_tr("dump - Display all SAs");
3093 		break;
3094 	case CMD_MONITOR:
3095 		puts_tr("monitor - Monitor all PF_KEY reply messages.");
3096 		break;
3097 	case CMD_PMONITOR:
3098 		puts_tr(
3099 "pmonitor, passive_monitor - Monitor PF_KEY messages that");
3100 		puts_tr(
3101 "                            reply to all PF_KEY sockets.");
3102 		break;
3103 
3104 	case CMD_QUIT:
3105 		puts_tr("quit, exit - Exit the program");
3106 		break;
3107 	case CMD_SAVE:
3108 		puts_tr("save	    - Saves all SAs to a file");
3109 		break;
3110 	case CMD_HELP:
3111 		puts_tr("help	    - Display list of commands");
3112 		puts_tr("help <cmd> - Display help for command");
3113 		puts_tr("help attr  - Display possible SA attributes");
3114 		break;
3115 	default:
3116 		(void) printf(gettext("%s: Unknown command\n"), cmds);
3117 		break;
3118 	}
3119 }
3120 
3121 
3122 static void
3123 dohelp(char *cmds)
3124 {
3125 	if (cmds != NULL) {
3126 		dohelpcmd(cmds);
3127 		return;
3128 	}
3129 	puts_tr("Commands");
3130 	puts_tr("--------");
3131 	puts_tr("?, help  - Display this list");
3132 	puts_tr("help <cmd> - Display help for command");
3133 	puts_tr("help attr  - Display possible SA attributes");
3134 	puts_tr("quit, exit - Exit the program");
3135 	puts_tr("monitor - Monitor all PF_KEY reply messages.");
3136 	puts_tr("pmonitor, passive_monitor - Monitor PF_KEY messages that");
3137 	puts_tr("                            reply to all PF_KEY sockets.");
3138 	puts_tr("");
3139 	puts_tr("The following commands are of the form:");
3140 	puts_tr("    <command> {SA type} {attribute value}*");
3141 	puts_tr("");
3142 	puts_tr("add (interactive only) - Add a new security association (SA)");
3143 	puts_tr("update (interactive only) - Update an existing SA");
3144 	puts_tr("update-pair (interactive only) - Update an existing SA pair");
3145 	puts_tr("delete - Delete an SA");
3146 	puts_tr("delete-pair - Delete an SA pair");
3147 	puts_tr("get - Display an SA");
3148 	puts_tr("flush - Delete all SAs");
3149 	puts_tr("dump - Display all SAs");
3150 	puts_tr("save - Saves all SAs to a file");
3151 }
3152 
3153 /*
3154  * "Parse" a command line from argv.
3155  */
3156 static void
3157 parseit(int argc, char *argv[], char *ebuf, boolean_t read_cmdfile)
3158 {
3159 	int cmd, satype;
3160 	char *ep = NULL;
3161 
3162 	if (argc == 0)
3163 		return;
3164 	cmd = parsecmd(*argv++);
3165 
3166 	/*
3167 	 * Some commands loop forever and should only be run from the command
3168 	 * line, they should never be run from a command file as this may
3169 	 * be used at boot time.
3170 	 */
3171 	switch (cmd) {
3172 	case CMD_HELP:
3173 		if (read_cmdfile)
3174 			ERROR(ep, ebuf, gettext("Help not appropriate in "
3175 			    "config file."));
3176 		else
3177 			dohelp(*argv);
3178 		return;
3179 	case CMD_MONITOR:
3180 		if (read_cmdfile)
3181 			ERROR(ep, ebuf, gettext("Monitor not appropriate in "
3182 			    "config file."));
3183 		else
3184 			domonitor(B_FALSE);
3185 		break;
3186 	case CMD_PMONITOR:
3187 		if (read_cmdfile)
3188 			ERROR(ep, ebuf, gettext("Monitor not appropriate in "
3189 			    "config file."));
3190 		else
3191 			domonitor(B_TRUE);
3192 		break;
3193 	case CMD_QUIT:
3194 		EXIT_OK(NULL);
3195 	}
3196 
3197 	handle_errors(ep, ebuf, B_FALSE, B_FALSE);
3198 
3199 	satype = parsesatype(*argv, ebuf);
3200 
3201 	if (satype != SADB_SATYPE_UNSPEC) {
3202 		argv++;
3203 	} else {
3204 		/*
3205 		 * You must specify either "all" or a specific SA type
3206 		 * for the "save" command.
3207 		 */
3208 		if (cmd == CMD_SAVE)
3209 			if (*argv == NULL) {
3210 				FATAL(ep, ebuf, gettext(
3211 				    "Must specify a specific "
3212 				    "SA type for save.\n"));
3213 			} else {
3214 				argv++;
3215 			}
3216 	}
3217 
3218 	switch (cmd) {
3219 	case CMD_FLUSH:
3220 		if (!cflag)
3221 			doflush(satype);
3222 		/*
3223 		 * If this was called because of an entry in a cmd file
3224 		 * then this action needs to be counted to prevent
3225 		 * do_interactive() treating this as an error.
3226 		 */
3227 		lines_added++;
3228 		break;
3229 	case CMD_ADD:
3230 	case CMD_UPDATE:
3231 	case CMD_UPDATE_PAIR:
3232 		/*
3233 		 * NOTE: Shouldn't allow ADDs or UPDATEs with keying material
3234 		 * from the command line.
3235 		 */
3236 		if (!interactive) {
3237 			errx(1, gettext(
3238 			    "can't do ADD or UPDATE from the command line.\n"));
3239 		}
3240 		if (satype == SADB_SATYPE_UNSPEC) {
3241 			FATAL(ep, ebuf, gettext(
3242 			    "Must specify a specific SA type."));
3243 			/* NOTREACHED */
3244 		}
3245 		/* Parse for extensions, including keying material. */
3246 		doaddup(cmd, satype, argv, ebuf);
3247 		break;
3248 	case CMD_DELETE:
3249 	case CMD_DELETE_PAIR:
3250 	case CMD_GET:
3251 		if (satype == SADB_SATYPE_UNSPEC) {
3252 			FATAL(ep, ebuf, gettext(
3253 			    "Must specify a single SA type."));
3254 			/* NOTREACHED */
3255 		}
3256 		/* Parse for bare minimum to locate an SA. */
3257 		dodelget(cmd, satype, argv, ebuf);
3258 		break;
3259 	case CMD_DUMP:
3260 		if (read_cmdfile)
3261 			ERROR(ep, ebuf, gettext("Dump not appropriate in "
3262 			    "config file."));
3263 		else
3264 			dodump(satype, NULL);
3265 		break;
3266 	case CMD_SAVE:
3267 		if (read_cmdfile) {
3268 			ERROR(ep, ebuf, gettext("Save not appropriate in "
3269 			    "config file."));
3270 		} else {
3271 			mask_signals(B_FALSE);	/* Mask signals */
3272 			dodump(satype, opensavefile(argv[0]));
3273 			mask_signals(B_TRUE);	/* Unmask signals */
3274 		}
3275 		break;
3276 	default:
3277 		warnx(gettext("Unknown command (%s).\n"),
3278 		    *(argv - ((satype == SADB_SATYPE_UNSPEC) ? 1 : 2)));
3279 		usage();
3280 	}
3281 	handle_errors(ep, ebuf, B_FALSE, B_FALSE);
3282 }
3283 
3284 int
3285 main(int argc, char *argv[])
3286 {
3287 	int ch;
3288 	FILE *infile = stdin, *savefile;
3289 	boolean_t dosave = B_FALSE, readfile = B_FALSE;
3290 	char *configfile = NULL;
3291 	struct stat sbuf;
3292 
3293 	(void) setlocale(LC_ALL, "");
3294 #if !defined(TEXT_DOMAIN)
3295 #define	TEXT_DOMAIN "SYS_TEST"
3296 #endif
3297 	(void) textdomain(TEXT_DOMAIN);
3298 
3299 	/*
3300 	 * Check to see if the command is being run from smf(5).
3301 	 */
3302 	my_fmri = getenv("SMF_FMRI");
3303 
3304 	openlog("ipseckey", LOG_CONS, LOG_AUTH);
3305 	if (getuid() != 0) {
3306 		errx(1, "Insufficient privileges to run ipseckey.");
3307 	}
3308 
3309 	/* umask me to paranoid, I only want to create files read-only */
3310 	(void) umask((mode_t)00377);
3311 
3312 	while ((ch = getopt(argc, argv, "pnvf:s:c:")) != EOF)
3313 		switch (ch) {
3314 		case 'p':
3315 			pflag = B_TRUE;
3316 			break;
3317 		case 'n':
3318 			nflag = B_TRUE;
3319 			break;
3320 		case 'v':
3321 			vflag = B_TRUE;
3322 			break;
3323 		case 'c':
3324 			cflag = B_TRUE;
3325 			/* FALLTHRU */
3326 		case 'f':
3327 			if (dosave)
3328 				usage();
3329 			infile = fopen(optarg, "r");
3330 			if (infile == NULL) {
3331 				EXIT_BADCONFIG2("Unable to open configuration "
3332 				    "file: %s\n", optarg);
3333 			}
3334 			/*
3335 			 * Check file permissions/ownership and warn or
3336 			 * fail depending on state of SMF control.
3337 			 */
3338 			if (fstat(fileno(infile), &sbuf) == -1) {
3339 				(void) fclose(infile);
3340 				EXIT_BADCONFIG2("Unable to stat configuration "
3341 				    "file: %s\n", optarg);
3342 			}
3343 			if (INSECURE_PERMS(sbuf)) {
3344 				if (my_fmri != NULL) {
3345 					(void) fclose(infile);
3346 					EXIT_BADCONFIG2("Config file "
3347 					    "%s has insecure permissions.",
3348 					    optarg);
3349 				} else 	{
3350 					(void) fprintf(stderr, "%s %s\n",
3351 					    optarg, gettext(
3352 					    "has insecure permissions, will be "
3353 					    "rejected in permanent config."));
3354 				}
3355 			}
3356 			configfile = strdup(optarg);
3357 			readfile = B_TRUE;
3358 			break;
3359 		case 's':
3360 			if (readfile)
3361 				usage();
3362 			dosave = B_TRUE;
3363 			savefile = opensavefile(optarg);
3364 			break;
3365 		default:
3366 			usage();
3367 		}
3368 
3369 	argc -= optind;
3370 	argv += optind;
3371 
3372 	mypid = getpid();
3373 
3374 	keysock = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
3375 
3376 	if (keysock == -1) {
3377 		if (errno == EPERM) {
3378 			EXIT_BADPERM("Insufficient privileges to open "
3379 			    "PF_KEY socket.\n");
3380 		} else {
3381 			/* some other reason */
3382 			EXIT_FATAL("Opening PF_KEY socket");
3383 		}
3384 	}
3385 
3386 	if (dosave) {
3387 		mask_signals(B_FALSE);	/* Mask signals */
3388 		dodump(SADB_SATYPE_UNSPEC, savefile);
3389 		mask_signals(B_TRUE);	/* Unmask signals */
3390 		EXIT_OK(NULL);
3391 	}
3392 
3393 	/*
3394 	 * When run from smf(5) flush any existing SA's first
3395 	 * otherwise you will end up in maintenance mode.
3396 	 */
3397 	if ((my_fmri != NULL) && readfile) {
3398 		(void) fprintf(stdout, gettext(
3399 		    "Flushing existing SA's before adding new SA's\n"));
3400 		(void) fflush(stdout);
3401 		doflush(SADB_SATYPE_UNSPEC);
3402 	}
3403 	if (infile != stdin || *argv == NULL) {
3404 		/* Go into interactive mode here. */
3405 		do_interactive(infile, configfile, "ipseckey> ", my_fmri,
3406 		    parseit);
3407 	}
3408 	parseit(argc, argv, NULL, B_FALSE);
3409 
3410 	return (0);
3411 }
3412