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