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