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