xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c (revision 33c72b7598992897b94815b1f47b7b8077e53808)
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  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
22  */
23 
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <sys/sysconf.h>
29 #include <string.h>
30 #include <strings.h>
31 #include <libintl.h>
32 #include <locale.h>
33 #include <ctype.h>
34 #include <time.h>
35 #include <sys/sysmacros.h>
36 #include <sys/stat.h>
37 #include <sys/mman.h>
38 #include <fcntl.h>
39 #include <sys/socket.h>
40 #include <netdb.h>
41 #include <errno.h>
42 #include <assert.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <door.h>
46 #include <setjmp.h>
47 
48 #include <ipsec_util.h>
49 #include <ikedoor.h>
50 
51 static int	doorfd = -1;
52 
53 /*
54  * These are additional return values for the command line parsing
55  * function (parsecmd()).  They are specific to this utility, but
56  * need to share the same space as the IKE_SVC_* defs, without conflicts.
57  * So they're defined relative to the end of that range.
58  */
59 #define	IKEADM_HELP_GENERAL	IKE_SVC_MAX + 1
60 #define	IKEADM_HELP_GET		IKE_SVC_MAX + 2
61 #define	IKEADM_HELP_SET		IKE_SVC_MAX + 3
62 #define	IKEADM_HELP_ADD		IKE_SVC_MAX + 4
63 #define	IKEADM_HELP_DEL		IKE_SVC_MAX + 5
64 #define	IKEADM_HELP_DUMP	IKE_SVC_MAX + 6
65 #define	IKEADM_HELP_FLUSH	IKE_SVC_MAX + 7
66 #define	IKEADM_HELP_READ	IKE_SVC_MAX + 8
67 #define	IKEADM_HELP_WRITE	IKE_SVC_MAX + 9
68 #define	IKEADM_HELP_TOKEN	IKE_SVC_MAX + 10
69 #define	IKEADM_HELP_HELP	IKE_SVC_MAX + 11
70 #define	IKEADM_EXIT		IKE_SVC_MAX + 12
71 
72 /*
73  * Disable default TAB completion for now (until some brave soul tackles it).
74  */
75 /* ARGSUSED */
76 static
77 CPL_MATCH_FN(no_match)
78 {
79 	return (0);
80 }
81 
82 static void command_complete(int s) __NORETURN;
83 static void usage(void) __NORETURN;
84 
85 static void
86 command_complete(int s)
87 {
88 	if (interactive) {
89 		longjmp(env, 1);
90 	} else {
91 		exit(s);
92 	}
93 }
94 
95 static void
96 usage(void)
97 {
98 	if (!interactive) {
99 		(void) fprintf(stderr, gettext("Usage:\t"
100 		    "ikeadm [ -hnp ] cmd obj [cmd-specific options]\n"));
101 		(void) fprintf(stderr, gettext("      \tikeadm help\n"));
102 	} else {
103 		(void) fprintf(stderr,
104 		    gettext("\nType help for usage info\n"));
105 	}
106 
107 	command_complete(1);
108 }
109 
110 static void
111 print_help()
112 {
113 	(void) printf(gettext("Valid commands and objects:\n"));
114 	(void) printf(
115 	    "\tget   debug|priv|stats|p1|rule|preshared|defaults [%s]\n",
116 	    gettext("identifier"));
117 	(void) printf("\tset   priv %s\n", gettext("level"));
118 	(void) printf("\tset   debug %s [%s]\n",
119 	    gettext("level"), gettext("filename"));
120 	(void) printf("\tadd   rule|preshared {%s}|%s\n",
121 	    gettext("definition"), gettext("filename"));
122 	(void) printf("\tdel   p1|rule|preshared %s\n", gettext("identifier"));
123 	(void) printf("\tdump  p1|rule|preshared|certcache|groups|"
124 	    "encralgs|authalgs\n");
125 	(void) printf("\tflush p1|certcache\n");
126 	(void) printf("\tread  rule|preshared [%s]\n", gettext("filename"));
127 	(void) printf("\twrite rule|preshared %s\n", gettext("filename"));
128 	(void) printf("\ttoken <login|logout> %s\n",
129 	    gettext("<PKCS#11 Token Object>"));
130 	(void) printf(
131 	    "\thelp  [get|set|add|del|dump|flush|read|write|token|help]\n");
132 	(void) printf("\texit  %s\n", gettext("exit the program"));
133 	(void) printf("\tquit  %s\n", gettext("exit the program"));
134 
135 	command_complete(0);
136 }
137 
138 static void
139 print_get_help()
140 {
141 	(void) printf(
142 	    gettext("This command gets information from in.iked.\n\n"));
143 	(void) printf(gettext("Objects that may be retrieved include:\n"));
144 	(void) printf("\tdebug\t\t");
145 	(void) printf(gettext("the current debug level\n"));
146 	(void) printf("\tpriv\t\t");
147 	(void) printf(gettext("the current privilege level\n"));
148 	(void) printf("\tstats\t\t");
149 	(void) printf(gettext("current usage statistics\n"));
150 	(void) printf("\tp1\t\t");
151 	(void) printf(gettext("a phase 1 SA, identified by\n"));
152 	(void) printf(gettext("\t\t\t  local_ip remote_ip OR\n"));
153 	(void) printf(gettext("\t\t\t  init_cookie resp_cookie\n"));
154 	(void) printf("\trule\t\t");
155 	(void) printf(gettext("a phase 1 rule, identified by its label\n"));
156 	(void) printf("\tpreshared\t");
157 	(void) printf(gettext("a preshared key, identified by\n"));
158 	(void) printf(gettext("\t\t\t  local_ip remote_ip OR\n"));
159 	(void) printf(gettext("\t\t\t  local_id remote_id\n"));
160 	(void) printf("\n");
161 
162 	command_complete(0);
163 }
164 
165 static void
166 print_set_help()
167 {
168 	(void) printf(gettext("This command sets values in in.iked.\n\n"));
169 	(void) printf(gettext("Objects that may be set include:\n"));
170 	(void) printf("\tdebug\t\t");
171 	(void) printf(gettext("change the debug level\n"));
172 	(void) printf("\tpriv\t\t");
173 	(void) printf(
174 	    gettext("change the privilege level (may only be lowered)\n"));
175 	(void) printf("\n");
176 
177 	command_complete(0);
178 }
179 
180 static void
181 print_add_help()
182 {
183 	(void) printf(
184 	    gettext("This command adds items to in.iked's tables.\n\n"));
185 	(void) printf(gettext("Objects that may be set include:\n"));
186 	(void) printf("\trule\t\t");
187 	(void) printf(gettext("a phase 1 policy rule\n"));
188 	(void) printf("\tpreshared\t");
189 	(void) printf(gettext("a preshared key\n"));
190 	(void) printf(
191 	    gettext("\nObjects may be entered on the command-line, as a\n"));
192 	(void) printf(
193 	    gettext("series of keywords and tokens contained in curly\n"));
194 	(void) printf(
195 	    gettext("braces ('{', '}'); or the name of a file containing\n"));
196 	(void) printf(gettext("the object definition may be provided.\n\n"));
197 	(void) printf(
198 	    gettext("For security purposes, preshared keys may only be\n"));
199 	(void) printf(
200 	    gettext("entered on the command-line if ikeadm is running in\n"));
201 	(void) printf(gettext("interactive mode.\n"));
202 	(void) printf("\n");
203 
204 	command_complete(0);
205 }
206 
207 static void
208 print_del_help()
209 {
210 	(void) printf(
211 	    gettext("This command deletes an item from in.iked's tables.\n\n"));
212 	(void) printf(gettext("Objects that may be deleted include:\n"));
213 	(void) printf("\tp1\t\t");
214 	(void) printf(gettext("a phase 1 SA, identified by\n"));
215 	(void) printf(gettext("\t\t\t  local_ip remote_ip OR\n"));
216 	(void) printf(gettext("\t\t\t  init_cookie resp_cookie\n"));
217 	(void) printf("\trule\t\t");
218 	(void) printf(gettext("a phase 1 rule, identified by its label\n"));
219 	(void) printf("\tpreshared\t");
220 	(void) printf(gettext("a preshared key, identified by\n"));
221 	(void) printf(gettext("\t\t\t  local_ip remote_ip OR\n"));
222 	(void) printf(gettext("\t\t\t  local_id remote_id\n"));
223 	(void) printf("\n");
224 
225 	command_complete(0);
226 }
227 
228 static void
229 print_dump_help()
230 {
231 	(void) printf(
232 	    gettext("This command dumps one of in.iked's tables.\n\n"));
233 	(void) printf(gettext("Tables that may be dumped include:\n"));
234 	(void) printf("\tp1\t\t");
235 	(void) printf(gettext("all phase 1 SAs\n"));
236 	(void) printf("\trule\t\t");
237 	(void) printf(gettext("all phase 1 rules\n"));
238 	(void) printf("\tpreshared\t");
239 	(void) printf(gettext("all preshared keys\n"));
240 	(void) printf("\tcertcache\t");
241 	(void) printf(gettext("all cached certificates\n"));
242 	(void) printf("\tgroups\t\t");
243 	(void) printf(gettext("all implemented Diffie-Hellman groups\n"));
244 	(void) printf("\tencralgs\t");
245 	(void) printf(gettext("all encryption algorithms for IKE\n"));
246 	(void) printf("\tauthalgs\t");
247 	(void) printf(gettext("all authentication algorithms IKE\n"));
248 	(void) printf("\n");
249 
250 	command_complete(0);
251 }
252 
253 static void
254 print_flush_help()
255 {
256 	(void) printf(
257 	    gettext("This command clears one of in.iked's tables.\n\n"));
258 	(void) printf(gettext("Tables that may be flushed include:\n"));
259 	(void) printf("\tp1\t\t");
260 	(void) printf(gettext("all phase 1 SAs\n"));
261 	(void) printf("\tcertcache\t");
262 	(void) printf(gettext("all cached certificates\n"));
263 	(void) printf("\n");
264 
265 	command_complete(0);
266 }
267 
268 static void
269 print_read_help()
270 {
271 	(void) printf(
272 	    gettext("This command reads a new configuration file into\n"));
273 	(void) printf(
274 	    gettext("in.iked, discarding the old configuration info.\n\n"));
275 	(void) printf(gettext("Sets of data that may be read include:\n"));
276 	(void) printf("\trule\t\t");
277 	(void) printf(gettext("all phase 1 rules\n"));
278 	(void) printf("\tpreshared\t");
279 	(void) printf(gettext("all preshared keys\n\n"));
280 	(void) printf(
281 	    gettext("A filename may be provided to specify a source file\n"));
282 	(void) printf(gettext("other than the default.\n"));
283 	(void) printf("\n");
284 
285 	command_complete(0);
286 }
287 
288 static void
289 print_write_help()
290 {
291 	(void) printf(
292 	    gettext("This command writes in.iked's current configuration\n"));
293 	(void) printf(gettext("out to a config file.\n\n"));
294 	(void) printf(gettext("Sets of data that may be written include:\n"));
295 	(void) printf("\trule\t\t");
296 	(void) printf(gettext("all phase 1 rules\n"));
297 	(void) printf("\tpreshared\t");
298 	(void) printf(gettext("all preshared keys\n\n"));
299 	(void) printf(
300 	    gettext("A filename must be provided to specify the file to\n"));
301 	(void) printf(gettext("which the information should be written.\n"));
302 	(void) printf("\n");
303 
304 	command_complete(0);
305 }
306 
307 static void
308 print_token_help()
309 {
310 	(void) printf(gettext(
311 	    "This command logs IKE into and out of PKCS#11 tokens.\n\n"));
312 	(void) printf(gettext("Commands include:\n"));
313 	(void) printf("\tlogin <PKCS#11 Token Object>\t");
314 	(void) printf(gettext("log into token\n"));
315 	(void) printf("\tlogout <PKCS#11 Token Object>\t");
316 	(void) printf(gettext("log out of token\n\n"));
317 	(void) printf(
318 	    gettext("The PKCS#11 Token Object name must be "
319 	    "enclosed in quotation marks.\n"));
320 	(void) printf("\n");
321 
322 	command_complete(0);
323 }
324 
325 static void
326 print_help_help()
327 {
328 	(void) printf(
329 	    gettext("This command provides information about commands.\n\n"));
330 	(void) printf(
331 	    gettext("The 'help' command alone provides a list of valid\n"));
332 	(void) printf(
333 	    gettext("commands, along with the valid objects for each.\n"));
334 	(void) printf(
335 	    gettext("'help' followed by a valid command name provides\n"));
336 	(void) printf(gettext("further information about that command.\n"));
337 	(void) printf("\n");
338 
339 	command_complete(0);
340 }
341 
342 /*PRINTFLIKE1*/
343 static void
344 message(char *fmt, ...)
345 {
346 	va_list	ap;
347 	char	msgbuf[BUFSIZ];
348 
349 	va_start(ap, fmt);
350 	(void) vsnprintf(msgbuf, BUFSIZ, fmt, ap);
351 	(void) fprintf(stderr, gettext("ikeadm: %s\n"), msgbuf);
352 	va_end(ap);
353 }
354 
355 static int
356 open_door(void)
357 {
358 	if (doorfd >= 0)
359 		(void) close(doorfd);
360 	doorfd = open(DOORNM, O_RDONLY);
361 	return (doorfd);
362 }
363 
364 static ike_service_t *
365 ikedoor_call(char *reqp, int size, door_desc_t *descp, int ndesc)
366 {
367 	door_arg_t	arg;
368 	int retries = 0;
369 
370 	arg.data_ptr = reqp;
371 	arg.data_size = size;
372 	arg.desc_ptr = descp;
373 	arg.desc_num = ndesc;
374 	arg.rbuf = (char *)NULL;
375 	arg.rsize = 0;
376 
377 retry:
378 	if (door_call(doorfd, &arg) < 0) {
379 		if ((errno == EBADF) && ((++retries < 2) &&
380 		    (open_door() >= 0)))
381 			goto retry;
382 		(void) fprintf(stderr,
383 		    gettext("Unable to communicate with in.iked\n"));
384 		Bail("door_call failed");
385 	}
386 
387 	if ((ndesc > 0) && (descp->d_attributes & DOOR_RELEASE) &&
388 	    ((errno == EBADF) || (errno == EFAULT))) {
389 		/* callers assume passed fds will be closed no matter what */
390 		(void) close(descp->d_data.d_desc.d_descriptor);
391 	}
392 
393 	/* LINTED E_BAD_PTR_CAST_ALIGN */
394 	return ((ike_service_t *)arg.rbuf);
395 }
396 
397 /*
398  * Parsing functions
399  */
400 
401 /* stolen from ipseckey.c, with a second tier added */
402 static int
403 parsecmd(char *cmdstr, char *objstr)
404 {
405 #define	MAXOBJS		11
406 	struct objtbl {
407 		char	*obj;
408 		int	token;
409 	};
410 	static struct cmdtbl {
411 		char		*cmd;
412 		int		null_obj_token;
413 		struct objtbl	objt[MAXOBJS];
414 	} table[] = {
415 		{"get", IKE_SVC_ERROR, {
416 				{"debug",	IKE_SVC_GET_DBG},
417 				{"priv",	IKE_SVC_GET_PRIV},
418 				{"stats",	IKE_SVC_GET_STATS},
419 				{"p1",		IKE_SVC_GET_P1},
420 				{"rule",	IKE_SVC_GET_RULE},
421 				{"preshared",	IKE_SVC_GET_PS},
422 				{"defaults",	IKE_SVC_GET_DEFS},
423 				{NULL,		IKE_SVC_ERROR}
424 			}
425 		},
426 		{"set", IKE_SVC_ERROR, {
427 				{"debug",	IKE_SVC_SET_DBG},
428 				{"priv",	IKE_SVC_SET_PRIV},
429 				{NULL,		IKE_SVC_ERROR}
430 			}
431 		},
432 		{"token", IKE_SVC_ERROR, {
433 				{"login",	IKE_SVC_SET_PIN},
434 				{"logout",	IKE_SVC_DEL_PIN},
435 				{NULL,		IKE_SVC_ERROR},
436 			}
437 		},
438 		{"add", IKE_SVC_ERROR, {
439 				{"rule",	IKE_SVC_NEW_RULE},
440 				{"preshared",	IKE_SVC_NEW_PS},
441 				{NULL,		IKE_SVC_ERROR}
442 			}
443 		},
444 		{"del", IKE_SVC_ERROR, {
445 				{"p1",		IKE_SVC_DEL_P1},
446 				{"rule",	IKE_SVC_DEL_RULE},
447 				{"preshared",	IKE_SVC_DEL_PS},
448 				{NULL,		IKE_SVC_ERROR}
449 			}
450 		},
451 		{"dump", IKE_SVC_ERROR, {
452 				{"p1",		IKE_SVC_DUMP_P1S},
453 				{"rule",	IKE_SVC_DUMP_RULES},
454 				{"preshared",	IKE_SVC_DUMP_PS},
455 				{"certcache",	IKE_SVC_DUMP_CERTCACHE},
456 				{"groups",	IKE_SVC_DUMP_GROUPS},
457 				{"encralgs",	IKE_SVC_DUMP_ENCRALGS},
458 				{"authalgs",	IKE_SVC_DUMP_AUTHALGS},
459 				{NULL,		IKE_SVC_ERROR}
460 			}
461 		},
462 		{"flush", IKE_SVC_ERROR, {
463 				{"p1",		IKE_SVC_FLUSH_P1S},
464 				{"certcache",	IKE_SVC_FLUSH_CERTCACHE},
465 				{NULL,		IKE_SVC_ERROR}
466 			}
467 		},
468 		{"read", IKE_SVC_ERROR, {
469 				{"rule",	IKE_SVC_READ_RULES},
470 				{"preshared",	IKE_SVC_READ_PS},
471 				{NULL,		IKE_SVC_ERROR}
472 			}
473 		},
474 		{"write", IKE_SVC_ERROR, {
475 				{"rule",	IKE_SVC_WRITE_RULES},
476 				{"preshared",	IKE_SVC_WRITE_PS},
477 				{NULL,		IKE_SVC_ERROR}
478 			}
479 		},
480 		{"help", IKEADM_HELP_GENERAL, {
481 				{"get",		IKEADM_HELP_GET},
482 				{"set",		IKEADM_HELP_SET},
483 				{"add",		IKEADM_HELP_ADD},
484 				{"del",		IKEADM_HELP_DEL},
485 				{"dump",	IKEADM_HELP_DUMP},
486 				{"flush",	IKEADM_HELP_FLUSH},
487 				{"read",	IKEADM_HELP_READ},
488 				{"write",	IKEADM_HELP_WRITE},
489 				{"token",	IKEADM_HELP_TOKEN},
490 				{"help",	IKEADM_HELP_HELP},
491 				{NULL,		IKE_SVC_ERROR}
492 			}
493 		},
494 		{"exit", IKEADM_EXIT, {
495 				{NULL,		IKE_SVC_ERROR}
496 			}
497 		},
498 		{"quit", IKEADM_EXIT, {
499 				{NULL,		IKE_SVC_ERROR}
500 			}
501 		},
502 		{"dbg", IKE_SVC_ERROR, {
503 				{"rbdump",	IKE_SVC_DBG_RBDUMP},
504 				{NULL,		IKE_SVC_ERROR}
505 			}
506 		},
507 		{NULL,	IKE_SVC_ERROR, {
508 				{NULL,		IKE_SVC_ERROR}
509 			}
510 		}
511 	};
512 	struct cmdtbl	*ct = table;
513 	struct objtbl	*ot;
514 
515 	if (cmdstr == NULL) {
516 		return (IKE_SVC_ERROR);
517 	}
518 
519 	while (ct->cmd != NULL && strcmp(ct->cmd, cmdstr) != 0)
520 		ct++;
521 	ot = ct->objt;
522 
523 	if (ct->cmd == NULL) {
524 		message(gettext("Unrecognized command '%s'"), cmdstr);
525 		return (ot->token);
526 	}
527 
528 	if (objstr == NULL) {
529 		return (ct->null_obj_token);
530 	}
531 
532 	while (ot->obj != NULL && strcmp(ot->obj, objstr) != 0)
533 		ot++;
534 
535 	if (ot->obj == NULL)
536 		message(gettext("Unrecognized object '%s'"), objstr);
537 
538 	return (ot->token);
539 }
540 
541 /*
542  * Parsing functions:
543  * Parse command-line identification info.  All return -1 on failure,
544  * or the number of cmd-line args "consumed" on success (though argc
545  * and argv params are not actually modified).
546  */
547 
548 static int
549 parse_label(int argc, char **argv, char *label)
550 {
551 	if ((argc < 1) || (argv == NULL))
552 		return (-1);
553 
554 	if (strlcpy(label, argv[0], MAX_LABEL_LEN) >= MAX_LABEL_LEN)
555 		return (-1);
556 
557 	return (1);
558 }
559 
560 /*
561  * Parse a PKCS#11 token get the label.
562  */
563 static int
564 parse_token(int argc, char **argv, char *token_label)
565 {
566 	if ((argc < 1) || (argv == NULL))
567 		return (-1);
568 
569 	if (strlcpy(token_label, argv[0], PKCS11_TOKSIZE) >= PKCS11_TOKSIZE)
570 		return (-1);
571 
572 	return (0);
573 }
574 
575 /*
576  * Parse an address off the command line. In the hpp param, either
577  * return a hostent pointer (caller frees) or a pointer to a dummy_he_t
578  * (must also be freed by the caller; both cases are handled by the
579  * macro FREE_HE).  The new getipnodebyname() call does the Right Thing
580  * (TM), even with raw addresses (colon-separated IPv6 or dotted decimal
581  * IPv4).
582  * (mostly stolen from ipseckey.c, though some tweaks were made
583  * to better serve our purposes here.)
584  */
585 
586 typedef struct {
587 	struct hostent	he;
588 	char		*addtl[2];
589 } dummy_he_t;
590 
591 static int
592 parse_addr(int argc, char **argv, struct hostent **hpp)
593 {
594 	int		hp_errno;
595 	struct hostent	*hp = NULL;
596 	dummy_he_t	*dhp;
597 	char		*addr1;
598 
599 	if ((argc < 1) || (argv == NULL) || (argv[0] == NULL))
600 		return (-1);
601 
602 	if (!nflag) {
603 		/*
604 		 * Try name->address first.  Assume AF_INET6, and
605 		 * get IPV4s, plus IPv6s iff IPv6 is configured.
606 		 */
607 		hp = getipnodebyname(argv[0], AF_INET6, AI_DEFAULT | AI_ALL,
608 		    &hp_errno);
609 	} else {
610 		/*
611 		 * Try a normal address conversion only.  malloc a
612 		 * dummy_he_t to construct a fake hostent.  Caller
613 		 * will know to free this one using free_he().
614 		 */
615 		dhp = (dummy_he_t *)malloc(sizeof (dummy_he_t));
616 		addr1 = (char *)malloc(sizeof (struct in6_addr));
617 		if (inet_pton(AF_INET6, argv[0], addr1) == 1) {
618 			dhp->he.h_addr_list = dhp->addtl;
619 			dhp->addtl[0] = addr1;
620 			dhp->addtl[1] = NULL;
621 			hp = &dhp->he;
622 			dhp->he.h_addrtype = AF_INET6;
623 			dhp->he.h_length = sizeof (struct in6_addr);
624 		} else if (inet_pton(AF_INET, argv[0], addr1) == 1) {
625 			dhp->he.h_addr_list = dhp->addtl;
626 			dhp->addtl[0] = addr1;
627 			dhp->addtl[1] = NULL;
628 			hp = &dhp->he;
629 			dhp->he.h_addrtype = AF_INET;
630 			dhp->he.h_length = sizeof (struct in_addr);
631 		} else {
632 			hp = NULL;
633 		}
634 	}
635 
636 	*hpp = hp;
637 
638 	if (hp == NULL) {
639 		message(gettext("Unknown address %s."), argv[0]);
640 		return (-1);
641 	}
642 
643 	return (1);
644 }
645 
646 /*
647  * Free a dummy_he_t structure that was malloc'd in parse_addr().
648  * Unfortunately, callers of parse_addr don't want to know about
649  * dummy_he_t structs, so all they have is a pointer to the struct
650  * hostent; so that's what's passed in.  To manage this, we make
651  * the assumption that the struct hostent is the first field in
652  * the dummy_he_t, and therefore a pointer to it is a pointer to
653  * the dummy_he_t.
654  */
655 static void
656 free_he(struct hostent *hep)
657 {
658 	dummy_he_t	*p = (dummy_he_t *)hep;
659 
660 	assert(p != NULL);
661 
662 	if (p->addtl[0])
663 		free(p->addtl[0]);
664 	if (p->addtl[1])
665 		free(p->addtl[1]);
666 
667 	free(p);
668 }
669 
670 #define	FREE_HE(x) \
671 	if (nflag) \
672 		free_he(x); \
673 	else \
674 		freehostent(x)
675 
676 static void
677 headdr2sa(char *hea, struct sockaddr_storage *sa, int len)
678 {
679 	struct sockaddr_in	*sin;
680 	struct sockaddr_in6	*sin6;
681 
682 	if (len == sizeof (struct in6_addr)) {
683 		/* LINTED E_BAD_PTR_CAST_ALIGN */
684 		if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)hea)) {
685 			sin = (struct sockaddr_in *)sa;
686 			(void) memset(sin, 0, sizeof (*sin));
687 			/* LINTED E_BAD_PTR_CAST_ALIGN */
688 			IN6_V4MAPPED_TO_INADDR((struct in6_addr *)hea,
689 			    &sin->sin_addr);
690 			sin->sin_family = AF_INET;
691 		} else {
692 			sin6 = (struct sockaddr_in6 *)sa;
693 			(void) memset(sin6, 0, sizeof (*sin6));
694 			(void) memcpy(&sin6->sin6_addr, hea,
695 			    sizeof (struct in6_addr));
696 			sin6->sin6_family = AF_INET6;
697 		}
698 	} else {
699 		sin = (struct sockaddr_in *)sa;
700 		(void) memset(sin, 0, sizeof (*sin));
701 		(void) memcpy(&sin->sin_addr, hea, sizeof (struct in_addr));
702 		sin->sin_family = AF_INET;
703 	}
704 }
705 
706 /*
707  * The possible ident-type keywords that might be used on the command
708  * line.  This is a superset of the ones supported by ipseckey, those
709  * in the ike config file, and those in ike.preshared.
710  */
711 static keywdtab_t	idtypes[] = {
712 	/* ip, ipv4, and ipv6 are valid for preshared keys... */
713 	{SADB_IDENTTYPE_RESERVED,	"ip"},
714 	{SADB_IDENTTYPE_RESERVED,	"ipv4"},
715 	{SADB_IDENTTYPE_RESERVED,	"ipv6"},
716 	{SADB_IDENTTYPE_PREFIX,		"prefix"},
717 	{SADB_IDENTTYPE_PREFIX,		"ipv4-prefix"},
718 	{SADB_IDENTTYPE_PREFIX,		"ipv6-prefix"},
719 	{SADB_IDENTTYPE_PREFIX,		"subnet"},
720 	{SADB_IDENTTYPE_PREFIX,		"subnetv4"},
721 	{SADB_IDENTTYPE_PREFIX,		"subnetv6"},
722 	{SADB_IDENTTYPE_FQDN,		"fqdn"},
723 	{SADB_IDENTTYPE_FQDN,		"dns"},
724 	{SADB_IDENTTYPE_FQDN,		"domain"},
725 	{SADB_IDENTTYPE_FQDN,		"domainname"},
726 	{SADB_IDENTTYPE_USER_FQDN,	"user_fqdn"},
727 	{SADB_IDENTTYPE_USER_FQDN,	"mbox"},
728 	{SADB_IDENTTYPE_USER_FQDN,	"mailbox"},
729 	{SADB_X_IDENTTYPE_DN,		"dn"},
730 	{SADB_X_IDENTTYPE_DN,		"asn1dn"},
731 	{SADB_X_IDENTTYPE_GN,		"gn"},
732 	{SADB_X_IDENTTYPE_GN,		"asn1gn"},
733 	{SADB_X_IDENTTYPE_ADDR_RANGE,	"ipv4-range"},
734 	{SADB_X_IDENTTYPE_ADDR_RANGE,	"ipv6-range"},
735 	{SADB_X_IDENTTYPE_ADDR_RANGE,	"rangev4"},
736 	{SADB_X_IDENTTYPE_ADDR_RANGE,	"rangev6"},
737 	{SADB_X_IDENTTYPE_KEY_ID,	"keyid"},
738 	{0,				NULL}
739 };
740 
741 static int
742 parse_idtype(char *type, uint16_t *idnum)
743 {
744 	keywdtab_t	*idp;
745 
746 	if (type == NULL)
747 		return (-1);
748 
749 	for (idp = idtypes; idp->kw_str != NULL; idp++) {
750 		if (strcasecmp(idp->kw_str, type) == 0) {
751 			if (idnum != NULL)
752 				*idnum = idp->kw_tag;
753 			return (1);
754 		}
755 	}
756 
757 	return (-1);
758 }
759 
760 /*
761  * The sadb_ident_t is malloc'd, since its length varies;
762  * so the caller must free() it when done with the data.
763  */
764 static int
765 parse_ident(int argc, char **argv, sadb_ident_t **idpp)
766 {
767 	int		alloclen, consumed;
768 	sadb_ident_t	*idp;
769 	if ((argc < 2) || (argv == NULL) || (argv[0] == NULL) ||
770 	    (argv[1] == NULL))
771 		return (-1);
772 
773 	alloclen = sizeof (sadb_ident_t) + IKEDOORROUNDUP(strlen(argv[1]) + 1);
774 	*idpp = idp = (sadb_ident_t *)malloc(alloclen);
775 	if (idp == NULL)
776 		Bail("parsing identity");
777 
778 	if ((consumed = parse_idtype(argv[0], &idp->sadb_ident_type)) < 0) {
779 		message(gettext("unknown identity type %s."), argv[0]);
780 		return (-1);
781 	}
782 
783 	idp->sadb_ident_len = SADB_8TO64(alloclen);
784 	idp->sadb_ident_reserved = 0;
785 	idp->sadb_ident_id = 0;
786 
787 	/* now copy in identity param */
788 	(void) strlcpy((char *)(idp + 1), argv[1],
789 	    alloclen - (sizeof (sadb_ident_t)));
790 
791 	return (++consumed);
792 }
793 
794 static int
795 parse_cky(int argc, char **argv, uint64_t *ckyp)
796 {
797 	u_longlong_t	arg;
798 
799 	if ((argc < 1) || (argv[0] == NULL))
800 		return (-1);
801 
802 	errno = 0;
803 	arg = strtoull(argv[0], NULL, 0);
804 	if (errno != 0) {
805 		message(gettext("failed to parse cookie %s."), argv[0]);
806 		return (-1);
807 	}
808 
809 	*ckyp = (uint64_t)arg;
810 
811 	return (1);
812 }
813 
814 static int
815 parse_addr_pr(int argc, char **argv, struct hostent **h1pp,
816     struct hostent **h2pp)
817 {
818 	int	rtn, consumed = 0;
819 
820 	if ((rtn = parse_addr(argc, argv, h1pp)) < 0) {
821 		return (-1);
822 	}
823 	consumed = rtn;
824 	argc -= rtn;
825 	argv += rtn;
826 
827 	if ((rtn = parse_addr(argc, argv, h2pp)) < 0) {
828 		FREE_HE(*h1pp);
829 		return (-1);
830 	}
831 	consumed += rtn;
832 
833 	return (consumed);
834 }
835 
836 /*
837  * The sadb_ident_ts are malloc'd, since their length varies;
838  * so the caller must free() them when done with the data.
839  */
840 static int
841 parse_ident_pr(int argc, char **argv, sadb_ident_t **id1pp,
842     sadb_ident_t **id2pp)
843 {
844 	int	rtn, consumed = 0;
845 
846 	if ((rtn = parse_ident(argc, argv, id1pp)) < 0) {
847 		return (-1);
848 	}
849 	consumed = rtn;
850 	argc -= rtn;
851 	argv += rtn;
852 
853 	(*id1pp)->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
854 
855 	if ((rtn = parse_ident(argc, argv, id2pp)) < 0) {
856 		free(*id1pp);
857 		return (-1);
858 	}
859 	consumed += rtn;
860 
861 	(*id2pp)->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
862 
863 	return (consumed);
864 }
865 
866 static int
867 parse_cky_pr(int argc, char **argv, ike_cky_pr_t *cpr)
868 {
869 	int	rtn, consumed = 0;
870 
871 	if ((rtn = parse_cky(argc, argv, &cpr->cky_i)) < 0) {
872 		return (-1);
873 	}
874 	consumed = rtn;
875 	argc -= rtn;
876 	argv += rtn;
877 
878 	if ((rtn = parse_cky(argc, argv, &cpr->cky_r)) < 0) {
879 		return (-1);
880 	}
881 	consumed += rtn;
882 
883 	return (consumed);
884 }
885 
886 /*
887  * Preshared key field types...used for parsing preshared keys that
888  * have been entered on the command line.  The code to parse preshared
889  * keys (parse_ps, parse_key, parse_psfldid, parse_ikmtype, ...) is
890  * mostly duplicated from in.iked's readps.c.
891  */
892 #define	PSFLD_LOCID	1
893 #define	PSFLD_LOCIDTYPE	2
894 #define	PSFLD_REMID	3
895 #define	PSFLD_REMIDTYPE	4
896 #define	PSFLD_MODE	5
897 #define	PSFLD_KEY	6
898 
899 static keywdtab_t	psfldtypes[] = {
900 	{PSFLD_LOCID,		"localid"},
901 	{PSFLD_LOCIDTYPE,	"localidtype"},
902 	{PSFLD_REMID,		"remoteid"},
903 	{PSFLD_REMIDTYPE,	"remoteidtype"},
904 	{PSFLD_MODE,		"ike_mode"},
905 	{PSFLD_KEY,		"key"},
906 	{0,			NULL}
907 };
908 
909 static int
910 parse_psfldid(char *type, uint16_t *idnum)
911 {
912 	keywdtab_t	*pfp;
913 
914 	if (type == NULL)
915 		return (-1);
916 
917 	for (pfp = psfldtypes; pfp->kw_str != NULL; pfp++) {
918 		if (strcasecmp(pfp->kw_str, type) == 0) {
919 			if (idnum != NULL)
920 				*idnum = pfp->kw_tag;
921 			return (1);
922 		}
923 	}
924 
925 	return (-1);
926 }
927 
928 static keywdtab_t	ikemodes[] = {
929 	{IKE_XCHG_IDENTITY_PROTECT,	"main"},
930 	{IKE_XCHG_AGGRESSIVE,		"aggressive"},
931 	{IKE_XCHG_IP_AND_AGGR,		"both"},
932 	{0,				NULL}
933 };
934 
935 static int
936 parse_ikmtype(char *mode, uint16_t *modenum)
937 {
938 	keywdtab_t	*ikmp;
939 
940 	if (mode == NULL)
941 		return (-1);
942 
943 	for (ikmp = ikemodes; ikmp->kw_str != NULL; ikmp++) {
944 		if (strcasecmp(ikmp->kw_str, mode) == 0) {
945 			if (modenum != NULL)
946 				*modenum = ikmp->kw_tag;
947 			return (1);
948 		}
949 	}
950 
951 	return (-1);
952 }
953 
954 #define	hd2num(hd) (((hd) >= '0' && (hd) <= '9') ? ((hd) - '0') : \
955 	(((hd) >= 'a' && (hd) <= 'f') ? ((hd) - 'a' + 10) : ((hd) - 'A' + 10)))
956 
957 static uint8_t *
958 parse_key(char *input, uint_t *keybuflen, uint_t *lbits)
959 {
960 	uint8_t	*keyp, *keybufp;
961 	uint_t	i, hexlen = 0, bits, alloclen;
962 
963 	for (i = 0; input[i] != '\0' && input[i] != '/'; i++)
964 		hexlen++;
965 
966 	if (input[i] == '\0') {
967 		bits = 0;
968 	} else {
969 		/* Have /nn. */
970 		input[i] = '\0';
971 		if (sscanf((input + i + 1), "%u", &bits) != 1)
972 			return (NULL);
973 
974 		/* hexlen is in nibbles */
975 		if (((bits + 3) >> 2) > hexlen)
976 			return (NULL);
977 
978 		/*
979 		 * Adjust hexlen down if user gave us too small of a bit
980 		 * count.
981 		 */
982 		if ((hexlen << 2) > bits + 3) {
983 			hexlen = (bits + 3) >> 2;
984 			input[hexlen] = '\0';
985 		}
986 	}
987 
988 	/*
989 	 * Allocate.  Remember, hexlen is in nibbles.
990 	 */
991 
992 	alloclen = (hexlen/2 + (hexlen & 0x1));
993 	keyp = malloc(alloclen);
994 
995 	if (keyp == NULL)
996 		return (NULL);
997 
998 	keybufp = keyp;
999 	*keybuflen = alloclen;
1000 	if (bits == 0)
1001 		*lbits = (hexlen + (hexlen & 0x1)) << 2;
1002 	else
1003 		*lbits = bits;
1004 
1005 	/*
1006 	 * Read in nibbles.  Read in odd-numbered as shifted high.
1007 	 * (e.g. 123 becomes 0x1230).
1008 	 */
1009 	for (i = 0; input[i] != '\0'; i += 2) {
1010 		boolean_t second = (input[i + 1] != '\0');
1011 
1012 		if (!isxdigit(input[i]) ||
1013 		    (!isxdigit(input[i + 1]) && second)) {
1014 			free(keyp);
1015 			return (NULL);
1016 		}
1017 		*keyp = (hd2num(input[i]) << 4);
1018 		if (second)
1019 			*keyp |= hd2num(input[i + 1]);
1020 		else
1021 			break; /* out of for loop. */
1022 		keyp++;
1023 	}
1024 
1025 	/* zero the remaining bits if we're a non-octet amount. */
1026 	if (bits & 0x7)
1027 		*((input[i] == '\0') ? keyp - 1 : keyp) &=
1028 		    0xff << (8 - (bits & 0x7));
1029 	return (keybufp);
1030 }
1031 
1032 /*
1033  * the ike_ps_t struct (plus trailing data) will be allocated here,
1034  * so it will need to be freed by the caller.
1035  */
1036 static int
1037 parse_ps(int argc, char **argv, ike_ps_t **presharedpp, int *len)
1038 {
1039 	uint_t		c = 0, locidlen, remidlen, keylen, keybits;
1040 	uint_t		a_locidtotal = 0, a_remidtotal = 0;
1041 	char		*locid, *remid, *locpfx = NULL, *rempfx = NULL;
1042 	uint8_t		*keyp = NULL;
1043 	uint16_t	fldid, locidtype, remidtype, mtype;
1044 	struct hostent	*loche = NULL, *remhe = NULL;
1045 	ike_ps_t	*psp = NULL;
1046 	sadb_ident_t	*sidp;
1047 	boolean_t	whacked = B_FALSE;
1048 	int pfxlen = 0;
1049 
1050 	if ((argv[c] == NULL) || (argv[c][0] != '{'))
1051 		return (-1);
1052 	if (argv[c][1] != 0) {
1053 		/* no space between '{' and first token */
1054 		argv[c]++;
1055 	} else {
1056 		c++;
1057 	}
1058 	if ((argv[argc - 1][strlen(argv[argc - 1]) - 1] == '}') &&
1059 	    (argv[argc - 1][0] != '}')) {
1060 		/*
1061 		 * whack '}' without a space before it or parsers break.
1062 		 * Remember this trailing character for later
1063 		 */
1064 		argv[argc - 1][strlen(argv[argc - 1]) - 1] = '\0';
1065 		whacked = B_TRUE;
1066 	}
1067 
1068 	/* Default to type IP */
1069 	locidtype = remidtype = SADB_IDENTTYPE_RESERVED;
1070 	/* Default to base exchanges */
1071 	mtype = IKE_XCHG_BASE;
1072 
1073 	while ((c < argc) && (argv[c] != NULL) && (argv[c][0] != '}')) {
1074 		if ((argv[c + 1] == NULL) || (argv[c + 1][0] == '}'))
1075 			goto bail;
1076 		if (parse_psfldid(argv[c++], &fldid) < 0)
1077 			goto bail;
1078 		switch (fldid) {
1079 		case PSFLD_LOCID:
1080 			locid = argv[c++];
1081 			locidlen = strlen(locid) + 1;
1082 			break;
1083 		case PSFLD_LOCIDTYPE:
1084 			if (parse_idtype(argv[c++], &locidtype) < 0)
1085 				goto bail;
1086 			break;
1087 		case PSFLD_REMID:
1088 			remid = argv[c++];
1089 			remidlen = strlen(remid) + 1;
1090 			break;
1091 		case PSFLD_REMIDTYPE:
1092 			if (parse_idtype(argv[c++], &remidtype) < 0)
1093 				goto bail;
1094 			break;
1095 		case PSFLD_MODE:
1096 			if (parse_ikmtype(argv[c++], &mtype) < 0)
1097 				goto bail;
1098 			break;
1099 		case PSFLD_KEY:
1100 			keyp  = parse_key(argv[c++], &keylen, &keybits);
1101 			if (keyp == NULL)
1102 				goto bail;
1103 			break;
1104 		}
1105 	}
1106 
1107 	/* Make sure the line was terminated with '}' */
1108 	if (argv[c] == NULL) {
1109 		if (!whacked)
1110 			goto bail;
1111 	} else if (argv[c][0] != '}') {
1112 		goto bail;
1113 	}
1114 
1115 	/*
1116 	 * make sure we got all the required fields.  If no idtype, assume
1117 	 * ip addr; if that translation fails, we'll catch the error then.
1118 	 */
1119 	if (locid == NULL || remid == NULL || keyp == NULL || mtype == 0)
1120 		goto bail;
1121 
1122 	/* figure out the size buffer we need */
1123 	*len = sizeof (ike_ps_t);
1124 	if (locidtype != SADB_IDENTTYPE_RESERVED) {
1125 		a_locidtotal = IKEDOORROUNDUP(sizeof (sadb_ident_t) + locidlen);
1126 		*len += a_locidtotal;
1127 	}
1128 	if (remidtype != SADB_IDENTTYPE_RESERVED) {
1129 		a_remidtotal = IKEDOORROUNDUP(sizeof (sadb_ident_t) + remidlen);
1130 		*len += a_remidtotal;
1131 	}
1132 	*len += keylen;
1133 
1134 	psp = malloc(*len);
1135 	if (psp == NULL)
1136 		goto bail;
1137 	(void) memset(psp, 0, *len);
1138 
1139 	psp->ps_ike_mode = mtype;
1140 
1141 	psp->ps_localid_off = sizeof (ike_ps_t);
1142 	if (locidtype == SADB_IDENTTYPE_RESERVED) {
1143 		locpfx = strchr(locid, '/');
1144 		if (locpfx != NULL) {
1145 			*locpfx = '\0';
1146 			locpfx++;
1147 		}
1148 
1149 		/*
1150 		 * this is an ip address, store in the sockaddr field;
1151 		 * we won't use an sadb_ident_t.
1152 		 */
1153 		psp->ps_localid_len = 0;
1154 		if (parse_addr(1, &locid, &loche) < 0)
1155 			goto bail;
1156 		if (loche->h_addr_list[1] != NULL) {
1157 			message(gettext("preshared key identifier cannot "
1158 			    "match multiple IP addresses"));
1159 			goto bail;
1160 		}
1161 		headdr2sa(loche->h_addr_list[0], &psp->ps_ipaddrs.loc_addr,
1162 		    loche->h_length);
1163 		FREE_HE(loche);
1164 	} else {
1165 		psp->ps_localid_len = sizeof (sadb_ident_t) + locidlen;
1166 		sidp = (sadb_ident_t *)((int)psp + psp->ps_localid_off);
1167 		sidp->sadb_ident_len = psp->ps_localid_len;
1168 		sidp->sadb_ident_type = locidtype;
1169 		(void) strlcpy((char *)(sidp + 1), locid, a_locidtotal);
1170 	}
1171 
1172 	psp->ps_remoteid_off = psp->ps_localid_off + a_locidtotal;
1173 	if (remidtype == SADB_IDENTTYPE_RESERVED) {
1174 		rempfx = strchr(remid, '/');
1175 		if (rempfx != NULL) {
1176 			*rempfx = '\0';
1177 			rempfx++;
1178 		}
1179 
1180 		/*
1181 		 * this is an ip address, store in the sockaddr field;
1182 		 * we won't use an sadb_ident_t.
1183 		 */
1184 		psp->ps_remoteid_len = 0;
1185 		if (parse_addr(1, &remid, &remhe) < 0)
1186 			goto bail;
1187 		if (remhe->h_addr_list[1] != NULL) {
1188 			message(gettext("preshared key identifier cannot "
1189 			    "match multiple IP addresses"));
1190 			goto bail;
1191 		}
1192 		headdr2sa(remhe->h_addr_list[0], &psp->ps_ipaddrs.rem_addr,
1193 		    remhe->h_length);
1194 		FREE_HE(remhe);
1195 	} else {
1196 		/* make sure we have at least 16-bit alignment */
1197 		if (remidlen & 0x1)
1198 			remidlen++;
1199 		psp->ps_remoteid_len = sizeof (sadb_ident_t) + remidlen;
1200 		sidp = (sadb_ident_t *)((int)psp + psp->ps_remoteid_off);
1201 		sidp->sadb_ident_len = psp->ps_remoteid_len;
1202 		sidp->sadb_ident_type = remidtype;
1203 		(void) strlcpy((char *)(sidp + 1), remid, a_remidtotal);
1204 	}
1205 
1206 	psp->ps_key_off = psp->ps_remoteid_off + a_remidtotal;
1207 	psp->ps_key_len = keylen;
1208 	psp->ps_key_bits = keybits;
1209 	(void) memcpy((uint8_t *)((int)psp + psp->ps_key_off), keyp, keylen);
1210 	if (locpfx != NULL && ((pfxlen = atoi(locpfx)) > 0))
1211 		psp->ps_localid_plen = pfxlen;
1212 	if (rempfx != NULL && ((pfxlen = atoi(rempfx)) > 0))
1213 		psp->ps_remoteid_plen = pfxlen;
1214 
1215 	*presharedpp = psp;
1216 
1217 	return (c);
1218 
1219 bail:
1220 	if (loche != NULL)
1221 		FREE_HE(loche);
1222 	if (remhe != NULL)
1223 		FREE_HE(remhe);
1224 	if (keyp != NULL)
1225 		free(keyp);
1226 	if (psp != NULL)
1227 		free(psp);
1228 
1229 	*presharedpp = NULL;
1230 
1231 	return (-1);
1232 }
1233 
1234 /*
1235  * Printing functions
1236  *
1237  * A potential point of confusion here is that the ikeadm-specific string-
1238  * producing functions do not match the ipsec_util.c versions in style: the
1239  * ikeadm-specific functions return a string (and are named foostr), while
1240  * the ipsec_util.c functions actually print the string to the file named
1241  * in the second arg to the function (and are named dump_foo).
1242  *
1243  * Localization for ikeadm seems more straightforward when complete
1244  * phrases are translated rather than: a part of a phrase, a call to
1245  * dump_foo(), and more of the phrase.  It could also accommodate
1246  * non-English grammar more easily.
1247  */
1248 
1249 static char *
1250 errstr(int err)
1251 {
1252 	static char	rtn[MAXLINESIZE];
1253 
1254 	switch (err) {
1255 	case IKE_ERR_NO_OBJ:
1256 		return (gettext("No data returned"));
1257 	case IKE_ERR_NO_DESC:
1258 		return (gettext("No destination provided"));
1259 	case IKE_ERR_ID_INVALID:
1260 		return (gettext("Id info invalid"));
1261 	case IKE_ERR_LOC_INVALID:
1262 		return (gettext("Destination invalid"));
1263 	case IKE_ERR_CMD_INVALID:
1264 		return (gettext("Command invalid"));
1265 	case IKE_ERR_DATA_INVALID:
1266 		return (gettext("Supplied data invalid"));
1267 	case IKE_ERR_CMD_NOTSUP:
1268 		return (gettext("Unknown command"));
1269 	case IKE_ERR_REQ_INVALID:
1270 		return (gettext("Request invalid"));
1271 	case IKE_ERR_NO_PRIV:
1272 		return (gettext("Not allowed at current privilege level"));
1273 	case IKE_ERR_NO_AUTH:
1274 		return (gettext("User not authorized"));
1275 	case IKE_ERR_SYS_ERR:
1276 		return (gettext("System error"));
1277 	case IKE_ERR_DUP_IGNORED:
1278 		return (gettext("One or more duplicate entries ignored"));
1279 	case IKE_ERR_NO_TOKEN:
1280 		return (gettext(
1281 		    "token login failed or no objects on device"));
1282 	case IKE_ERR_IN_PROGRESS:
1283 		return (gettext(
1284 		    "Duplicate operation already in progress"));
1285 	case IKE_ERR_NO_MEM:
1286 		return (gettext(
1287 		    "Insufficient memory"));
1288 	default:
1289 		(void) snprintf(rtn, MAXLINESIZE,
1290 		    gettext("<unknown error %d>"), err);
1291 		return (rtn);
1292 	}
1293 }
1294 
1295 static char *
1296 dbgstr(int bit)
1297 {
1298 	static char	rtn[MAXLINESIZE];
1299 
1300 	switch (bit) {
1301 	case D_CERT:
1302 		return (gettext("Certificate management"));
1303 	case D_KEY:
1304 		return (gettext("Key management"));
1305 	case D_OP:
1306 		return (gettext("Operational"));
1307 	case D_P1:
1308 		return (gettext("Phase 1 SA creation"));
1309 	case D_P2:
1310 		return (gettext("Phase 2 SA creation"));
1311 	case D_PFKEY:
1312 		return (gettext("PF_KEY interface"));
1313 	case D_POL:
1314 		return (gettext("Policy management"));
1315 	case D_PROP:
1316 		return (gettext("Proposal construction"));
1317 	case D_DOOR:
1318 		return (gettext("Door interface"));
1319 	case D_CONFIG:
1320 		return (gettext("Config file processing"));
1321 	case D_LABEL:
1322 		return (gettext("MAC label processing"));
1323 	default:
1324 		(void) snprintf(rtn, MAXLINESIZE,
1325 		    gettext("<unknown flag 0x%x>"), bit);
1326 		return (rtn);
1327 	}
1328 }
1329 
1330 static char *
1331 privstr(int priv)
1332 {
1333 	static char	rtn[MAXLINESIZE];
1334 
1335 	switch (priv) {
1336 	case IKE_PRIV_MINIMUM:
1337 		return (gettext("base privileges"));
1338 	case IKE_PRIV_MODKEYS:
1339 		return (gettext("access to preshared key information"));
1340 	case IKE_PRIV_KEYMAT:
1341 		return (gettext("access to keying material"));
1342 	default:
1343 		(void) snprintf(rtn, MAXLINESIZE,
1344 		    gettext("<unknown level %d>"), priv);
1345 		return (rtn);
1346 	}
1347 }
1348 
1349 static char *
1350 xchgstr(int xchg)
1351 {
1352 	static char	rtn[MAXLINESIZE];
1353 
1354 	switch (xchg) {
1355 	case IKE_XCHG_NONE:
1356 		return (gettext("<unspecified>"));
1357 	case IKE_XCHG_BASE:
1358 		return (gettext("base"));
1359 	case IKE_XCHG_IDENTITY_PROTECT:
1360 		return (gettext("main mode (identity protect)"));
1361 	case IKE_XCHG_AUTH_ONLY:
1362 		return (gettext("authentication only"));
1363 	case IKE_XCHG_AGGRESSIVE:
1364 		return (gettext("aggressive mode"));
1365 	case IKE_XCHG_IP_AND_AGGR:
1366 		return (gettext("main and aggressive mode"));
1367 	case IKE_XCHG_ANY:
1368 		return (gettext("any mode"));
1369 	default:
1370 		(void) snprintf(rtn, MAXLINESIZE,
1371 		    gettext("<unknown %d>"), xchg);
1372 		return (rtn);
1373 	}
1374 }
1375 
1376 static char *
1377 statestr(int state)
1378 {
1379 	static char	rtn[MAXLINESIZE];
1380 
1381 	switch (state) {
1382 	case IKE_SA_STATE_INIT:
1383 		return (gettext("INITIALIZING"));
1384 	case IKE_SA_STATE_SENT_SA:
1385 		return (gettext("SENT FIRST MSG (SA)"));
1386 	case IKE_SA_STATE_SENT_KE:
1387 		return (gettext("SENT SECOND MSG (KE)"));
1388 	case IKE_SA_STATE_SENT_LAST:
1389 		return (gettext("SENT FINAL MSG"));
1390 	case IKE_SA_STATE_DONE:
1391 		return (gettext("ACTIVE"));
1392 	case IKE_SA_STATE_DELETED:
1393 		return (gettext("DELETED"));
1394 	case IKE_SA_STATE_INVALID:
1395 		return (gettext("<invalid>"));
1396 	default:
1397 		(void) snprintf(rtn, MAXLINESIZE,
1398 		    gettext("<unknown %d>"), state);
1399 		return (rtn);
1400 	}
1401 }
1402 
1403 static char *
1404 authmethstr(int meth)
1405 {
1406 	static char	rtn[MAXLINESIZE];
1407 
1408 	switch (meth) {
1409 	case IKE_AUTH_METH_PRE_SHARED_KEY:
1410 		return (gettext("pre-shared key"));
1411 	case IKE_AUTH_METH_DSS_SIG:
1412 		return (gettext("DSS signatures"));
1413 	case IKE_AUTH_METH_RSA_SIG:
1414 		return (gettext("RSA signatures"));
1415 	case IKE_AUTH_METH_RSA_ENCR:
1416 		return (gettext("RSA Encryption"));
1417 	case IKE_AUTH_METH_RSA_ENCR_REVISED:
1418 		return (gettext("Revised RSA Encryption"));
1419 	default:
1420 		(void) snprintf(rtn, MAXLINESIZE,
1421 		    gettext("<unknown %d>"), meth);
1422 		return (rtn);
1423 	}
1424 }
1425 
1426 static char *
1427 prfstr(int prf)
1428 {
1429 	static char	rtn[MAXLINESIZE];
1430 
1431 	switch (prf) {
1432 	case IKE_PRF_NONE:
1433 		return (gettext("<none/unavailable>"));
1434 	case IKE_PRF_HMAC_MD5:
1435 		return ("HMAC MD5");
1436 	case IKE_PRF_HMAC_SHA1:
1437 		return ("HMAC SHA1");
1438 	case IKE_PRF_HMAC_SHA256:
1439 		return ("HMAC SHA256");
1440 	case IKE_PRF_HMAC_SHA384:
1441 		return ("HMAC SHA384");
1442 	case IKE_PRF_HMAC_SHA512:
1443 		return ("HMAC SHA512");
1444 	default:
1445 		(void) snprintf(rtn, MAXLINESIZE,
1446 		    gettext("<unknown %d>"), prf);
1447 		return (rtn);
1448 	}
1449 }
1450 
1451 static char *
1452 dhstr(int grp)
1453 {
1454 	static char	rtn[MAXLINESIZE];
1455 
1456 	switch (grp) {
1457 	case 0:
1458 		return (gettext("<unavailable>"));
1459 	case IKE_GRP_DESC_MODP_768:
1460 		return (gettext("768-bit MODP (group 1)"));
1461 	case IKE_GRP_DESC_MODP_1024:
1462 		return (gettext("1024-bit MODP (group 2)"));
1463 	case IKE_GRP_DESC_EC2N_155:
1464 		return (gettext("EC2N group on GP[2^155]"));
1465 	case IKE_GRP_DESC_EC2N_185:
1466 		return (gettext("EC2N group on GP[2^185]"));
1467 	case IKE_GRP_DESC_MODP_1536:
1468 		return (gettext("1536-bit MODP (group 5)"));
1469 	case IKE_GRP_DESC_MODP_2048:
1470 		return (gettext("2048-bit MODP (group 14)"));
1471 	case IKE_GRP_DESC_MODP_3072:
1472 		return (gettext("3072-bit MODP (group 15)"));
1473 	case IKE_GRP_DESC_MODP_4096:
1474 		return (gettext("4096-bit MODP (group 16)"));
1475 	case IKE_GRP_DESC_MODP_6144:
1476 		return (gettext("6144-bit MODP (group 17)"));
1477 	case IKE_GRP_DESC_MODP_8192:
1478 		return (gettext("8192-bit MODP (group 18)"));
1479 	case IKE_GRP_DESC_ECP_256:
1480 		return (gettext("256-bit ECP (group 19)"));
1481 	case IKE_GRP_DESC_ECP_384:
1482 		return (gettext("384-bit ECP (group 20)"));
1483 	case IKE_GRP_DESC_ECP_521:
1484 		return (gettext("521-bit ECP (group 21)"));
1485 	case IKE_GRP_DESC_MODP_1024_160:
1486 		return (
1487 		    gettext("1024-bit MODP with 160-bit subprime (group 22)"));
1488 	case IKE_GRP_DESC_MODP_2048_224:
1489 		return (
1490 		    gettext("2048-bit MODP with 224-bit subprime (group 23)"));
1491 	case IKE_GRP_DESC_MODP_2048_256:
1492 		return (
1493 		    gettext("2048-bit MODP with 256-bit subprime (group 24)"));
1494 	case IKE_GRP_DESC_ECP_192:
1495 		return (gettext("192-bit ECP (group 25)"));
1496 	case IKE_GRP_DESC_ECP_224:
1497 		return (gettext("224-bit ECP (group 26)"));
1498 	default:
1499 		(void) snprintf(rtn, MAXLINESIZE, gettext("<unknown %d>"), grp);
1500 		return (rtn);
1501 	}
1502 }
1503 
1504 static void
1505 print_hdr(char *prefix, ike_p1_hdr_t *hdrp)
1506 {
1507 	char sbuf[TBUF_SIZE];
1508 	char tbuf[TBUF_SIZE];
1509 	time_t ltime = (time_t)hdrp->p1hdr_dpd_time;
1510 
1511 	(void) printf(
1512 	    gettext("%s Cookies: Initiator 0x%llx  Responder 0x%llx\n"),
1513 	    prefix, ntohll(hdrp->p1hdr_cookies.cky_i),
1514 	    ntohll(hdrp->p1hdr_cookies.cky_r));
1515 	(void) printf(gettext("%s The local host is the %s.\n"), prefix,
1516 	    hdrp->p1hdr_isinit ? gettext("initiator") : gettext("responder"));
1517 	(void) printf(gettext("%s ISAKMP version %d.%d; %s exchange\n"), prefix,
1518 	    hdrp->p1hdr_major, hdrp->p1hdr_minor, xchgstr(hdrp->p1hdr_xchg));
1519 	(void) printf(gettext("%s Current state is %s\n"), prefix,
1520 	    statestr(hdrp->p1hdr_state));
1521 	if (hdrp->p1hdr_support_dpd == B_FALSE) {
1522 		return;
1523 	}
1524 	(void) printf(gettext("%s Dead Peer Detection (RFC 3706)"
1525 	    " enabled"), prefix);
1526 	if (hdrp->p1hdr_dpd_state < DPD_IN_PROGRESS) {
1527 		(void) printf("\n");
1528 		return;
1529 	}
1530 	if (strftime(tbuf, TBUF_SIZE, NULL,
1531 	    localtime(&ltime)) == 0) {
1532 		(void) strlcpy(tbuf, gettext("<time conversion failed>"),
1533 		    TBUF_SIZE);
1534 	}
1535 	(void) printf(gettext("\n%s Dead Peer Detection handshake "), prefix);
1536 	switch (hdrp->p1hdr_dpd_state) {
1537 	case DPD_SUCCESSFUL:
1538 		(void) strlcpy(sbuf, gettext("was successful at "), TBUF_SIZE);
1539 		break;
1540 	case DPD_FAILURE:
1541 		(void) strlcpy(sbuf, gettext("failed at "), TBUF_SIZE);
1542 		break;
1543 	case DPD_IN_PROGRESS:
1544 		(void) strlcpy(sbuf, gettext("is in progress."), TBUF_SIZE);
1545 		break;
1546 	}
1547 	(void) printf("%s %s", sbuf,
1548 	    (hdrp->p1hdr_dpd_state == DPD_IN_PROGRESS) ? "" : tbuf);
1549 	(void) printf("\n");
1550 }
1551 
1552 static void
1553 print_lt_limits(char *prefix, ike_p1_xform_t *xfp)
1554 {
1555 	char byte_str[BYTE_STR_SIZE]; /* byte lifetime string representation */
1556 	char secs_str[SECS_STR_SIZE]; /* lifetime string representation */
1557 
1558 	(void) printf(gettext("%s Lifetime limits:\n"), prefix);
1559 	(void) printf(gettext("%s %u seconds%s; %u kbytes %sprotected\n"),
1560 	    prefix, xfp->p1xf_max_secs, secs2out(xfp->p1xf_max_secs,
1561 	    secs_str, sizeof (secs_str), SPC_BEGIN), xfp->p1xf_max_kbytes,
1562 	    bytecnt2out((uint64_t)xfp->p1xf_max_kbytes << 10, byte_str,
1563 	    sizeof (byte_str), SPC_END));
1564 	(void) printf(gettext("%s keying material for IPsec SAs can be "
1565 	    "provided %u times%s\n"), prefix, xfp->p1xf_max_keyuses,
1566 	    xfp->p1xf_max_keyuses == 0 ? " (no limit)" : "");
1567 }
1568 
1569 #define	LT_USAGE_LEN	16	/* 1 uint64 + 2 uint32s */
1570 static void
1571 print_lt_usage(char *prefix, ike_p1_stats_t *sp)
1572 {
1573 	time_t	scratch;
1574 	char	tbuf[TBUF_SIZE];
1575 	char	bytestr[BYTE_STR_SIZE]; /* byte lifetime representation */
1576 
1577 	(void) printf(gettext("%s Current usage:\n"), prefix);
1578 	scratch = (time_t)sp->p1stat_start;
1579 	if (strftime(tbuf, TBUF_SIZE, NULL, localtime(&scratch)) == 0)
1580 		(void) strlcpy(tbuf, gettext("<time conversion failed>"),
1581 		    TBUF_SIZE);
1582 	(void) printf(gettext("%s SA was created at %s\n"), prefix, tbuf);
1583 	(void) printf(gettext("%s %u kbytes %sprotected\n"),
1584 	    prefix, sp->p1stat_kbytes,
1585 	    bytecnt2out((uint64_t)sp->p1stat_kbytes << 10, bytestr,
1586 	    sizeof (bytestr), SPC_END));
1587 	(void) printf(gettext("%s keying material for IPsec SAs provided "
1588 	    "%u times\n"), prefix, sp->p1stat_keyuses);
1589 }
1590 
1591 static void
1592 print_xform(char *prefix, ike_p1_xform_t *xfp, boolean_t print_lifetimes)
1593 {
1594 	(void) printf(gettext("%s Authentication method: %s"), prefix,
1595 	    authmethstr(xfp->p1xf_auth_meth));
1596 	(void) printf(gettext("\n%s Encryption alg: "), prefix);
1597 	(void) dump_ealg(xfp->p1xf_encr_alg, stdout);
1598 	if (xfp->p1xf_encr_low_bits != 0) {
1599 		(void) printf(gettext("(%d..%d)"), xfp->p1xf_encr_low_bits,
1600 		    xfp->p1xf_encr_high_bits);
1601 	} else if ((xfp->p1xf_encr_low_bits == 0) &&
1602 	    (xfp->p1xf_encr_high_bits != 0)) {
1603 		/*
1604 		 * High bits is a placeholder for
1605 		 * negotiated algorithm strength
1606 		 */
1607 		(void) printf(gettext("(%d)"), xfp->p1xf_encr_high_bits);
1608 	}
1609 	(void) printf(gettext("; Authentication alg: "));
1610 	(void) dump_aalg(xfp->p1xf_auth_alg, stdout);
1611 	(void) printf("\n%s ", prefix);
1612 	if (xfp->p1xf_prf != 0)
1613 		(void) printf(gettext("PRF: %s ; "), prfstr(xfp->p1xf_prf));
1614 	(void) printf(gettext("Oakley Group: %s\n"),
1615 	    dhstr(xfp->p1xf_dh_group));
1616 	if (xfp->p1xf_pfs == 0) {
1617 		(void) printf(gettext("%s Phase 2 PFS is not used\n"), prefix);
1618 	} else {
1619 		(void) printf(gettext(
1620 		    "%s Phase 2 PFS is required (Oakley Group: %s)\n"),
1621 		    prefix, dhstr(xfp->p1xf_pfs));
1622 	}
1623 
1624 	if (print_lifetimes)
1625 		print_lt_limits(prefix, xfp);
1626 }
1627 
1628 static void
1629 print_lifetime(char *prefix, ike_p1_xform_t *xfp, ike_p1_stats_t *sp,
1630     int statlen)
1631 {
1632 	time_t	current, remain, exp;
1633 	char	tbuf[TBUF_SIZE];
1634 	char	byte_str[BYTE_STR_SIZE]; /* byte lifetime representation */
1635 	char	secs_str[SECS_STR_SIZE]; /* seconds lifetime representation */
1636 
1637 	current = time(NULL);
1638 
1639 	print_lt_limits(prefix, xfp);
1640 
1641 	/*
1642 	 * make sure the stats struct we've been passed is as big
1643 	 * as we expect it to be.  The usage stats are at the end,
1644 	 * so anything less than the size we expect won't work.
1645 	 */
1646 	if (statlen >= sizeof (ike_p1_stats_t)) {
1647 		print_lt_usage(prefix, sp);
1648 	} else {
1649 		return;
1650 	}
1651 
1652 	(void) printf(gettext("%s Expiration info:\n"), prefix);
1653 
1654 	if (xfp->p1xf_max_kbytes != 0)
1655 		(void) printf(gettext("%s %u more bytes %scan be "
1656 		    "protected.\n"),
1657 		    prefix, xfp->p1xf_max_kbytes - sp->p1stat_kbytes,
1658 		    bytecnt2out((uint64_t)(xfp->p1xf_max_kbytes -
1659 		    sp->p1stat_kbytes) << 10, byte_str, sizeof (byte_str),
1660 		    SPC_END));
1661 
1662 	if (xfp->p1xf_max_keyuses != 0)
1663 		(void) printf(gettext("%s Keying material can be provided "
1664 		    "%u more times.\n"), prefix,
1665 		    xfp->p1xf_max_keyuses - sp->p1stat_keyuses);
1666 
1667 	if (xfp->p1xf_max_secs != 0) {
1668 		exp = (time_t)sp->p1stat_start + (time_t)xfp->p1xf_max_secs;
1669 		remain = exp - current;
1670 		if (strftime(tbuf, TBUF_SIZE, NULL, localtime(&exp)) == 0)
1671 			(void) strlcpy(tbuf,
1672 			    gettext("<time conversion failed>"), TBUF_SIZE);
1673 		/*
1674 		 * The SA may have expired but still exist because libike
1675 		 * has not freed it yet.
1676 		 */
1677 		if (remain > 0) {
1678 			(void) printf(gettext(
1679 			    "%s SA expires in %lu seconds%s\n"),
1680 			    prefix, remain, secs2out(remain, secs_str,
1681 			    sizeof (secs_str), SPC_BEGIN));
1682 			(void) printf(gettext("%s Time of expiration: %s\n"),
1683 			    prefix, tbuf);
1684 		} else {
1685 			(void) printf(gettext("%s SA Expired at %s\n"),
1686 			    prefix, tbuf);
1687 		}
1688 	}
1689 }
1690 
1691 /* used to verify structure lengths... */
1692 #define	COUNTER_32BIT	4
1693 #define	COUNTER_PAIR	8
1694 
1695 static void
1696 print_p1stats(char *prefix, ike_p1_stats_t *sp, int statlen,
1697     boolean_t print_lifetimes)
1698 {
1699 	if (statlen < COUNTER_PAIR)
1700 		return;
1701 	(void) printf(gettext("%s %u Quick Mode SAs created; "), prefix,
1702 	    sp->p1stat_new_qm_sas);
1703 	(void) printf(gettext("%u Quick Mode SAs deleted\n"),
1704 	    sp->p1stat_del_qm_sas);
1705 	statlen -= COUNTER_PAIR;
1706 
1707 	if ((print_lifetimes) && (statlen >= LT_USAGE_LEN))
1708 		print_lt_usage(prefix, sp);
1709 }
1710 
1711 static void
1712 print_errs(char *prefix, ike_p1_errors_t *errp, int errlen)
1713 {
1714 	/*
1715 	 * Don't try to break this one up; it's either all or nothing!
1716 	 */
1717 	if (errlen < sizeof (ike_p1_errors_t))
1718 		return;
1719 
1720 	(void) printf(gettext("%s %u RX errors: "), prefix,
1721 	    errp->p1err_decrypt + errp->p1err_hash + errp->p1err_otherrx);
1722 	(void) printf(gettext("%u decryption, %u hash, %u other\n"),
1723 	    errp->p1err_decrypt, errp->p1err_hash, errp->p1err_otherrx);
1724 	(void) printf(gettext("%s %u TX errors\n"), prefix, errp->p1err_tx);
1725 }
1726 
1727 static void
1728 print_addr_range(char *prefix, ike_addr_pr_t *pr)
1729 {
1730 	boolean_t	range = B_TRUE;
1731 	struct sockaddr_storage	*beg, *end;
1732 	struct sockaddr_in	*bsin, *esin;
1733 	struct sockaddr_in6	*bsin6, *esin6;
1734 
1735 	beg = &pr->beg_iprange;
1736 	end = &pr->end_iprange;
1737 
1738 	if (beg->ss_family != end->ss_family) {
1739 		(void) printf(gettext("%s invalid address range\n"), prefix);
1740 		return;
1741 	}
1742 
1743 	switch (beg->ss_family) {
1744 	case AF_INET:
1745 		bsin = (struct sockaddr_in *)beg;
1746 		esin = (struct sockaddr_in *)end;
1747 		if ((uint32_t)bsin->sin_addr.s_addr ==
1748 		    (uint32_t)esin->sin_addr.s_addr)
1749 			range = B_FALSE;
1750 		break;
1751 	case AF_INET6:
1752 		bsin6 = (struct sockaddr_in6 *)beg;
1753 		esin6 = (struct sockaddr_in6 *)end;
1754 		if (IN6_ARE_ADDR_EQUAL(&bsin6->sin6_addr, &esin6->sin6_addr))
1755 			range = B_FALSE;
1756 		break;
1757 	default:
1758 		(void) printf(gettext("%s invalid address range\n"), prefix);
1759 		return;
1760 	}
1761 
1762 	(void) printf("%s ", prefix);
1763 	(void) dump_sockaddr((struct sockaddr *)beg, 0, B_TRUE, stdout, nflag);
1764 	if (range) {
1765 		(void) printf(" - ");
1766 		(void) dump_sockaddr((struct sockaddr *)end, 0, B_TRUE, stdout,
1767 		    nflag);
1768 	}
1769 	(void) printf("\n");
1770 
1771 }
1772 
1773 /*
1774  * used to tell printing function if info should be identified
1775  * as belonging to initiator, responder, or neither
1776  */
1777 #define	IS_INITIATOR	1
1778 #define	IS_RESPONDER	2
1779 #define	DONT_PRINT_INIT	3
1780 
1781 static void
1782 print_addr(char *prefix, struct sockaddr_storage *sa, int init_instr,
1783     int mask)
1784 {
1785 	(void) printf(gettext("%s Address"), prefix);
1786 
1787 	if (init_instr != DONT_PRINT_INIT)
1788 		(void) printf(" (%s):\n", (init_instr == IS_INITIATOR) ?
1789 		    gettext("Initiator") : gettext("Responder"));
1790 	else
1791 		(void) printf(":\n");
1792 
1793 	(void) printf("%s ", prefix);
1794 	(void) dump_sockaddr((struct sockaddr *)sa, mask, B_FALSE, stdout,
1795 	    nflag);
1796 }
1797 
1798 static void
1799 print_id(char *prefix, sadb_ident_t *idp, int init_instr)
1800 {
1801 	boolean_t	canprint;
1802 
1803 	switch (init_instr) {
1804 	case IS_INITIATOR:
1805 		(void) printf(gettext("%s Initiator identity, "), prefix);
1806 		break;
1807 	case IS_RESPONDER:
1808 		(void) printf(gettext("%s Responder identity, "), prefix);
1809 		break;
1810 	case DONT_PRINT_INIT:
1811 		(void) printf(gettext("%s Identity, "), prefix);
1812 		break;
1813 	default:
1814 		(void) printf(gettext("<invalid identity>\n"));
1815 		return;
1816 	}
1817 	(void) printf(gettext("uid=%d, type "), idp->sadb_ident_id);
1818 	canprint = dump_sadb_idtype(idp->sadb_ident_type, stdout, NULL);
1819 	if (canprint) {
1820 		(void) printf("\n%s %s\n", prefix, (char *)(idp + 1));
1821 	} else {
1822 		(void) printf(gettext("\n%s "), prefix);
1823 		print_asn1_name(stdout,
1824 		    (const unsigned char *)(idp + 1),
1825 		    SADB_64TO8(idp->sadb_ident_len) - sizeof (sadb_ident_t));
1826 	}
1827 }
1828 
1829 static void
1830 print_idspec(char *prefix, char *idp, int icnt, int ecnt)
1831 {
1832 	int	i;
1833 
1834 	(void) printf(gettext("%s Identity descriptors:\n"), prefix);
1835 
1836 	for (i = 0; i < icnt; i++) {
1837 		if (i == 0)
1838 			(void) printf(gettext("%s Includes:\n"), prefix);
1839 		(void) printf("%s    %s\n", prefix, idp);
1840 		idp += strlen(idp) + 1;
1841 	}
1842 
1843 	for (i = 0; i < ecnt; i++) {
1844 		if (i == 0)
1845 			(void) printf(gettext("%s Excludes:\n"), prefix);
1846 		(void) printf("%s    %s\n", prefix, idp);
1847 		idp += strlen(idp) + 1;
1848 	}
1849 }
1850 
1851 static void
1852 print_keys(char *prefix, ike_p1_key_t *keyp, int size)
1853 {
1854 	uint32_t	*curp;
1855 	ike_p1_key_t	*p;
1856 	int		ssize;
1857 
1858 	curp = (uint32_t *)keyp;
1859 
1860 	ssize = sizeof (ike_p1_key_t);
1861 
1862 	while ((intptr_t)curp - (intptr_t)keyp < size) {
1863 		size_t p1klen, len;
1864 
1865 		p = (ike_p1_key_t *)curp;
1866 		p1klen = p->p1key_len;
1867 		len = p1klen - ssize;
1868 
1869 		p1klen = roundup(p1klen, sizeof (ike_p1_key_t));
1870 		if (p1klen < ssize) {
1871 			(void) printf(gettext("Short key\n"));
1872 			break;
1873 		}
1874 
1875 		switch (p->p1key_type) {
1876 		case IKE_KEY_PRESHARED:
1877 			(void) printf(gettext("%s Pre-shared key (%d bytes): "),
1878 			    prefix, len);
1879 			break;
1880 		case IKE_KEY_SKEYID:
1881 			(void) printf(gettext("%s SKEYID (%d bytes): "),
1882 			    prefix, len);
1883 			break;
1884 		case IKE_KEY_SKEYID_D:
1885 			(void) printf(gettext("%s SKEYID_d (%d bytes): "),
1886 			    prefix, len);
1887 			break;
1888 		case IKE_KEY_SKEYID_A:
1889 			(void) printf(gettext("%s SKEYID_a (%d bytes): "),
1890 			    prefix, len);
1891 			break;
1892 		case IKE_KEY_SKEYID_E:
1893 			(void) printf(gettext("%s SKEYID_e (%d bytes): "),
1894 			    prefix, len);
1895 			break;
1896 		case IKE_KEY_ENCR:
1897 			(void) printf(gettext("%s Encryption key (%d bytes): "),
1898 			    prefix, len);
1899 			break;
1900 		case IKE_KEY_IV:
1901 			(void) printf(
1902 			    gettext("%s Initialization vector (%d bytes): "),
1903 			    prefix, len);
1904 			break;
1905 		default:
1906 			(void) printf(gettext("%s Unidentified key info %p %d"),
1907 			    prefix, p, p1klen);
1908 			goto badkey;
1909 		}
1910 		(void) dump_key((uint8_t *)(p + 1), SADB_8TO1(len), 0,
1911 		    stdout, B_FALSE);
1912 badkey:
1913 		(void) printf("\n");
1914 		assert(IS_P2ALIGNED(p1klen, 8));
1915 		curp += (p1klen >> 2);
1916 	}
1917 }
1918 
1919 static void
1920 print_group_header(void)
1921 {
1922 	(void) printf(gettext("\nList of Diffie-Hellman groups for setting "
1923 	    "up IKE SAs"));
1924 	(void) printf(gettext("\nThe values match the IPsec attribute "
1925 	    "assigned numbers published by IANA\n\n"));
1926 	(void) printf("%-6s%-9s%-50s\n",
1927 	    gettext("Value"), gettext("Strength"), gettext("Description"));
1928 }
1929 
1930 static void
1931 print_group(ike_group_t *gp)
1932 {
1933 	(void) printf("%-6u%-9u%-50s\n",
1934 	    gp->group_number, gp->group_bits, gp->group_label);
1935 }
1936 
1937 static void
1938 print_encralg_header(void)
1939 {
1940 	(void) printf(gettext("\nList of encryption algorithms for IKE"));
1941 	(void) printf(gettext("\nThe values match the IPsec attribute "
1942 	    "assigned numbers published by IANA\n\n"));
1943 	(void) printf("%-6s%-20s%-15s\n", gettext("Value"),
1944 	    gettext("Name"), gettext("Keylen range"));
1945 }
1946 
1947 static void
1948 print_encralg(ike_encralg_t *ep)
1949 {
1950 	char keylen_str[16];
1951 
1952 	(void) strlcpy(keylen_str, "N/A", sizeof (keylen_str));
1953 	if (ep->encr_keylen_min != 0 || ep->encr_keylen_max != 0)
1954 		(void) snprintf(keylen_str, sizeof (keylen_str), "%d-%d",
1955 		    ep->encr_keylen_min, ep->encr_keylen_max);
1956 	(void) printf("%-6u%-20s%-15s\n",
1957 	    ep->encr_value, ep->encr_name, keylen_str);
1958 }
1959 
1960 static void
1961 print_authalg_header(void)
1962 {
1963 	(void) printf(gettext("\nList of authentication algorithms for IKE"));
1964 	(void) printf(gettext("\nThe values match the IPsec attribute "
1965 	    "assigned numbers published by IANA\n\n"));
1966 	(void) printf("%-6s%-20s\n", gettext("Value"), gettext("Name"));
1967 }
1968 
1969 static void
1970 print_authalg(ike_authalg_t *ap)
1971 {
1972 	(void) printf("%-6u%-20s\n",
1973 	    ap->auth_value, ap->auth_name);
1974 }
1975 
1976 static void
1977 print_p1(ike_p1_sa_t *p1)
1978 {
1979 	ike_p1_stats_t	*sp;
1980 	ike_p1_errors_t	*ep;
1981 	ike_p1_key_t	*kp;
1982 	sadb_ident_t	*lidp, *ridp;
1983 	int		lstat, rstat;
1984 
1985 	(void) printf("\n");
1986 	print_hdr("IKESA:", &p1->p1sa_hdr);
1987 	print_xform("XFORM:", &p1->p1sa_xform, B_FALSE);
1988 
1989 	if (p1->p1sa_hdr.p1hdr_isinit) {
1990 		lstat = IS_INITIATOR;
1991 		rstat = IS_RESPONDER;
1992 	} else {
1993 		lstat = IS_RESPONDER;
1994 		rstat = IS_INITIATOR;
1995 	}
1996 	print_addr("LOCIP:", &p1->p1sa_ipaddrs.loc_addr, lstat, 0);
1997 	print_addr("REMIP:", &p1->p1sa_ipaddrs.rem_addr, rstat, 0);
1998 
1999 	/*
2000 	 * the stat len might be 0; but still make the call
2001 	 * to print_lifetime() to pick up the xform info
2002 	 */
2003 	sp = (ike_p1_stats_t *)((int)(p1) + p1->p1sa_stat_off);
2004 	print_lifetime("LIFTM:", &p1->p1sa_xform, sp, p1->p1sa_stat_len);
2005 
2006 	if (p1->p1sa_stat_len > 0) {
2007 		print_p1stats("STATS:", sp, p1->p1sa_stat_len, B_FALSE);
2008 	}
2009 
2010 	if (p1->p1sa_error_len > 0) {
2011 		ep = (ike_p1_errors_t *)((int)(p1) + p1->p1sa_error_off);
2012 		print_errs("ERRS: ", ep, p1->p1sa_error_len);
2013 	}
2014 
2015 	if (p1->p1sa_localid_len > 0) {
2016 		lidp = (sadb_ident_t *)((int)(p1) + p1->p1sa_localid_off);
2017 		print_id("LOCID:", lidp, lstat);
2018 	}
2019 
2020 	if (p1->p1sa_remoteid_len > 0) {
2021 		ridp = (sadb_ident_t *)((int)(p1) + p1->p1sa_remoteid_off);
2022 		print_id("REMID:", ridp, rstat);
2023 	}
2024 
2025 	if (p1->p1sa_key_len > 0) {
2026 		kp = (ike_p1_key_t *)((int)(p1) + p1->p1sa_key_off);
2027 		print_keys("KEY:  ", kp, p1->p1sa_key_len);
2028 	}
2029 }
2030 
2031 static void
2032 print_certcache(ike_certcache_t *c)
2033 {
2034 	(void) printf("\n");
2035 
2036 	(void) printf(gettext("CERTIFICATE CACHE ID: %d\n"), c->cache_id);
2037 	(void) printf(gettext("\tSubject Name: <%s>\n"),
2038 	    (c->subject != NULL) ? c->subject : gettext("Name unavailable"));
2039 	(void) printf(gettext("\t Issuer Name: <%s>\n"),
2040 	    (c->issuer != NULL) ? c->issuer : gettext("Name unavailable"));
2041 	if ((int)c->certclass == -1)
2042 		(void) printf(gettext("\t\t[trusted certificate]\n"));
2043 	switch (c->linkage) {
2044 	case CERT_OFF_WIRE:
2045 		(void) printf(gettext("\t\t[Public certificate only]\n"));
2046 		(void) printf(gettext(
2047 		    "\t\t[Obtained via certificate payload]\n"));
2048 		break;
2049 	case CERT_NO_PRIVKEY:
2050 		(void) printf(gettext("\t\t[Public certificate only]\n"));
2051 		break;
2052 	case CERT_PRIVKEY_LOCKED:
2053 		(void) printf(gettext(
2054 		    "\t\t[Private key linked but locked]\n"));
2055 		break;
2056 	case CERT_PRIVKEY_AVAIL:
2057 		(void) printf(gettext("\t\t[Private key available]\n"));
2058 		break;
2059 	}
2060 }
2061 
2062 static void
2063 print_ps(ike_ps_t *ps)
2064 {
2065 	sadb_ident_t	*lidp, *ridp;
2066 	uint8_t		*keyp;
2067 
2068 	(void) printf("\n");
2069 
2070 	(void) printf(gettext("PSKEY: For %s exchanges\n"),
2071 	    xchgstr(ps->ps_ike_mode));
2072 
2073 	if (ps->ps_key_len > 0) {
2074 		keyp = (uint8_t *)((int)(ps) + ps->ps_key_off);
2075 		(void) printf(gettext("PSKEY: Pre-shared key (%d bytes): "),
2076 		    ps->ps_key_len);
2077 		(void) dump_key(keyp, ps->ps_key_bits, 0, stdout, B_FALSE);
2078 		(void) printf("\n");
2079 	}
2080 
2081 	/*
2082 	 * We get *either* and address or an ident, never both.  So if
2083 	 * the ident is there, don't try printing an address.
2084 	 */
2085 	if (ps->ps_localid_len > 0) {
2086 		lidp = (sadb_ident_t *)
2087 		    ((int)(ps) + ps->ps_localid_off);
2088 		print_id("LOCID:", lidp, DONT_PRINT_INIT);
2089 	} else {
2090 		print_addr("LOCIP:", &ps->ps_ipaddrs.loc_addr, DONT_PRINT_INIT,
2091 		    ps->ps_localid_plen > 0 ? ps->ps_localid_plen : 0);
2092 	}
2093 
2094 	if (ps->ps_remoteid_len > 0) {
2095 		ridp = (sadb_ident_t *)
2096 		    ((int)(ps) + ps->ps_remoteid_off);
2097 		print_id("REMID:", ridp, DONT_PRINT_INIT);
2098 	} else {
2099 		print_addr("REMIP:", &ps->ps_ipaddrs.rem_addr, DONT_PRINT_INIT,
2100 		    ps->ps_remoteid_plen > 0 ? ps->ps_remoteid_plen : 0);
2101 	}
2102 }
2103 
2104 #define	PREFIXLEN	16
2105 
2106 static void
2107 print_rule(ike_rule_t *rp)
2108 {
2109 	char		prefix[PREFIXLEN];
2110 	int		i;
2111 	ike_p1_xform_t	*xfp;
2112 	ike_addr_pr_t	*lipp, *ripp;
2113 	char		*lidp, *ridp;
2114 	char byte_str[BYTE_STR_SIZE]; /* kbyte string representation */
2115 	char secs_str[SECS_STR_SIZE]; /* seconds string representation */
2116 
2117 	(void) printf("\n");
2118 	(void) printf(gettext("GLOBL: Label '%s', key manager cookie %u\n"),
2119 	    rp->rule_label, rp->rule_kmcookie);
2120 	(void) printf(gettext("GLOBL: local_idtype="));
2121 	(void) dump_sadb_idtype(rp->rule_local_idtype, stdout, NULL);
2122 	(void) printf(gettext(", ike_mode=%s\n"), xchgstr(rp->rule_ike_mode));
2123 	(void) printf(gettext(
2124 	    "GLOBL: p1_nonce_len=%u, p2_nonce_len=%u, p2_pfs=%s (group %u)\n"),
2125 	    rp->rule_p1_nonce_len, rp->rule_p2_nonce_len,
2126 	    (rp->rule_p2_pfs) ? gettext("true") : gettext("false"),
2127 	    rp->rule_p2_pfs);
2128 	(void) printf(
2129 	    gettext("GLOBL: p2_lifetime=%u seconds%s\n"),
2130 	    rp->rule_p2_lifetime_secs, secs2out(rp->rule_p2_lifetime_secs,
2131 	    secs_str, sizeof (secs_str), SPC_BEGIN));
2132 	(void) printf(
2133 	    gettext("GLOBL: p2_softlife=%u seconds%s\n"),
2134 	    rp->rule_p2_softlife_secs, secs2out(rp->rule_p2_softlife_secs,
2135 	    secs_str, sizeof (secs_str), SPC_BEGIN));
2136 	(void) printf(
2137 	    gettext("GLOBL: p2_idletime=%u seconds%s\n"),
2138 	    rp->rule_p2_idletime_secs, secs2out(rp->rule_p2_idletime_secs,
2139 	    secs_str, sizeof (secs_str), SPC_BEGIN));
2140 	/*
2141 	 * Perform explicit conversion before passing to bytecnt2out()
2142 	 * to avoid integer overflow.
2143 	 */
2144 	(void) printf(
2145 	    gettext("GLOBL: p2_lifetime_kb=%u kilobytes%s\n"),
2146 	    rp->rule_p2_lifetime_kb,
2147 	    bytecnt2out((uint64_t)(rp->rule_p2_lifetime_kb) << 10,
2148 	    byte_str, sizeof (byte_str), SPC_BEGIN));
2149 	(void) printf(
2150 	    gettext("GLOBL: p2_softlife_kb=%u kilobytes%s\n"),
2151 	    rp->rule_p2_softlife_kb,
2152 	    bytecnt2out(((uint64_t)(rp->rule_p2_softlife_kb)) << 10,
2153 	    byte_str, sizeof (byte_str), SPC_BEGIN));
2154 
2155 	if (rp->rule_locip_cnt > 0) {
2156 		(void) printf(gettext("LOCIP: IP address range(s):\n"));
2157 		lipp = (ike_addr_pr_t *)((int)rp + rp->rule_locip_off);
2158 		for (i = 0; i < rp->rule_locip_cnt; i++, lipp++) {
2159 			print_addr_range("LOCIP:", lipp);
2160 		}
2161 	}
2162 
2163 	if (rp->rule_remip_cnt > 0) {
2164 		(void) printf(gettext("REMIP: IP address range(s):\n"));
2165 		ripp = (ike_addr_pr_t *)((int)rp + rp->rule_remip_off);
2166 		for (i = 0; i < rp->rule_remip_cnt; i++, ripp++) {
2167 			print_addr_range("REMIP:", ripp);
2168 		}
2169 	}
2170 
2171 	if (rp->rule_locid_inclcnt + rp->rule_locid_exclcnt > 0) {
2172 		lidp = (char *)((int)rp + rp->rule_locid_off);
2173 		print_idspec("LOCID:", lidp, rp->rule_locid_inclcnt,
2174 		    rp->rule_locid_exclcnt);
2175 	}
2176 
2177 	if (rp->rule_remid_inclcnt + rp->rule_remid_exclcnt > 0) {
2178 		ridp = (char *)((int)rp + rp->rule_remid_off);
2179 		print_idspec("REMID:", ridp, rp->rule_remid_inclcnt,
2180 		    rp->rule_remid_exclcnt);
2181 	}
2182 
2183 	if (rp->rule_xform_cnt > 0) {
2184 		(void) printf(gettext("XFRMS: Available Transforms:\n"));
2185 		xfp = (ike_p1_xform_t *)((int)rp +  rp->rule_xform_off);
2186 		for (i = 0; i < rp->rule_xform_cnt; i++, xfp++) {
2187 			(void) snprintf(prefix, PREFIXLEN, "XF %2u:", i);
2188 			print_xform(prefix, xfp, B_TRUE);
2189 		}
2190 	}
2191 }
2192 
2193 #undef	PREFIXLEN
2194 
2195 #define	PRSACNTS(init, resp) \
2196 		(void) printf(gettext("initiator: %10u   responder: %10u\n"), \
2197 		    (init), (resp))
2198 
2199 static void
2200 print_stats(ike_stats_t *sp, int len)
2201 {
2202 	/*
2203 	 * before printing each line, make sure the structure we were
2204 	 * given is big enough to include the fields needed.
2205 	 */
2206 	if (len < COUNTER_PAIR)
2207 		return;
2208 	(void) printf(gettext("Phase 1 SA counts:\n"));
2209 	(void) printf(gettext("Current:   "));
2210 	PRSACNTS(sp->st_init_p1_current, sp->st_resp_p1_current);
2211 	len -= COUNTER_PAIR;
2212 
2213 	if (len < COUNTER_PAIR)
2214 		return;
2215 	(void) printf(gettext("Total:     "));
2216 	PRSACNTS(sp->st_init_p1_total, sp->st_resp_p1_total);
2217 	len -= COUNTER_PAIR;
2218 
2219 	if (len < COUNTER_PAIR)
2220 		return;
2221 	(void) printf(gettext("Attempted: "));
2222 	PRSACNTS(sp->st_init_p1_attempts, sp->st_resp_p1_attempts);
2223 	len -= COUNTER_PAIR;
2224 
2225 	if (len < (COUNTER_PAIR + COUNTER_32BIT))
2226 		return;
2227 	(void) printf(gettext("Failed:    "));
2228 	PRSACNTS(sp->st_init_p1_noresp + sp->st_init_p1_respfail,
2229 	    sp->st_resp_p1_fail);
2230 	(void) printf(
2231 	    gettext("           initiator fails include %u time-out(s)\n"),
2232 	    sp->st_init_p1_noresp);
2233 
2234 	if (len < PATH_MAX)
2235 		return;
2236 	if (*(sp->st_pkcs11_libname) != '\0')
2237 		(void) printf(gettext("PKCS#11 library linked in from %s\n"),
2238 		    sp->st_pkcs11_libname);
2239 }
2240 
2241 /* Print one line of 'get defaults' output (i.e. single value). */
2242 static void
2243 print_defaults(char *label, char *description, char *unit,
2244     uint_t current, uint_t def)
2245 {
2246 	(void) printf("%-18s%-10s%11u %-10s%-26s\n", label,
2247 	    (current != def) ? gettext("config") : gettext("default"),
2248 	    current, unit, description);
2249 }
2250 
2251 /*
2252  * Print out defaults used by in.iked, the argument is a buffer containing
2253  * two ike_defaults_t's, the first contains the hard coded defaults, the second
2254  * contains the actual values used. If these differ, then the defaults have been
2255  * changed via a config file entry. Note that "-" indicates this default
2256  * is not tunable via ike.config(4) or is system wide tunable.
2257  */
2258 static void
2259 do_print_defaults(ike_defaults_t *dp)
2260 {
2261 	ike_defaults_t *ddp;
2262 	ddp = (ike_defaults_t *)(dp + 1);
2263 
2264 	(void) printf(gettext("\nGlobal defaults. Some values can be"
2265 	    " over-ridden on a per rule basis.\n"));
2266 	(void) printf(gettext("\nSystem defaults are time delayed.\n\n"));
2267 
2268 	(void) printf("%-18s%-10s%-12s%-10s%-26s\n\n",
2269 	    gettext("Token:"), gettext("Source:"), gettext("Value:"),
2270 	    gettext("Unit:"), gettext("Description:"));
2271 
2272 	/* iked tunables */
2273 	print_defaults("p1_lifetime_secs", gettext("phase 1 lifetime"),
2274 	    gettext("seconds"), ddp->rule_p1_lifetime_secs,
2275 	    dp->rule_p1_lifetime_secs);
2276 
2277 	print_defaults("-", gettext("minimum phase 1 lifetime"),
2278 	    gettext("seconds"), ddp->rule_p1_minlife,
2279 	    dp->rule_p1_minlife);
2280 
2281 	print_defaults("p1_nonce_len", gettext("phase 1 nonce length"),
2282 	    gettext("bytes"), ddp->rule_p1_nonce_len,
2283 	    dp->rule_p1_nonce_len);
2284 
2285 	print_defaults("p2_lifetime_secs", gettext("phase 2 lifetime"),
2286 	    gettext("seconds"), ddp->rule_p2_lifetime_secs,
2287 	    dp->rule_p2_lifetime_secs);
2288 
2289 	print_defaults("p2_softlife_secs", gettext("phase 2 soft lifetime"),
2290 	    gettext("seconds"), ddp->rule_p2_softlife_secs,
2291 	    dp->rule_p2_softlife_secs);
2292 
2293 	print_defaults("p2_idletime_secs", gettext("phase 2 idle time"),
2294 	    gettext("seconds"), ddp->rule_p2_idletime_secs,
2295 	    dp->rule_p2_idletime_secs);
2296 
2297 	print_defaults("p2_lifetime_kb", gettext("phase 2 lifetime"),
2298 	    gettext("kilobytes"), ddp->rule_p2_lifetime_kb,
2299 	    dp->rule_p2_lifetime_kb);
2300 
2301 	print_defaults("p2_softlife_kb", gettext("phase 2 soft lifetime"),
2302 	    gettext("kilobytes"), ddp->rule_p2_softlife_kb,
2303 	    dp->rule_p2_softlife_kb);
2304 
2305 	/* system wide tunables */
2306 	print_defaults("-", gettext("system phase 2 lifetime"),
2307 	    gettext("seconds"), ddp->sys_p2_lifetime_secs,
2308 	    dp->sys_p2_lifetime_secs);
2309 
2310 	print_defaults("-", gettext("system phase 2 soft lifetime"),
2311 	    gettext("seconds"), ddp->sys_p2_softlife_secs,
2312 	    dp->sys_p2_softlife_secs);
2313 
2314 	print_defaults("-", gettext("system phase 2 idle time"),
2315 	    gettext("seconds"), ddp->sys_p2_idletime_secs,
2316 	    dp->sys_p2_idletime_secs);
2317 
2318 	print_defaults("-", gettext("system phase 2 lifetime"),
2319 	    gettext("bytes"), ddp->sys_p2_lifetime_bytes,
2320 	    dp->sys_p2_lifetime_bytes);
2321 
2322 	print_defaults("-", gettext("system phase 2 soft lifetime"),
2323 	    gettext("bytes"), ddp->sys_p2_softlife_bytes,
2324 	    dp->sys_p2_softlife_bytes);
2325 
2326 	/* minimum and maximum values */
2327 	print_defaults("-", gettext("minimum phase 2 hard lifetime"),
2328 	    gettext("seconds"), ddp->rule_p2_minlife_hard_secs,
2329 	    dp->rule_p2_minlife_hard_secs);
2330 
2331 	print_defaults("-", gettext("minimum phase 2 soft lifetime"),
2332 	    gettext("seconds"), ddp->rule_p2_minlife_soft_secs,
2333 	    dp->rule_p2_minlife_soft_secs);
2334 
2335 	print_defaults("-", gettext("minimum phase 2 idle lifetime"),
2336 	    gettext("seconds"), ddp->rule_p2_minlife_idle_secs,
2337 	    dp->rule_p2_minlife_idle_secs);
2338 
2339 	print_defaults("-", gettext("minimum phase 2 hard lifetime"),
2340 	    gettext("kilobytes"), ddp->rule_p2_minlife_hard_kb,
2341 	    dp->rule_p2_minlife_hard_kb);
2342 
2343 	print_defaults("-", gettext("minimum phase 2 soft lifetime"),
2344 	    gettext("kilobytes"), ddp->rule_p2_minlife_soft_kb,
2345 	    dp->rule_p2_minlife_soft_kb);
2346 
2347 	print_defaults("-", gettext("minimum phase 2 delta"),
2348 	    gettext("seconds"), ddp->rule_p2_mindiff_secs,
2349 	    dp->rule_p2_mindiff_secs);
2350 
2351 	print_defaults("-", gettext("minimum phase 2 delta"),
2352 	    gettext("kilobytes"), ddp->rule_p2_mindiff_kb,
2353 	    dp->rule_p2_mindiff_kb);
2354 
2355 	print_defaults("-", gettext("maximum phase 2 lifetime"),
2356 	    gettext("seconds"), ddp->rule_p2_maxlife_secs,
2357 	    dp->rule_p2_maxlife_secs);
2358 
2359 	print_defaults("-", gettext("conversion factor"),
2360 	    gettext("kbytes/s"), ddp->conversion_factor,
2361 	    dp->conversion_factor);
2362 
2363 	print_defaults("-", gettext("maximum phase 2 lifetime"),
2364 	    gettext("kilobytes"), ddp->rule_p2_maxlife_kb,
2365 	    dp->rule_p2_maxlife_kb);
2366 
2367 	/* other values */
2368 	print_defaults("p2_nonce_len", gettext("phase 2 nonce length"),
2369 	    gettext("bytes"), ddp->rule_p2_nonce_len,
2370 	    dp->rule_p2_nonce_len);
2371 
2372 	print_defaults("p2_pfs", gettext("phase 2 PFS"),
2373 	    " ", ddp->rule_p2_pfs, dp->rule_p2_pfs);
2374 
2375 	print_defaults("max_certs", gettext("max certificates"),
2376 	    " ", ddp->rule_max_certs, dp->rule_max_certs);
2377 
2378 	print_defaults("-", gettext("IKE port number"),
2379 	    " ", ddp->rule_ike_port, dp->rule_ike_port);
2380 
2381 	print_defaults("-", gettext("NAT-T port number"),
2382 	    " ", ddp->rule_natt_port, dp->rule_natt_port);
2383 }
2384 
2385 static void
2386 print_categories(int level)
2387 {
2388 	int	mask;
2389 
2390 	if (level == 0) {
2391 		(void) printf(gettext("No debug categories enabled.\n"));
2392 		return;
2393 	}
2394 
2395 	(void) printf(gettext("Debug categories enabled:"));
2396 	for (mask = 1; mask <= D_HIGHBIT; mask <<= 1) {
2397 		if (level & mask)
2398 			(void) printf("\n\t%s", dbgstr(mask));
2399 	}
2400 	(void) printf("\n");
2401 }
2402 
2403 /*PRINTFLIKE2*/
2404 static void
2405 ikeadm_err_exit(ike_err_t *err, char *fmt, ...)
2406 {
2407 	va_list	ap;
2408 	char	bailbuf[BUFSIZ];
2409 
2410 	va_start(ap, fmt);
2411 	(void) vsnprintf(bailbuf, BUFSIZ, fmt, ap);
2412 	va_end(ap);
2413 	if ((err != NULL) && (err->ike_err == IKE_ERR_SYS_ERR)) {
2414 		bail_msg("%s: %s", bailbuf, (err->ike_err_unix == 0) ?
2415 		    gettext("<unknown error>") : strerror(err->ike_err_unix));
2416 	} else {
2417 		bail_msg("%s: %s", bailbuf, (err == NULL) ?
2418 		    gettext("<unknown error>") : errstr(err->ike_err));
2419 	}
2420 }
2421 
2422 /*PRINTFLIKE2*/
2423 static void
2424 ikeadm_err_msg(ike_err_t *err, char *fmt, ...)
2425 {
2426 	va_list	ap;
2427 	char	mbuf[BUFSIZ];
2428 
2429 	va_start(ap, fmt);
2430 	(void) vsnprintf(mbuf, BUFSIZ, fmt, ap);
2431 	va_end(ap);
2432 	if ((err != NULL) && (err->ike_err == IKE_ERR_SYS_ERR)) {
2433 		message("%s: %s", mbuf, (err->ike_err_unix == 0) ?
2434 		    gettext("<unknown error>") :
2435 		    ((err->ike_err_unix == EEXIST) ?
2436 		    gettext("Duplicate entry") :
2437 		    strerror(err->ike_err_unix)));
2438 	} else {
2439 		message("%s: %s", mbuf, (err == NULL) ?
2440 		    gettext("<unknown error>") : errstr(err->ike_err));
2441 	}
2442 }
2443 
2444 
2445 /*
2446  * Command functions
2447  */
2448 
2449 /*
2450  * Exploit the fact that ike_dbg_t and ike_priv_t have identical
2451  * formats in the following two functions.
2452  */
2453 static void
2454 do_getvar(int cmd)
2455 {
2456 	ike_service_t	req, *rtn;
2457 	ike_dbg_t	*dreq;
2458 	char		*varname;
2459 
2460 	switch (cmd) {
2461 	case IKE_SVC_GET_DBG:
2462 		varname = gettext("debug");
2463 		break;
2464 	case IKE_SVC_GET_PRIV:
2465 		varname = gettext("privilege");
2466 		break;
2467 	default:
2468 		bail_msg(gettext("unrecognized get command (%d)"), cmd);
2469 	}
2470 
2471 	dreq = &req.svc_dbg;
2472 	dreq->cmd = cmd;
2473 	dreq->dbg_level = 0;
2474 
2475 	rtn = ikedoor_call((char *)&req, sizeof (ike_dbg_t), NULL, 0);
2476 
2477 	if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
2478 		ikeadm_err_exit(&rtn->svc_err,
2479 		    gettext("error getting %s level"), varname);
2480 	}
2481 	dreq = &rtn->svc_dbg;
2482 	(void) printf(gettext("Current %s level is 0x%x"),
2483 	    varname, dreq->dbg_level);
2484 
2485 	if (cmd == IKE_SVC_GET_DBG) {
2486 		(void) printf("\n");
2487 		print_categories(dreq->dbg_level);
2488 	} else {
2489 		(void) printf(gettext(", %s enabled\n"),
2490 		    privstr(dreq->dbg_level));
2491 	}
2492 }
2493 
2494 /*
2495  * Log into a token and unlock all objects
2496  * referenced by PKCS#11 hint files.
2497  */
2498 static void
2499 do_setdel_pin(int cmd, int argc, char **argv)
2500 {
2501 	ike_service_t	req, *rtn;
2502 	ike_pin_t	*preq;
2503 	char		token_label[PKCS11_TOKSIZE];
2504 	char		*token_pin;
2505 	char		prompt[80];
2506 
2507 	if (argc < 1)
2508 		Bail(gettext("Must specify PKCS#11 token object."));
2509 
2510 	preq = &req.svc_pin;
2511 	preq->cmd = cmd;
2512 
2513 	switch (cmd) {
2514 	case IKE_SVC_SET_PIN:
2515 		if (parse_token(argc, argv, token_label) != 0)
2516 			Bail("Invalid syntax for \"token login\"");
2517 		(void) snprintf(prompt, sizeof (prompt),
2518 		    "Enter PIN for PKCS#11 token \'%s\': ", token_label);
2519 		token_pin =
2520 		    getpassphrase(prompt);
2521 		(void) strlcpy((char *)preq->token_pin, token_pin, MAX_PIN_LEN);
2522 		bzero(token_pin, strlen(token_pin));
2523 		break;
2524 	case IKE_SVC_DEL_PIN:
2525 		if (parse_token(argc, argv, token_label) != 0)
2526 			Bail("Invalid syntax for \"token logout\"");
2527 		break;
2528 	default:
2529 		bail_msg(gettext("unrecognized token command (%d)"), cmd);
2530 	}
2531 
2532 	(void) strlcpy(preq->pkcs11_token, token_label, PKCS11_TOKSIZE);
2533 
2534 	rtn = ikedoor_call((char *)&req, sizeof (ike_pin_t), NULL, 0);
2535 	if (cmd == IKE_SVC_SET_PIN)
2536 		bzero(preq->token_pin, sizeof (preq->token_pin));
2537 
2538 	if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
2539 		ikeadm_err_exit(&rtn->svc_err,
2540 		    gettext("PKCS#11 operation"));
2541 	}
2542 	preq = &rtn->svc_pin;
2543 	message(gettext("PKCS#11 operation successful"));
2544 }
2545 
2546 static void
2547 do_setvar(int cmd, int argc, char **argv)
2548 {
2549 	ike_service_t	req, *rtn;
2550 	ike_dbg_t	*dreq;
2551 	door_desc_t	*descp = NULL, desc;
2552 	int		fd, ndesc = 0;
2553 	uint32_t	reqlevel;
2554 	char		*varname;
2555 
2556 	if (argc < 1)
2557 		Bail("unspecified level");
2558 	reqlevel = strtoul(argv[0], NULL, 0);
2559 
2560 	switch (cmd) {
2561 	case IKE_SVC_SET_DBG:
2562 		if (argc > 2)
2563 			Bail("Too many arguments to \"set debug\"");
2564 		varname = gettext("debug");
2565 		if (reqlevel == 0) {
2566 			/* check for a string... */
2567 			reqlevel = parsedbgopts(argv[0]);
2568 		}
2569 		if (reqlevel == D_INVALID)
2570 			bail_msg(gettext("Bad debug flag: %s"), argv[0]);
2571 		break;
2572 	case IKE_SVC_SET_PRIV:
2573 		if (argc > 1)
2574 			Bail("Too many arguments to \"set priv\"");
2575 
2576 		varname = gettext("privilege");
2577 		if (reqlevel == 0) {
2578 			/* check for a string... */
2579 			reqlevel = privstr2num(argv[0]);
2580 		}
2581 		if (reqlevel > IKE_PRIV_MAXIMUM)
2582 			bail_msg(gettext("Bad privilege flag: %s"), argv[0]);
2583 		break;
2584 	default:
2585 		bail_msg(gettext("unrecognized set command (%d)"), cmd);
2586 	}
2587 
2588 	dreq = &req.svc_dbg;
2589 	dreq->cmd = cmd;
2590 	dreq->dbg_level = reqlevel;
2591 
2592 	if ((argc == 2) && (cmd == IKE_SVC_SET_DBG)) {
2593 		fd = open(argv[1], O_RDWR | O_CREAT | O_APPEND,
2594 		    S_IRUSR | S_IWUSR);
2595 		if (fd < 0)
2596 			Bail("open debug file");
2597 		desc.d_data.d_desc.d_descriptor = fd;
2598 		desc.d_attributes = DOOR_DESCRIPTOR;
2599 		descp = &desc;
2600 		ndesc = 1;
2601 	}
2602 
2603 	rtn = ikedoor_call((char *)&req, sizeof (ike_dbg_t), descp, ndesc);
2604 
2605 	if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
2606 		ikeadm_err_exit(&rtn->svc_err,
2607 		    gettext("error setting %s level"), varname);
2608 	}
2609 	dreq = &rtn->svc_dbg;
2610 	(void) printf(
2611 	    gettext("Successfully changed %s level from 0x%x to 0x%x\n"),
2612 	    varname, dreq->dbg_level, reqlevel);
2613 
2614 	if (cmd == IKE_SVC_SET_DBG) {
2615 		print_categories(reqlevel);
2616 	} else {
2617 		(void) printf(gettext("New privilege level 0x%x enables %s\n"),
2618 		    reqlevel, privstr(reqlevel));
2619 	}
2620 }
2621 
2622 static void
2623 do_getstats(int cmd)
2624 {
2625 	ike_service_t	*rtn;
2626 	ike_statreq_t	sreq, *sreqp;
2627 	ike_stats_t	*sp;
2628 
2629 	sreq.cmd = cmd;
2630 
2631 	rtn = ikedoor_call((char *)&sreq, sizeof (ike_statreq_t), NULL, 0);
2632 	if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
2633 		ikeadm_err_exit(&rtn->svc_err, gettext("error getting stats"));
2634 	}
2635 
2636 	sreqp = &rtn->svc_stats;
2637 	sp = (ike_stats_t *)(sreqp + 1);
2638 	print_stats(sp, sreqp->stat_len);
2639 }
2640 
2641 static void
2642 do_getdefs(int cmd)
2643 {
2644 	ike_service_t	*rtn;
2645 	ike_defreq_t	dreq, *dreqp;
2646 	ike_defaults_t	*dp;
2647 
2648 	dreq.cmd = cmd;
2649 
2650 	rtn = ikedoor_call((char *)&dreq, sizeof (ike_defreq_t), NULL, 0);
2651 	if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
2652 		ikeadm_err_exit(&rtn->svc_err,
2653 		    gettext("error getting defaults"));
2654 	}
2655 
2656 	dreqp = &rtn->svc_defaults;
2657 	dp = (ike_defaults_t *)(dreqp + 1);
2658 
2659 	/*
2660 	 * Before printing each line, make sure the structure we were
2661 	 * given is big enough to include the fields needed.
2662 	 * Silently bail out of there is a version mismatch.
2663 	 */
2664 	if (dreqp->stat_len < ((2 * sizeof (ike_defaults_t))
2665 	    + sizeof (ike_defreq_t)) || dreqp->version != DOORVER) {
2666 		return;
2667 	}
2668 	do_print_defaults(dp);
2669 }
2670 
2671 static void
2672 do_dump(int cmd)
2673 {
2674 	char		*name;
2675 	ike_service_t	req, *rtn;
2676 	ike_dump_t	*dreq, *dump;
2677 
2678 	switch (cmd) {
2679 	case IKE_SVC_DUMP_P1S:
2680 		name = gettext("phase 1 SA info");
2681 		break;
2682 	case IKE_SVC_DUMP_RULES:
2683 		name = gettext("policy rules");
2684 		break;
2685 	case IKE_SVC_DUMP_PS:
2686 		name = gettext("preshared keys");
2687 		break;
2688 	case IKE_SVC_DUMP_CERTCACHE:
2689 		name = gettext("certcache");
2690 		break;
2691 	case IKE_SVC_DUMP_GROUPS:
2692 		name = gettext("groups");
2693 		print_group_header();
2694 		break;
2695 	case IKE_SVC_DUMP_ENCRALGS:
2696 		name = gettext("encralgs");
2697 		print_encralg_header();
2698 		break;
2699 	case IKE_SVC_DUMP_AUTHALGS:
2700 		name = gettext("authalgs");
2701 		print_authalg_header();
2702 		break;
2703 	default:
2704 		bail_msg(gettext("unrecognized dump command (%d)"), cmd);
2705 	}
2706 
2707 	dreq = &req.svc_dump;
2708 	dreq->cmd = cmd;
2709 	dreq->dump_len = 0;
2710 	dreq->dump_next = 0;
2711 	do {
2712 		rtn = ikedoor_call((char *)&req, sizeof (ike_dump_t),
2713 		    NULL, 0);
2714 		if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
2715 			if (rtn && (rtn->svc_err.ike_err == IKE_ERR_NO_OBJ)) {
2716 				/* no entries to print */
2717 				break;
2718 			}
2719 			ikeadm_err_exit(&rtn->svc_err,
2720 			    gettext("error getting %s"), name);
2721 		}
2722 		dump = &rtn->svc_dump;
2723 
2724 		switch (cmd) {
2725 		case IKE_SVC_DUMP_P1S:
2726 			print_p1((ike_p1_sa_t *)(dump + 1));
2727 			break;
2728 		case IKE_SVC_DUMP_RULES:
2729 			print_rule((ike_rule_t *)(dump + 1));
2730 			break;
2731 		case IKE_SVC_DUMP_PS:
2732 			print_ps((ike_ps_t *)(dump + 1));
2733 			break;
2734 		case IKE_SVC_DUMP_CERTCACHE:
2735 			print_certcache((ike_certcache_t *)(dump + 1));
2736 			break;
2737 		case IKE_SVC_DUMP_GROUPS:
2738 			print_group((ike_group_t *)(dump + 1));
2739 			break;
2740 		case IKE_SVC_DUMP_ENCRALGS:
2741 			print_encralg((ike_encralg_t *)(dump + 1));
2742 			break;
2743 		case IKE_SVC_DUMP_AUTHALGS:
2744 			print_authalg((ike_authalg_t *)(dump + 1));
2745 			break;
2746 		}
2747 
2748 		dreq->dump_next = dump->dump_next;
2749 
2750 		(void) munmap((char *)rtn, dump->dump_len);
2751 
2752 	} while (dreq->dump_next);
2753 
2754 	(void) printf(gettext("\nCompleted dump of %s\n"), name);
2755 }
2756 
2757 static void
2758 do_getdel_doorcall(int cmd, int idlen, int idtype, char *idp, char *name)
2759 {
2760 	int		totallen;
2761 	char		*p;
2762 	ike_service_t	*reqp, *rtnp;
2763 	ike_get_t	*getp;
2764 	boolean_t	getcmd;
2765 
2766 	getcmd = ((cmd == IKE_SVC_GET_P1) || (cmd == IKE_SVC_GET_RULE) ||
2767 	    (cmd == IKE_SVC_GET_PS));
2768 
2769 	/*
2770 	 * WARNING: to avoid being redundant, this code takes advantage
2771 	 * of the fact that the ike_get_t and ike_del_t structures are
2772 	 * identical (only the field names differ, their function and
2773 	 * size are the same).  If for some reason those structures
2774 	 * change, this code will need to be re-written to accomodate
2775 	 * that difference.
2776 	 */
2777 	totallen = sizeof (ike_get_t) + idlen;
2778 	if ((reqp = (ike_service_t *)malloc(totallen)) == NULL)
2779 		Bail("malloc(id)");
2780 
2781 	getp = &reqp->svc_get;
2782 	getp->cmd = cmd;
2783 	getp->get_len = totallen;
2784 	getp->get_idtype = idtype;
2785 	p = (char *)(getp + 1);
2786 
2787 	(void) memcpy(p, idp, idlen);
2788 
2789 	rtnp = ikedoor_call((char *)reqp, totallen, NULL, 0);
2790 	if ((rtnp == NULL) || (rtnp->svc_err.cmd == IKE_SVC_ERROR)) {
2791 		if (rtnp && (rtnp->svc_err.ike_err == IKE_ERR_NO_OBJ)) {
2792 			message(gettext("Could not find requested %s."), name);
2793 		} else {
2794 			ikeadm_err_msg(&rtnp->svc_err, gettext("error %s %s"),
2795 			    (getcmd) ? gettext("getting") : gettext("deleting"),
2796 			    name);
2797 		}
2798 		free(reqp);
2799 		return;
2800 	}
2801 	getp = &rtnp->svc_get;
2802 
2803 	if (getcmd) {
2804 		switch (cmd) {
2805 		case IKE_SVC_GET_P1:
2806 			print_p1((ike_p1_sa_t *)(getp + 1));
2807 			break;
2808 		case IKE_SVC_GET_PS:
2809 			print_ps((ike_ps_t *)(getp + 1));
2810 			break;
2811 		case IKE_SVC_GET_RULE:
2812 			print_rule((ike_rule_t *)(getp + 1));
2813 			break;
2814 		}
2815 	} else {
2816 		message(gettext("Successfully deleted selected %s."), name);
2817 	}
2818 
2819 	(void) munmap((char *)rtnp, getp->get_len);
2820 	free(reqp);
2821 }
2822 
2823 static void
2824 do_getdel(int cmd, int argc, char **argv)
2825 {
2826 	int		idlen, idtype = 0, i, j;
2827 	int		bytelen1, bytelen2;
2828 	char		*name, *idp, *p, *p1, *p2;
2829 	ike_addr_pr_t	apr;
2830 	ike_cky_pr_t	cpr;
2831 	sadb_ident_t	*sid1p, *sid2p;
2832 	struct hostent	*he1p, *he2p;
2833 	char		label[MAX_LABEL_LEN];
2834 
2835 	if ((argc < 1) || (argv[0] == NULL)) {
2836 		Bail("not enough identification info");
2837 	}
2838 
2839 	switch (cmd) {
2840 	case IKE_SVC_GET_P1:
2841 	case IKE_SVC_DEL_P1:
2842 		name = gettext("phase 1 SA");
2843 		/*
2844 		 * The first token must either be an address (or hostname)
2845 		 * or a cookie.  We require cookies to be entered as hex
2846 		 * numbers, beginning with 0x; so if our token starts with
2847 		 * that, it's a cookie.
2848 		 */
2849 		if (strncmp(argv[0], "0x", 2) == 0) {
2850 			if (parse_cky_pr(argc, argv, &cpr) >= 0) {
2851 				idtype = IKE_ID_CKY_PAIR;
2852 				idlen = sizeof (ike_cky_pr_t);
2853 				idp = (char *)&cpr;
2854 			}
2855 		} else {
2856 			if (parse_addr_pr(argc, argv, &he1p, &he2p) >= 0) {
2857 				idtype = IKE_ID_ADDR_PAIR;
2858 				idlen = sizeof (ike_addr_pr_t);
2859 			}
2860 		}
2861 		break;
2862 
2863 	case IKE_SVC_GET_RULE:
2864 	case IKE_SVC_DEL_RULE:
2865 		name = gettext("policy rule");
2866 		if (parse_label(argc, argv, label) >= 0) {
2867 			idtype = IKE_ID_LABEL;
2868 			idlen = MAX_LABEL_LEN;
2869 			idp = label;
2870 		}
2871 		break;
2872 
2873 	case IKE_SVC_GET_PS:
2874 	case IKE_SVC_DEL_PS:
2875 		name = gettext("preshared key");
2876 		/*
2877 		 * The first token must either be an address or an ident
2878 		 * type.  Check for an ident type to determine which it is.
2879 		 */
2880 		if (parse_idtype(argv[0], NULL) >= 0) {
2881 			if (parse_ident_pr(argc, argv, &sid1p, &sid2p) >= 0) {
2882 				idtype = IKE_ID_IDENT_PAIR;
2883 				idlen = SADB_64TO8(sid1p->sadb_ident_len) +
2884 				    SADB_64TO8(sid2p->sadb_ident_len);
2885 			}
2886 		} else {
2887 			if (parse_addr_pr(argc, argv, &he1p, &he2p) >= 0) {
2888 				idtype = IKE_ID_ADDR_PAIR;
2889 				idlen = sizeof (ike_addr_pr_t);
2890 			}
2891 		}
2892 		break;
2893 
2894 	default:
2895 		bail_msg(gettext("unrecognized get/del command (%d)"), cmd);
2896 	}
2897 
2898 	switch (idtype) {
2899 	case IKE_ID_ADDR_PAIR:
2900 		/*
2901 		 * we might have exploding addrs here; do every possible
2902 		 * combination.
2903 		 */
2904 		i = 0;
2905 		j = 0;
2906 		while ((p1 = he1p->h_addr_list[i++]) != NULL) {
2907 			headdr2sa(p1, &apr.loc_addr, he1p->h_length);
2908 
2909 			while ((p2 = he2p->h_addr_list[j++]) != NULL) {
2910 				headdr2sa(p2, &apr.rem_addr, he2p->h_length);
2911 				do_getdel_doorcall(cmd, idlen, idtype,
2912 				    (char *)&apr, name);
2913 			}
2914 		}
2915 		FREE_HE(he1p);
2916 		FREE_HE(he2p);
2917 		break;
2918 
2919 	case IKE_ID_IDENT_PAIR:
2920 		bytelen1 = SADB_64TO8(sid1p->sadb_ident_len);
2921 		bytelen2 = SADB_64TO8(sid2p->sadb_ident_len);
2922 		if (idlen != bytelen1 + bytelen2)
2923 			Bail("ident syntax error");
2924 		idp = p = (char *)malloc(idlen);
2925 		if (p == NULL)
2926 			Bail("malloc(id)");
2927 		(void) memcpy(p, (char *)sid1p, bytelen1);
2928 		p += bytelen1;
2929 		(void) memcpy(p, (char *)sid2p, bytelen2);
2930 		do_getdel_doorcall(cmd, idlen, idtype, idp, name);
2931 		free(idp);
2932 		free(sid1p);
2933 		free(sid2p);
2934 		break;
2935 
2936 	case IKE_ID_CKY_PAIR:
2937 	case IKE_ID_LABEL:
2938 		do_getdel_doorcall(cmd, idlen, idtype, idp, name);
2939 		break;
2940 
2941 	case 0:
2942 	default:
2943 		bail_msg(gettext("invalid %s identification\n"), name);
2944 	}
2945 }
2946 
2947 /*
2948  * Copy source into target, inserting an escape character ('\') before
2949  * any quotes that appear.  Return true on success, false on failure.
2950  */
2951 static boolean_t
2952 escapequotes(char *target, char *source, int tlen)
2953 {
2954 	int	s, t, len = strlen(source) + 1;
2955 
2956 	if (tlen < len)
2957 		return (B_FALSE);
2958 
2959 	for (s = 0, t = 0; s < len && t < tlen; s++) {
2960 		if (source[s] == '\"')
2961 			target[t++] = '\\';
2962 		target[t++] = source[s];
2963 	}
2964 
2965 	if ((t == tlen) && (s < len))
2966 		return (B_FALSE);
2967 
2968 	return (B_TRUE);
2969 }
2970 
2971 /*
2972  * Return true if the arg following the given keyword should
2973  * be in quotes (i.e. is a string), false if not.
2974  */
2975 static boolean_t
2976 quotedfield(char *keywd)
2977 {
2978 	if ((strncmp(keywd, "label", strlen("label") + 1) == 0) ||
2979 	    (strncmp(keywd, "local_id", strlen("local_id") + 1) == 0) ||
2980 	    (strncmp(keywd, "remote_id", strlen("remote_id") + 1) == 0))
2981 		return (B_TRUE);
2982 
2983 	return (B_FALSE);
2984 }
2985 
2986 static void
2987 do_new(int cmd, int argc, char **argv)
2988 {
2989 	ike_service_t	*rtn;
2990 	ike_new_t	new, *newp = NULL;
2991 	door_desc_t	desc, *descp = NULL;
2992 	int		i, fd, ndesc = 0, buflen;
2993 	char		*name, tmpfilepath[32];
2994 	FILE		*tmpfile;
2995 
2996 	switch (cmd) {
2997 	case IKE_SVC_NEW_PS:
2998 		name = gettext("preshared key");
2999 		break;
3000 	case IKE_SVC_NEW_RULE:
3001 		name = gettext("policy rule");
3002 		break;
3003 	default:
3004 		bail_msg(gettext("unrecognized new command (%d)"), cmd);
3005 	}
3006 
3007 	if (argc == 1) {
3008 		/* We've been given a file to read from */
3009 		fd = open(argv[0], O_RDONLY);
3010 		if (fd < 0)
3011 			Bail("open source file");
3012 
3013 		desc.d_data.d_desc.d_descriptor = fd;
3014 		desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
3015 		descp = &desc;
3016 		ndesc = 1;
3017 
3018 		new.cmd = cmd;
3019 		new.new_len = 0;
3020 		newp = &new;
3021 		buflen = sizeof (ike_new_t);
3022 
3023 	} else if ((argc > 1) && (cmd == IKE_SVC_NEW_PS)) {
3024 		/*
3025 		 * This is an alternative to using the tmpfile method
3026 		 * for preshared keys.  It means we're duplicating the
3027 		 * parsing effort that happens in readps.c; but it
3028 		 * does avoid having the key sitting in a file.
3029 		 */
3030 		ike_ps_t	*psp;
3031 		int		pslen;
3032 
3033 		/*
3034 		 * must be in interactive mode; don't want keys in
3035 		 * the process args.
3036 		 */
3037 		if (!interactive)
3038 			Bail("Must be in interactive mode to add key info.");
3039 		if (parse_ps(argc, argv, &psp, &pslen) < 0) {
3040 			errno = 0;
3041 			Bail("invalid preshared key definition");
3042 		}
3043 		newp = malloc(sizeof (ike_new_t) + pslen);
3044 		if (newp == NULL)
3045 			Bail("alloc pskey");
3046 		newp->cmd = cmd;
3047 		newp->new_len = sizeof (ike_new_t) + pslen;
3048 		(void) memcpy((char *)(newp + 1), psp, pslen);
3049 		buflen = newp->new_len;
3050 		/* parse_ps allocated the ike_ps_t buffer; free it now */
3051 		free(psp);
3052 
3053 	} else if ((argc > 1) && (cmd == IKE_SVC_NEW_RULE)) {
3054 		/*
3055 		 * We've been given the item in argv.  However, parsing
3056 		 * rules can get more than a little messy, and in.iked
3057 		 * already has a great parser for this stuff!  So don't
3058 		 * fool around with trying to do the parsing here. Just
3059 		 * write it out to a tempfile, and send the fd to in.iked.
3060 		 *
3061 		 * We could conceivably do this for preshared keys,
3062 		 * rather than duplicating the parsing effort; but that
3063 		 * would mean the key would be written out to a file,
3064 		 * which isn't such a good idea.
3065 		 */
3066 		boolean_t	doquotes = B_FALSE;
3067 		int		rtn;
3068 
3069 		if ((argv[0][0] != '{') ||
3070 		    (argv[argc - 1][strlen(argv[argc - 1]) - 1] != '}'))
3071 			bail_msg(gettext("improperly formatted %s"), name);
3072 
3073 		/* attempt to use a fairly unpredictable file name... */
3074 		(void) sprintf(tmpfilepath, "/var/run/%x", (int)gethrtime());
3075 		fd = open(tmpfilepath, O_RDWR | O_CREAT | O_EXCL,
3076 		    S_IRUSR | S_IWUSR);
3077 		if (fd < 0)
3078 			Bail("cannot open tmpfile");
3079 
3080 		/* and make it inaccessible asap */
3081 		if (unlink(tmpfilepath) < 0) {
3082 			(void) close(fd);
3083 			Bail("tmpfile error");
3084 		}
3085 
3086 		tmpfile = fdopen(fd, "w");
3087 		if (tmpfile == NULL) {
3088 			(void) close(fd);
3089 			Bail("cannot write to tmpfile");
3090 		}
3091 
3092 		for (i = 0; i < argc; i++) {
3093 			/*
3094 			 * We have to do some gyrations with our string here,
3095 			 * to properly handle quotes.  There are two issues:
3096 			 * - some of the fields of a rule may have embedded
3097 			 *   whitespace, and thus must be quoted on the cmd
3098 			 *   line.  The shell removes the quotes, and gives
3099 			 *   us a single argv string; but we need to put the
3100 			 *   quotes back in when we write the string out to
3101 			 *   file.  The doquotes boolean is set when we
3102 			 *   process a keyword which will be followed by a
3103 			 *   string value (so the NEXT argv element will be
3104 			 *   quoted).
3105 			 * - there might be a quote character in a field,
3106 			 *   that was escaped on the cmdline.  The shell
3107 			 *   removes the escape char, and leaves the quote
3108 			 *   in the string it gives us.  We need to put the
3109 			 *   escape char back in before writing to file.
3110 			 */
3111 			char	field[MAXLINESIZE];
3112 			if (!escapequotes(field, argv[i], MAXLINESIZE))
3113 				Bail("write to tmpfile failed (arg too big)");
3114 			if (doquotes) {
3115 				rtn = fprintf(tmpfile, "\"%s\"\n", field);
3116 				doquotes = B_FALSE;
3117 			} else {
3118 				rtn = fprintf(tmpfile, "%s\n", field);
3119 			}
3120 			if (rtn < 0)
3121 				Bail("write to tmpfile failed");
3122 			/*
3123 			 * check if this is a keyword identifying
3124 			 * a field that needs to be quoted.
3125 			 */
3126 			doquotes = quotedfield(argv[i]);
3127 		}
3128 		if (fflush(tmpfile) == EOF)
3129 			Bail("write to tmpfile failed");
3130 		/* rewind so that the daemon will get the beginning */
3131 		rewind(tmpfile);
3132 
3133 		desc.d_data.d_desc.d_descriptor = fd;
3134 		desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
3135 		descp = &desc;
3136 		ndesc = 1;
3137 
3138 		new.cmd = cmd;
3139 		new.new_len = 0;
3140 		newp = &new;
3141 		buflen = sizeof (ike_new_t);
3142 
3143 	} else {
3144 		/* not enough information! */
3145 		bail_msg(gettext("missing %s description or file name"), name);
3146 	}
3147 
3148 	rtn = ikedoor_call((char *)newp, buflen, descp, ndesc);
3149 
3150 	if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
3151 		ikeadm_err_msg(&rtn->svc_err,
3152 		    gettext("error creating new %s"), name);
3153 	} else {
3154 		message(gettext("Successfully created new %s."), name);
3155 	}
3156 }
3157 
3158 static void
3159 do_flush(int cmd)
3160 {
3161 	ike_service_t	*rtnp;
3162 	ike_flush_t	flush;
3163 
3164 	if (cmd != IKE_SVC_FLUSH_P1S && cmd != IKE_SVC_FLUSH_CERTCACHE) {
3165 		bail_msg(gettext("unrecognized flush command (%d)."), cmd);
3166 	}
3167 
3168 	flush.cmd = cmd;
3169 
3170 	rtnp = ikedoor_call((char *)&flush, sizeof (ike_flush_t), NULL, 0);
3171 	if ((rtnp == NULL) || (rtnp->svc_err.cmd == IKE_SVC_ERROR)) {
3172 		ikeadm_err_exit(&rtnp->svc_err, gettext("error doing flush"));
3173 	}
3174 	if (cmd == IKE_SVC_FLUSH_P1S)
3175 		message(gettext("Successfully flushed P1 SAs."));
3176 	else
3177 		message(gettext("Successfully flushed cert cache."));
3178 }
3179 
3180 static void
3181 do_rw(int cmd, int argc, char **argv)
3182 {
3183 	ike_service_t	*rtnp;
3184 	ike_rw_t	rw;
3185 	door_desc_t	desc, *descp = NULL;
3186 	int		oflag, omode, fd, ndesc = 0;
3187 	char		*op, *obj = NULL;
3188 	boolean_t	writing = B_FALSE;
3189 
3190 	switch (cmd) {
3191 	case IKE_SVC_READ_PS:
3192 		obj = gettext("preshared key");
3193 		/* FALLTHRU */
3194 	case IKE_SVC_READ_RULES:
3195 		if (obj == NULL)
3196 			obj = gettext("policy rule");
3197 		op = gettext("read");
3198 		oflag = O_RDONLY;
3199 		omode = 0;
3200 		break;
3201 
3202 	case IKE_SVC_WRITE_PS:
3203 		obj = gettext("preshared key");
3204 		/* FALLTHRU */
3205 	case IKE_SVC_WRITE_RULES:
3206 		if (obj == NULL)
3207 			obj = gettext("policy rule");
3208 		op = gettext("write");
3209 		oflag = O_RDWR | O_CREAT | O_EXCL;
3210 		omode = S_IRUSR | S_IWUSR;
3211 
3212 		/* for write commands, dest location must be specified */
3213 		if (argc < 1) {
3214 			bail_msg(gettext("destination location required "
3215 			    "to write %ss"), obj);
3216 		}
3217 		writing = B_TRUE;
3218 		break;
3219 
3220 	default:
3221 		bail_msg(gettext("unrecognized read/write command (%d)."), cmd);
3222 	}
3223 
3224 	rw.cmd = cmd;
3225 
3226 	if (argc >= 1) {
3227 		rw.rw_loc = IKE_RW_LOC_USER_SPEC;
3228 		fd = open(argv[0], oflag, omode);
3229 		if (fd < 0)
3230 			Bail("open user-specified file");
3231 
3232 		desc.d_data.d_desc.d_descriptor = fd;
3233 		desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
3234 		descp = &desc;
3235 		ndesc = 1;
3236 	} else {
3237 		rw.rw_loc = IKE_RW_LOC_DEFAULT;
3238 	}
3239 
3240 	rtnp = ikedoor_call((char *)&rw, sizeof (ike_rw_t), descp, ndesc);
3241 	if ((rtnp == NULL) || (rtnp->svc_err.cmd == IKE_SVC_ERROR)) {
3242 		/*
3243 		 * Need to remove the target file in the
3244 		 * case of a failed write command.
3245 		 */
3246 		if (writing) {
3247 			/*
3248 			 * argv[0] must be valid if we're writing; we
3249 			 * exit before setting this boolean if not.
3250 			 */
3251 			(void) unlink(argv[0]);
3252 			(void) close(fd);
3253 
3254 			if ((rtnp != NULL) &&
3255 			    (rtnp->svc_err.ike_err == IKE_ERR_NO_OBJ)) {
3256 				message(gettext("No %s information to write."),
3257 				    obj);
3258 				return;
3259 			}
3260 		}
3261 		ikeadm_err_exit(&rtnp->svc_err, gettext("error doing %s"), op);
3262 	}
3263 	message(gettext("Completed %s of %s configuration information."),
3264 	    op, obj);
3265 }
3266 
3267 static void
3268 do_rbdump()
3269 {
3270 	ike_cmd_t	req;
3271 	ike_service_t	*rtnp;
3272 
3273 	req.cmd = IKE_SVC_DBG_RBDUMP;
3274 
3275 	rtnp = ikedoor_call((char *)&req, sizeof (ike_cmd_t), NULL, 0);
3276 	if ((rtnp == NULL) || (rtnp->svc_err.cmd == IKE_SVC_ERROR)) {
3277 		ikeadm_err_exit(&rtnp->svc_err, gettext("error doing flush"));
3278 	}
3279 	message(gettext("Successfully dumped rulebase; check iked dbg"));
3280 }
3281 
3282 #define	REQ_ARG_CNT	1
3283 
3284 /*ARGSUSED*/
3285 static void
3286 parseit(int argc, char **argv, char *notused, boolean_t notused_either)
3287 {
3288 	int	cmd, cmd_obj_args = 1;
3289 	char	*cmdstr, *objstr;
3290 
3291 	if (interactive) {
3292 		if (argc == 0)
3293 			return;
3294 	}
3295 
3296 	if (argc < REQ_ARG_CNT) {
3297 		usage();
3298 	}
3299 
3300 	cmdstr = argv[0];
3301 	if (argc > REQ_ARG_CNT) {
3302 		cmd_obj_args++;
3303 		objstr = argv[1];
3304 	} else {
3305 		objstr = NULL;
3306 	}
3307 	cmd = parsecmd(cmdstr, objstr);
3308 
3309 	/* skip over args specifying command/object */
3310 	argc -= cmd_obj_args;
3311 	argv += cmd_obj_args;
3312 
3313 	switch (cmd) {
3314 	case IKE_SVC_GET_DEFS:
3315 		if (argc != 0) {
3316 			print_get_help();
3317 			break;
3318 		}
3319 		do_getdefs(cmd);
3320 		break;
3321 	case IKE_SVC_GET_DBG:
3322 	case IKE_SVC_GET_PRIV:
3323 		if (argc != 0) {
3324 			print_get_help();
3325 			break;
3326 		}
3327 		do_getvar(cmd);
3328 		break;
3329 	case IKE_SVC_GET_STATS:
3330 		if (argc != 0) {
3331 			print_get_help();
3332 			break;
3333 		}
3334 		do_getstats(cmd);
3335 		break;
3336 	case IKE_SVC_SET_DBG:
3337 	case IKE_SVC_SET_PRIV:
3338 		do_setvar(cmd, argc, argv);
3339 		break;
3340 	case IKE_SVC_SET_PIN:
3341 	case IKE_SVC_DEL_PIN:
3342 		do_setdel_pin(cmd, argc, argv);
3343 		break;
3344 	case IKE_SVC_DUMP_P1S:
3345 	case IKE_SVC_DUMP_RULES:
3346 	case IKE_SVC_DUMP_GROUPS:
3347 	case IKE_SVC_DUMP_ENCRALGS:
3348 	case IKE_SVC_DUMP_AUTHALGS:
3349 	case IKE_SVC_DUMP_PS:
3350 	case IKE_SVC_DUMP_CERTCACHE:
3351 		if (argc != 0) {
3352 			print_dump_help();
3353 			break;
3354 		}
3355 		do_dump(cmd);
3356 		break;
3357 	case IKE_SVC_GET_P1:
3358 	case IKE_SVC_GET_RULE:
3359 	case IKE_SVC_GET_PS:
3360 	case IKE_SVC_DEL_P1:
3361 	case IKE_SVC_DEL_RULE:
3362 	case IKE_SVC_DEL_PS:
3363 		do_getdel(cmd, argc, argv);
3364 		break;
3365 	case IKE_SVC_NEW_RULE:
3366 	case IKE_SVC_NEW_PS:
3367 		do_new(cmd, argc, argv);
3368 		break;
3369 	case IKE_SVC_FLUSH_P1S:
3370 	case IKE_SVC_FLUSH_CERTCACHE:
3371 		if (argc != 0) {
3372 			print_flush_help();
3373 			break;
3374 		}
3375 		do_flush(cmd);
3376 		break;
3377 	case IKE_SVC_READ_RULES:
3378 	case IKE_SVC_READ_PS:
3379 	case IKE_SVC_WRITE_RULES:
3380 	case IKE_SVC_WRITE_PS:
3381 		do_rw(cmd, argc, argv);
3382 		break;
3383 	case IKEADM_HELP_GENERAL:
3384 		print_help();
3385 		break;
3386 	case IKEADM_HELP_GET:
3387 		print_get_help();
3388 		break;
3389 	case IKEADM_HELP_SET:
3390 		print_set_help();
3391 		break;
3392 	case IKEADM_HELP_ADD:
3393 		print_add_help();
3394 		break;
3395 	case IKEADM_HELP_DEL:
3396 		print_del_help();
3397 		break;
3398 	case IKEADM_HELP_DUMP:
3399 		print_dump_help();
3400 		break;
3401 	case IKEADM_HELP_FLUSH:
3402 		print_flush_help();
3403 		break;
3404 	case IKEADM_HELP_READ:
3405 		print_read_help();
3406 		break;
3407 	case IKEADM_HELP_WRITE:
3408 		print_write_help();
3409 		break;
3410 	case IKEADM_HELP_TOKEN:
3411 		print_token_help();
3412 		break;
3413 	case IKEADM_HELP_HELP:
3414 		print_help_help();
3415 		break;
3416 	case IKEADM_EXIT:
3417 		if (interactive)
3418 			exit(0);
3419 		break;
3420 	case IKE_SVC_DBG_RBDUMP:
3421 		do_rbdump();
3422 		break;
3423 	case IKE_SVC_ERROR:
3424 		usage();
3425 	default:
3426 		exit(0);
3427 	}
3428 }
3429 
3430 int
3431 main(int argc, char **argv)
3432 {
3433 	char	ch;
3434 
3435 	(void) setlocale(LC_ALL, "");
3436 #if !defined(TEXT_DOMAIN)
3437 #define	TEXT_DOMAIN "SYS_TEST"
3438 #endif
3439 	(void) textdomain(TEXT_DOMAIN);
3440 
3441 	while ((ch = getopt(argc, argv, "hpn")) != EOF) {
3442 		switch (ch) {
3443 		case 'h':
3444 			print_help();
3445 			return (0);
3446 		case 'p':
3447 			pflag = B_TRUE;
3448 			break;
3449 		case 'n':
3450 			nflag = B_TRUE;
3451 			break;
3452 		default:
3453 			usage();
3454 		}
3455 	}
3456 	argc -= optind;
3457 	argv += optind;
3458 
3459 	if (open_door() < 0) {
3460 		(void) fprintf(stderr,
3461 		    gettext("Unable to communicate with in.iked\n"));
3462 		Bail("open_door failed");
3463 	}
3464 
3465 	if (*argv == NULL) {
3466 		/* no cmd-line args, do interactive mode */
3467 		do_interactive(stdin, NULL, "ikeadm> ", NULL, parseit,
3468 		    no_match);
3469 	}
3470 
3471 	parseit(argc, argv, NULL, B_FALSE);
3472 
3473 	return (0);
3474 }
3475