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