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