17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
58810c16bSdanmcd  * Common Development and Distribution License (the "License").
68810c16bSdanmcd  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22f02131e0SVladimir Kotal  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
2348bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * NOTE:I'm trying to use "struct sadb_foo" instead of "sadb_foo_t"
287c478bd9Sstevel@tonic-gate  *	as a maximal PF_KEY portability test.
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  *	Also, this is a deliberately single-threaded app, also for portability
317c478bd9Sstevel@tonic-gate  *	to systems without POSIX threads.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/stat.h>
367c478bd9Sstevel@tonic-gate #include <sys/socket.h>
377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
387c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
397c478bd9Sstevel@tonic-gate #include <net/pfkeyv2.h>
407c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
417c478bd9Sstevel@tonic-gate #include <netinet/in.h>
427c478bd9Sstevel@tonic-gate #include <sys/uio.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include <syslog.h>
457c478bd9Sstevel@tonic-gate #include <signal.h>
467c478bd9Sstevel@tonic-gate #include <unistd.h>
477c478bd9Sstevel@tonic-gate #include <limits.h>
487c478bd9Sstevel@tonic-gate #include <stdlib.h>
497c478bd9Sstevel@tonic-gate #include <stdio.h>
50e3320f40Smarkfen #include <stdarg.h>
517c478bd9Sstevel@tonic-gate #include <netdb.h>
527c478bd9Sstevel@tonic-gate #include <pwd.h>
537c478bd9Sstevel@tonic-gate #include <errno.h>
547c478bd9Sstevel@tonic-gate #include <libintl.h>
557c478bd9Sstevel@tonic-gate #include <locale.h>
567c478bd9Sstevel@tonic-gate #include <fcntl.h>
577c478bd9Sstevel@tonic-gate #include <strings.h>
587c478bd9Sstevel@tonic-gate #include <ctype.h>
599c2c14abSThejaswini Singarajipura #include <sys/cladm.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #include <ipsec_util.h>
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate static int keysock;
649c2c14abSThejaswini Singarajipura static int cluster_socket;
657c478bd9Sstevel@tonic-gate static uint32_t seq;
667c478bd9Sstevel@tonic-gate static pid_t mypid;
677c478bd9Sstevel@tonic-gate static boolean_t vflag = B_FALSE;	/* Verbose? */
68e3320f40Smarkfen static boolean_t cflag = B_FALSE;	/* Check Only */
69e3320f40Smarkfen 
70e3320f40Smarkfen char *my_fmri = NULL;
71e3320f40Smarkfen FILE *debugfile = stdout;
729c2c14abSThejaswini Singarajipura static struct sockaddr_in cli_addr;
739c2c14abSThejaswini Singarajipura static boolean_t in_cluster_mode = B_FALSE;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate #define	MAX_GET_SIZE	1024
76e3320f40Smarkfen /*
77ec485834Spwernau  * WARN() and ERROR() do the same thing really, with ERROR() the function
78e3320f40Smarkfen  * that prints the error buffer needs to be called at the end of a code block
79e3320f40Smarkfen  * This will print out all accumulated errors before bailing. The WARN()
80e3320f40Smarkfen  * macro calls handle_errors() in such a way that it prints the message
81e3320f40Smarkfen  * then continues.
82e3320f40Smarkfen  * If the FATAL() macro used call handle_errors() immediately.
83e3320f40Smarkfen  */
84e3320f40Smarkfen #define	ERROR(x, y, z)  x = record_error(x, y, z)
85e3320f40Smarkfen #define	ERROR1(w, x, y, z)  w = record_error(w, x, y, z)
86e3320f40Smarkfen #define	ERROR2(v, w, x, y, z)  v = record_error(v, w, x, y, z)
87e3320f40Smarkfen #define	WARN(x, y, z) ERROR(x, y, z);\
88e3320f40Smarkfen 	handle_errors(x, NULL, B_FALSE, B_FALSE); x = NULL
89e3320f40Smarkfen #define	WARN1(w, x, y, z) ERROR1(w, x, y, z);\
90e3320f40Smarkfen 	handle_errors(w, NULL, B_FALSE, B_FALSE); w = NULL
91e3320f40Smarkfen #define	WARN2(v, w, x, y, z) ERROR2(v, w, x, y, z);\
92e3320f40Smarkfen 	handle_errors(v, NULL, B_FALSE, B_FALSE); v = NULL
93e3320f40Smarkfen #define	FATAL(x, y, z) ERROR(x, y, z);\
94e3320f40Smarkfen 	handle_errors(x, y, B_TRUE, B_TRUE)
95e3320f40Smarkfen #define	FATAL1(w, x, y, z) ERROR1(w, x, y, z);\
96e3320f40Smarkfen 	handle_errors(w, x, B_TRUE, B_TRUE)
97e3320f40Smarkfen 
987c478bd9Sstevel@tonic-gate /* Defined as a uint64_t array for alignment purposes. */
997c478bd9Sstevel@tonic-gate static uint64_t get_buffer[MAX_GET_SIZE];
1007c478bd9Sstevel@tonic-gate 
101bfe6f8f5SVladimir Kotal /*
102bfe6f8f5SVladimir Kotal  * Disable default TAB completion for now (until some brave soul tackles it).
103bfe6f8f5SVladimir Kotal  */
104bfe6f8f5SVladimir Kotal /* ARGSUSED */
105bfe6f8f5SVladimir Kotal static
CPL_MATCH_FN(no_match)106bfe6f8f5SVladimir Kotal CPL_MATCH_FN(no_match)
107bfe6f8f5SVladimir Kotal {
108bfe6f8f5SVladimir Kotal 	return (0);
109bfe6f8f5SVladimir Kotal }
110bfe6f8f5SVladimir Kotal 
1117c478bd9Sstevel@tonic-gate /*
112e3320f40Smarkfen  * Create/Grow a buffer large enough to hold error messages. If *ebuf
113e3320f40Smarkfen  * is not NULL then it will contain a copy of the command line that
114e3320f40Smarkfen  * triggered the error/warning, copy this into a new buffer or
115e3320f40Smarkfen  * append new messages to the existing buffer.
116e3320f40Smarkfen  */
117e3320f40Smarkfen /*PRINTFLIKE1*/
118e3320f40Smarkfen char *
record_error(char * ep,char * ebuf,char * fmt,...)119e3320f40Smarkfen record_error(char *ep, char *ebuf, char *fmt, ...)
120e3320f40Smarkfen {
121e3320f40Smarkfen 	char *err_ptr;
122e3320f40Smarkfen 	char tmp_buff[1024];
123e3320f40Smarkfen 	va_list ap;
124e3320f40Smarkfen 	int length = 0;
125e3320f40Smarkfen 	err_ptr = ep;
126e3320f40Smarkfen 
127e3320f40Smarkfen 	va_start(ap, fmt);
12872c8fd38Smarkfen 	length = vsnprintf(tmp_buff, sizeof (tmp_buff), fmt, ap);
129e3320f40Smarkfen 	va_end(ap);
130e3320f40Smarkfen 
131e3320f40Smarkfen 	/* There is a new line character */
132e3320f40Smarkfen 	length++;
13372c8fd38Smarkfen 
13472c8fd38Smarkfen 	if (ep == NULL) {
13572c8fd38Smarkfen 		if (ebuf != NULL)
13672c8fd38Smarkfen 			length += strlen(ebuf);
13772c8fd38Smarkfen 	} else  {
13872c8fd38Smarkfen 		length += strlen(ep);
13972c8fd38Smarkfen 	}
14072c8fd38Smarkfen 
14172c8fd38Smarkfen 	if (err_ptr == NULL)
14272c8fd38Smarkfen 		err_ptr = calloc(length, sizeof (char));
14372c8fd38Smarkfen 	else
14472c8fd38Smarkfen 		err_ptr = realloc(err_ptr, length);
14572c8fd38Smarkfen 
146e3320f40Smarkfen 	if (err_ptr == NULL)
147e3320f40Smarkfen 		Bail("realloc() failure");
14872c8fd38Smarkfen 
14972c8fd38Smarkfen 	/*
15072c8fd38Smarkfen 	 * If (ep == NULL) then this is the first error to record,
15172c8fd38Smarkfen 	 * copy in the command line that triggered this error/warning.
15272c8fd38Smarkfen 	 */
15372c8fd38Smarkfen 	if (ep == NULL && ebuf != NULL)
15472c8fd38Smarkfen 		(void) strlcpy(err_ptr, ebuf, length);
15572c8fd38Smarkfen 
15672c8fd38Smarkfen 	/*
15772c8fd38Smarkfen 	 * Now the actual error.
15872c8fd38Smarkfen 	 */
159e3320f40Smarkfen 	(void) strlcat(err_ptr, tmp_buff, length);
160e3320f40Smarkfen 	return (err_ptr);
161e3320f40Smarkfen }
162e3320f40Smarkfen 
163e3320f40Smarkfen /*
164bfe6f8f5SVladimir Kotal  * If not in interactive mode print usage message and exit.
1657c478bd9Sstevel@tonic-gate  */
1667c478bd9Sstevel@tonic-gate static void
usage(void)1677c478bd9Sstevel@tonic-gate usage(void)
1687c478bd9Sstevel@tonic-gate {
1697c478bd9Sstevel@tonic-gate 	if (!interactive) {
1707c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Usage:\t"
1717c478bd9Sstevel@tonic-gate 		    "ipseckey [ -nvp ] | cmd [sa_type] [extfield value]*\n"));
1727c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1737c478bd9Sstevel@tonic-gate 		    gettext("\tipseckey [ -nvp ] -f infile\n"));
1747c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1757c478bd9Sstevel@tonic-gate 		    gettext("\tipseckey [ -nvp ] -s outfile\n"));
176bfe6f8f5SVladimir Kotal 		EXIT_FATAL(NULL);
177bfe6f8f5SVladimir Kotal 	} else {
178bfe6f8f5SVladimir Kotal 		(void) fprintf(stderr,
179bfe6f8f5SVladimir Kotal 		    gettext("Type help or ? for usage info\n"));
180e3320f40Smarkfen 	}
181e3320f40Smarkfen }
182e3320f40Smarkfen 
183e3320f40Smarkfen 
184e3320f40Smarkfen /*
185e3320f40Smarkfen  * Print out any errors, tidy up as required.
186e3320f40Smarkfen  * error pointer ep will be free()'d
187e3320f40Smarkfen  */
188e3320f40Smarkfen void
handle_errors(char * ep,char * ebuf,boolean_t fatal,boolean_t done)189e3320f40Smarkfen handle_errors(char *ep, char *ebuf, boolean_t fatal, boolean_t done)
190e3320f40Smarkfen {
191e3320f40Smarkfen 	if (ep != NULL) {
192e3320f40Smarkfen 		if (my_fmri == NULL) {
193e3320f40Smarkfen 			/*
194*bbf21555SRichard Lowe 			 * For now suppress the errors when run from smf(7)
195e3320f40Smarkfen 			 * because potentially sensitive information could
196e3320f40Smarkfen 			 * end up in a publicly readable logfile.
197e3320f40Smarkfen 			 */
198e3320f40Smarkfen 			(void) fprintf(stdout, "%s\n", ep);
199e3320f40Smarkfen 			(void) fflush(stdout);
200e3320f40Smarkfen 		}
201e3320f40Smarkfen 		free(ep);
202e3320f40Smarkfen 		if (fatal) {
203e3320f40Smarkfen 			if (ebuf != NULL) {
204e3320f40Smarkfen 				free(ebuf);
205e3320f40Smarkfen 			}
206e3320f40Smarkfen 			/* reset command buffer */
207e3320f40Smarkfen 			if (interactive)
208e3320f40Smarkfen 				longjmp(env, 1);
209e3320f40Smarkfen 		} else {
210e3320f40Smarkfen 			return;
211e3320f40Smarkfen 		}
2127c478bd9Sstevel@tonic-gate 	} else {
213e3320f40Smarkfen 		/*
214e3320f40Smarkfen 		 * No errors, if this is the last time that this function
215e3320f40Smarkfen 		 * is called, free(ebuf) and reset command buffer.
216e3320f40Smarkfen 		 */
217e3320f40Smarkfen 		if (done) {
218e3320f40Smarkfen 			if (ebuf != NULL) {
219e3320f40Smarkfen 				free(ebuf);
220e3320f40Smarkfen 			}
221e3320f40Smarkfen 			/* reset command buffer */
222e3320f40Smarkfen 			if (interactive)
223e3320f40Smarkfen 				longjmp(env, 1);
224e3320f40Smarkfen 		}
225e3320f40Smarkfen 		return;
2267c478bd9Sstevel@tonic-gate 	}
22772c8fd38Smarkfen 	EXIT_FATAL(NULL);
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate /*
2317c478bd9Sstevel@tonic-gate  * Initialize a PF_KEY base message.
2327c478bd9Sstevel@tonic-gate  */
2337c478bd9Sstevel@tonic-gate static void
msg_init(struct sadb_msg * msg,uint8_t type,uint8_t satype)2347c478bd9Sstevel@tonic-gate msg_init(struct sadb_msg *msg, uint8_t type, uint8_t satype)
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate 	msg->sadb_msg_version = PF_KEY_V2;
2377c478bd9Sstevel@tonic-gate 	msg->sadb_msg_type = type;
2387c478bd9Sstevel@tonic-gate 	msg->sadb_msg_errno = 0;
2397c478bd9Sstevel@tonic-gate 	msg->sadb_msg_satype = satype;
2407c478bd9Sstevel@tonic-gate 	/* For starters... */
2417c478bd9Sstevel@tonic-gate 	msg->sadb_msg_len = SADB_8TO64(sizeof (*msg));
2427c478bd9Sstevel@tonic-gate 	msg->sadb_msg_reserved = 0;
2437c478bd9Sstevel@tonic-gate 	msg->sadb_msg_seq = ++seq;
2447c478bd9Sstevel@tonic-gate 	msg->sadb_msg_pid = mypid;
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate /*
2487c478bd9Sstevel@tonic-gate  * parseXXX and rparseXXX commands parse input and convert them to PF_KEY
2497c478bd9Sstevel@tonic-gate  * field values, or do the reverse for the purposes of saving the SA tables.
2507c478bd9Sstevel@tonic-gate  * (See the save_XXX functions.)
2517c478bd9Sstevel@tonic-gate  */
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate #define	CMD_NONE	0
2547c478bd9Sstevel@tonic-gate #define	CMD_UPDATE	2
25538d95a78Smarkfen #define	CMD_UPDATE_PAIR	3
25638d95a78Smarkfen #define	CMD_ADD		4
25738d95a78Smarkfen #define	CMD_DELETE	5
25838d95a78Smarkfen #define	CMD_DELETE_PAIR	6
25938d95a78Smarkfen #define	CMD_GET		7
2607c478bd9Sstevel@tonic-gate #define	CMD_FLUSH	9
2617c478bd9Sstevel@tonic-gate #define	CMD_DUMP	10
2627c478bd9Sstevel@tonic-gate #define	CMD_MONITOR	11
2637c478bd9Sstevel@tonic-gate #define	CMD_PMONITOR	12
2647c478bd9Sstevel@tonic-gate #define	CMD_QUIT	13
2657c478bd9Sstevel@tonic-gate #define	CMD_SAVE	14
2667c478bd9Sstevel@tonic-gate #define	CMD_HELP	15
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate /*
2697c478bd9Sstevel@tonic-gate  * Parse the command.
2707c478bd9Sstevel@tonic-gate  */
2717c478bd9Sstevel@tonic-gate static int
parsecmd(char * cmdstr)2727c478bd9Sstevel@tonic-gate parsecmd(char *cmdstr)
2737c478bd9Sstevel@tonic-gate {
2747c478bd9Sstevel@tonic-gate 	static struct cmdtable {
2757c478bd9Sstevel@tonic-gate 		char *cmd;
2767c478bd9Sstevel@tonic-gate 		int token;
2777c478bd9Sstevel@tonic-gate 	} table[] = {
2787c478bd9Sstevel@tonic-gate 		/*
2797c478bd9Sstevel@tonic-gate 		 * Q: Do we want to do GETSPI?
2807c478bd9Sstevel@tonic-gate 		 * A: No, it's for automated key mgmt. only.  Either that,
2817c478bd9Sstevel@tonic-gate 		 *    or it isn't relevant until we support non IPsec SA types.
2827c478bd9Sstevel@tonic-gate 		 */
2837c478bd9Sstevel@tonic-gate 		{"update",		CMD_UPDATE},
28438d95a78Smarkfen 		{"update-pair",		CMD_UPDATE_PAIR},
2857c478bd9Sstevel@tonic-gate 		{"add",			CMD_ADD},
2867c478bd9Sstevel@tonic-gate 		{"delete", 		CMD_DELETE},
28738d95a78Smarkfen 		{"delete-pair",		CMD_DELETE_PAIR},
2887c478bd9Sstevel@tonic-gate 		{"get", 		CMD_GET},
2897c478bd9Sstevel@tonic-gate 		/*
2907c478bd9Sstevel@tonic-gate 		 * Q: And ACQUIRE and REGISTER and EXPIRE?
2917c478bd9Sstevel@tonic-gate 		 * A: not until we support non IPsec SA types.
2927c478bd9Sstevel@tonic-gate 		 */
2937c478bd9Sstevel@tonic-gate 		{"flush",		CMD_FLUSH},
2947c478bd9Sstevel@tonic-gate 		{"dump",		CMD_DUMP},
2957c478bd9Sstevel@tonic-gate 		{"monitor",		CMD_MONITOR},
2967c478bd9Sstevel@tonic-gate 		{"passive_monitor",	CMD_PMONITOR},
2977c478bd9Sstevel@tonic-gate 		{"pmonitor",		CMD_PMONITOR},
2987c478bd9Sstevel@tonic-gate 		{"quit",		CMD_QUIT},
2997c478bd9Sstevel@tonic-gate 		{"exit",		CMD_QUIT},
3007c478bd9Sstevel@tonic-gate 		{"save",		CMD_SAVE},
3017c478bd9Sstevel@tonic-gate 		{"help",		CMD_HELP},
3027c478bd9Sstevel@tonic-gate 		{"?",			CMD_HELP},
3037c478bd9Sstevel@tonic-gate 		{NULL,			CMD_NONE}
3047c478bd9Sstevel@tonic-gate 	};
3057c478bd9Sstevel@tonic-gate 	struct cmdtable *ct = table;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	while (ct->cmd != NULL && strcmp(ct->cmd, cmdstr) != 0)
3087c478bd9Sstevel@tonic-gate 		ct++;
3097c478bd9Sstevel@tonic-gate 	return (ct->token);
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate /*
3137c478bd9Sstevel@tonic-gate  * Convert a number from a command line.  I picked "u_longlong_t" for the
3147c478bd9Sstevel@tonic-gate  * number because we need the largest number available.  Also, the strto<num>
3157c478bd9Sstevel@tonic-gate  * calls don't deal in units of uintNN_t.
3167c478bd9Sstevel@tonic-gate  */
3177c478bd9Sstevel@tonic-gate static u_longlong_t
parsenum(char * num,boolean_t bail,char * ebuf)318e3320f40Smarkfen parsenum(char *num, boolean_t bail, char *ebuf)
3197c478bd9Sstevel@tonic-gate {
320e3320f40Smarkfen 	u_longlong_t rc = 0;
3217c478bd9Sstevel@tonic-gate 	char *end = NULL;
322e3320f40Smarkfen 	char *ep = NULL;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	if (num == NULL) {
325e3320f40Smarkfen 		FATAL(ep, ebuf, gettext("Unexpected end of command line,"
326e3320f40Smarkfen 		    " was expecting a number.\n"));
327e3320f40Smarkfen 		/* NOTREACHED */
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	errno = 0;
3317c478bd9Sstevel@tonic-gate 	rc = strtoull(num, &end, 0);
3327c478bd9Sstevel@tonic-gate 	if (errno != 0 || end == num || *end != '\0') {
3337c478bd9Sstevel@tonic-gate 		if (bail) {
33438d95a78Smarkfen 			FATAL1(ep, ebuf, gettext(
335e3320f40Smarkfen 			"Expecting a number, not \"%s\"!\n"), num);
3367c478bd9Sstevel@tonic-gate 		} else {
3377c478bd9Sstevel@tonic-gate 			/*
3387c478bd9Sstevel@tonic-gate 			 * -1, while not optimal, is sufficiently out of range
3397c478bd9Sstevel@tonic-gate 			 * for most of this function's applications when
3407c478bd9Sstevel@tonic-gate 			 * we don't just bail.
3417c478bd9Sstevel@tonic-gate 			 */
3427c478bd9Sstevel@tonic-gate 			return ((u_longlong_t)-1);
3437c478bd9Sstevel@tonic-gate 		}
3447c478bd9Sstevel@tonic-gate 	}
345e3320f40Smarkfen 	handle_errors(ep, NULL, B_FALSE, B_FALSE);
3467c478bd9Sstevel@tonic-gate 	return (rc);
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate /*
3507c478bd9Sstevel@tonic-gate  * Parse and reverse parse a specific SA type (AH, ESP, etc.).
3517c478bd9Sstevel@tonic-gate  */
3527c478bd9Sstevel@tonic-gate static struct typetable {
3537c478bd9Sstevel@tonic-gate 	char *type;
3547c478bd9Sstevel@tonic-gate 	int token;
3557c478bd9Sstevel@tonic-gate } type_table[] = {
3567c478bd9Sstevel@tonic-gate 	{"all",	SADB_SATYPE_UNSPEC},
3577c478bd9Sstevel@tonic-gate 	{"ah",	SADB_SATYPE_AH},
3587c478bd9Sstevel@tonic-gate 	{"esp",	SADB_SATYPE_ESP},
3597c478bd9Sstevel@tonic-gate 	/* PF_KEY NOTE:  More to come if net/pfkeyv2.h gets updated. */
3607c478bd9Sstevel@tonic-gate 	{NULL,	0}	/* Token value is irrelevant for this entry. */
3617c478bd9Sstevel@tonic-gate };
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate static int
parsesatype(char * type,char * ebuf)365e3320f40Smarkfen parsesatype(char *type, char *ebuf)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	struct typetable *tt = type_table;
368e3320f40Smarkfen 	char *ep = NULL;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	if (type == NULL)
3717c478bd9Sstevel@tonic-gate 		return (SADB_SATYPE_UNSPEC);
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	while (tt->type != NULL && strcasecmp(tt->type, type) != 0)
3747c478bd9Sstevel@tonic-gate 		tt++;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	/*
3777c478bd9Sstevel@tonic-gate 	 * New SA types (including ones keysock maintains for user-land
3787c478bd9Sstevel@tonic-gate 	 * protocols) may be added, so parse a numeric value if possible.
3797c478bd9Sstevel@tonic-gate 	 */
3807c478bd9Sstevel@tonic-gate 	if (tt->type == NULL) {
381e3320f40Smarkfen 		tt->token = (int)parsenum(type, B_FALSE, ebuf);
3827c478bd9Sstevel@tonic-gate 		if (tt->token == -1) {
383e3320f40Smarkfen 			ERROR1(ep, ebuf, gettext(
384e3320f40Smarkfen 			    "Unknown SA type (%s).\n"), type);
385e3320f40Smarkfen 			tt->token = SADB_SATYPE_UNSPEC;
3867c478bd9Sstevel@tonic-gate 		}
3877c478bd9Sstevel@tonic-gate 	}
388bfe6f8f5SVladimir Kotal 	handle_errors(ep, NULL, interactive ? B_TRUE : B_FALSE, B_FALSE);
3897c478bd9Sstevel@tonic-gate 	return (tt->token);
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate #define	NEXTEOF		0
3937c478bd9Sstevel@tonic-gate #define	NEXTNONE	1
3947c478bd9Sstevel@tonic-gate #define	NEXTNUM		2
3957c478bd9Sstevel@tonic-gate #define	NEXTSTR		3
3967c478bd9Sstevel@tonic-gate #define	NEXTNUMSTR	4
3977c478bd9Sstevel@tonic-gate #define	NEXTADDR	5
3987c478bd9Sstevel@tonic-gate #define	NEXTHEX		6
3997c478bd9Sstevel@tonic-gate #define	NEXTIDENT	7
4007c478bd9Sstevel@tonic-gate #define	NEXTADDR4	8
4017c478bd9Sstevel@tonic-gate #define	NEXTADDR6	9
4025d3b8cb7SBill Sommerfeld #define	NEXTLABEL	10
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate #define	TOK_EOF			0
4057c478bd9Sstevel@tonic-gate #define	TOK_UNKNOWN		1
4067c478bd9Sstevel@tonic-gate #define	TOK_SPI			2
4077c478bd9Sstevel@tonic-gate #define	TOK_REPLAY		3
4087c478bd9Sstevel@tonic-gate #define	TOK_STATE		4
4097c478bd9Sstevel@tonic-gate #define	TOK_AUTHALG		5
4107c478bd9Sstevel@tonic-gate #define	TOK_ENCRALG		6
4117c478bd9Sstevel@tonic-gate #define	TOK_FLAGS		7
4127c478bd9Sstevel@tonic-gate #define	TOK_SOFT_ALLOC		8
4137c478bd9Sstevel@tonic-gate #define	TOK_SOFT_BYTES		9
4147c478bd9Sstevel@tonic-gate #define	TOK_SOFT_ADDTIME	10
4157c478bd9Sstevel@tonic-gate #define	TOK_SOFT_USETIME	11
4167c478bd9Sstevel@tonic-gate #define	TOK_HARD_ALLOC		12
4177c478bd9Sstevel@tonic-gate #define	TOK_HARD_BYTES		13
4187c478bd9Sstevel@tonic-gate #define	TOK_HARD_ADDTIME	14
4197c478bd9Sstevel@tonic-gate #define	TOK_HARD_USETIME	15
4207c478bd9Sstevel@tonic-gate #define	TOK_CURRENT_ALLOC	16
4217c478bd9Sstevel@tonic-gate #define	TOK_CURRENT_BYTES	17
4227c478bd9Sstevel@tonic-gate #define	TOK_CURRENT_ADDTIME	18
4237c478bd9Sstevel@tonic-gate #define	TOK_CURRENT_USETIME	19
4247c478bd9Sstevel@tonic-gate #define	TOK_SRCADDR		20
4257c478bd9Sstevel@tonic-gate #define	TOK_DSTADDR		21
4267c478bd9Sstevel@tonic-gate #define	TOK_PROXYADDR		22
4277c478bd9Sstevel@tonic-gate #define	TOK_AUTHKEY		23
4287c478bd9Sstevel@tonic-gate #define	TOK_ENCRKEY		24
4297c478bd9Sstevel@tonic-gate #define	TOK_SRCIDTYPE		25
4307c478bd9Sstevel@tonic-gate #define	TOK_DSTIDTYPE		26
4317c478bd9Sstevel@tonic-gate #define	TOK_DPD			27
4327c478bd9Sstevel@tonic-gate #define	TOK_SENS_LEVEL		28
4337c478bd9Sstevel@tonic-gate #define	TOK_SENS_MAP		29
4347c478bd9Sstevel@tonic-gate #define	TOK_INTEG_LEVEL		30
4357c478bd9Sstevel@tonic-gate #define	TOK_INTEG_MAP		31
4367c478bd9Sstevel@tonic-gate #define	TOK_SRCADDR6		32
4377c478bd9Sstevel@tonic-gate #define	TOK_DSTADDR6		33
4387c478bd9Sstevel@tonic-gate #define	TOK_PROXYADDR6		34
4397c478bd9Sstevel@tonic-gate #define	TOK_SRCPORT		35
4407c478bd9Sstevel@tonic-gate #define	TOK_DSTPORT		36
4417c478bd9Sstevel@tonic-gate #define	TOK_PROTO		37
4427c478bd9Sstevel@tonic-gate #define	TOK_ENCAP		38
4437c478bd9Sstevel@tonic-gate #define	TOK_NATLOC		39
4447c478bd9Sstevel@tonic-gate #define	TOK_NATREM		40
4457c478bd9Sstevel@tonic-gate #define	TOK_NATLPORT		41
4467c478bd9Sstevel@tonic-gate #define	TOK_NATRPORT		42
4478810c16bSdanmcd #define	TOK_IPROTO		43
4488810c16bSdanmcd #define	TOK_IDSTADDR		44
4498810c16bSdanmcd #define	TOK_IDSTADDR6		45
4508810c16bSdanmcd #define	TOK_ISRCPORT		46
4518810c16bSdanmcd #define	TOK_IDSTPORT		47
45238d95a78Smarkfen #define	TOK_PAIR_SPI		48
45338d95a78Smarkfen #define	TOK_FLAG_INBOUND	49
45438d95a78Smarkfen #define	TOK_FLAG_OUTBOUND	50
4559c2c14abSThejaswini Singarajipura #define	TOK_REPLAY_VALUE	51
4569c2c14abSThejaswini Singarajipura #define	TOK_IDLE_ADDTIME	52
4579c2c14abSThejaswini Singarajipura #define	TOK_IDLE_USETIME	53
458628b0c67SMark Fenwick #define	TOK_RESERVED		54
4595d3b8cb7SBill Sommerfeld #define	TOK_LABEL		55
4605d3b8cb7SBill Sommerfeld #define	TOK_OLABEL		56
4615d3b8cb7SBill Sommerfeld #define	TOK_IMPLABEL		57
4625d3b8cb7SBill Sommerfeld 
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate static struct toktable {
4657c478bd9Sstevel@tonic-gate 	char *string;
4667c478bd9Sstevel@tonic-gate 	int token;
4677c478bd9Sstevel@tonic-gate 	int next;
4687c478bd9Sstevel@tonic-gate } tokens[] = {
4697c478bd9Sstevel@tonic-gate 	/* "String",		token value,		next arg is */
4707c478bd9Sstevel@tonic-gate 	{"spi",			TOK_SPI,		NEXTNUM},
47138d95a78Smarkfen 	{"pair-spi",		TOK_PAIR_SPI,		NEXTNUM},
4727c478bd9Sstevel@tonic-gate 	{"replay",		TOK_REPLAY,		NEXTNUM},
4737c478bd9Sstevel@tonic-gate 	{"state",		TOK_STATE,		NEXTNUMSTR},
4747c478bd9Sstevel@tonic-gate 	{"auth_alg",		TOK_AUTHALG,		NEXTNUMSTR},
4757c478bd9Sstevel@tonic-gate 	{"authalg",		TOK_AUTHALG,		NEXTNUMSTR},
4767c478bd9Sstevel@tonic-gate 	{"encr_alg",		TOK_ENCRALG,		NEXTNUMSTR},
4777c478bd9Sstevel@tonic-gate 	{"encralg",		TOK_ENCRALG,		NEXTNUMSTR},
4787c478bd9Sstevel@tonic-gate 	{"flags",		TOK_FLAGS,		NEXTNUM},
4797c478bd9Sstevel@tonic-gate 	{"soft_alloc",		TOK_SOFT_ALLOC,		NEXTNUM},
4807c478bd9Sstevel@tonic-gate 	{"soft_bytes",		TOK_SOFT_BYTES,		NEXTNUM},
4817c478bd9Sstevel@tonic-gate 	{"soft_addtime",	TOK_SOFT_ADDTIME,	NEXTNUM},
4827c478bd9Sstevel@tonic-gate 	{"soft_usetime",	TOK_SOFT_USETIME,	NEXTNUM},
4837c478bd9Sstevel@tonic-gate 	{"hard_alloc",		TOK_HARD_ALLOC,		NEXTNUM},
4847c478bd9Sstevel@tonic-gate 	{"hard_bytes",		TOK_HARD_BYTES,		NEXTNUM},
4857c478bd9Sstevel@tonic-gate 	{"hard_addtime",	TOK_HARD_ADDTIME,	NEXTNUM},
4867c478bd9Sstevel@tonic-gate 	{"hard_usetime",	TOK_HARD_USETIME,	NEXTNUM},
4877c478bd9Sstevel@tonic-gate 	{"current_alloc",	TOK_CURRENT_ALLOC,	NEXTNUM},
4887c478bd9Sstevel@tonic-gate 	{"current_bytes",	TOK_CURRENT_BYTES,	NEXTNUM},
4897c478bd9Sstevel@tonic-gate 	{"current_addtime",	TOK_CURRENT_ADDTIME,	NEXTNUM},
4907c478bd9Sstevel@tonic-gate 	{"current_usetime",	TOK_CURRENT_USETIME,	NEXTNUM},
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	{"saddr",		TOK_SRCADDR,		NEXTADDR},
4937c478bd9Sstevel@tonic-gate 	{"srcaddr",		TOK_SRCADDR,		NEXTADDR},
4947c478bd9Sstevel@tonic-gate 	{"src",			TOK_SRCADDR,		NEXTADDR},
4957c478bd9Sstevel@tonic-gate 	{"daddr",		TOK_DSTADDR,		NEXTADDR},
4967c478bd9Sstevel@tonic-gate 	{"dstaddr",		TOK_DSTADDR,		NEXTADDR},
4977c478bd9Sstevel@tonic-gate 	{"dst",			TOK_DSTADDR,		NEXTADDR},
4987c478bd9Sstevel@tonic-gate 	{"proxyaddr",		TOK_PROXYADDR,		NEXTADDR},
4997c478bd9Sstevel@tonic-gate 	{"proxy",		TOK_PROXYADDR,		NEXTADDR},
5008810c16bSdanmcd 	{"innersrc",		TOK_PROXYADDR,		NEXTADDR},
5018810c16bSdanmcd 	{"isrc",		TOK_PROXYADDR,		NEXTADDR},
5028810c16bSdanmcd 	{"innerdst",		TOK_IDSTADDR,		NEXTADDR},
5038810c16bSdanmcd 	{"idst",		TOK_IDSTADDR,		NEXTADDR},
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	{"sport",		TOK_SRCPORT,		NEXTNUM},
5067c478bd9Sstevel@tonic-gate 	{"dport",		TOK_DSTPORT,		NEXTNUM},
5078810c16bSdanmcd 	{"innersport",		TOK_ISRCPORT,		NEXTNUM},
5088810c16bSdanmcd 	{"isport",		TOK_ISRCPORT,		NEXTNUM},
5098810c16bSdanmcd 	{"innerdport",		TOK_IDSTPORT,		NEXTNUM},
5108810c16bSdanmcd 	{"idport",		TOK_IDSTPORT,		NEXTNUM},
5117c478bd9Sstevel@tonic-gate 	{"proto",		TOK_PROTO,		NEXTNUM},
512eeda67c6Sjojemann 	{"ulp",			TOK_PROTO,		NEXTNUM},
5138810c16bSdanmcd 	{"iproto",		TOK_IPROTO,		NEXTNUM},
5148810c16bSdanmcd 	{"iulp",		TOK_IPROTO,		NEXTNUM},
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	{"saddr6",		TOK_SRCADDR6,		NEXTADDR},
5177c478bd9Sstevel@tonic-gate 	{"srcaddr6",		TOK_SRCADDR6,		NEXTADDR},
5187c478bd9Sstevel@tonic-gate 	{"src6",		TOK_SRCADDR6,		NEXTADDR},
5197c478bd9Sstevel@tonic-gate 	{"daddr6",		TOK_DSTADDR6,		NEXTADDR},
5207c478bd9Sstevel@tonic-gate 	{"dstaddr6",		TOK_DSTADDR6,		NEXTADDR},
5217c478bd9Sstevel@tonic-gate 	{"dst6",		TOK_DSTADDR6,		NEXTADDR},
5227c478bd9Sstevel@tonic-gate 	{"proxyaddr6",		TOK_PROXYADDR6,		NEXTADDR},
5237c478bd9Sstevel@tonic-gate 	{"proxy6",		TOK_PROXYADDR6,		NEXTADDR},
5248810c16bSdanmcd 	{"innersrc6",		TOK_PROXYADDR6,		NEXTADDR},
5258810c16bSdanmcd 	{"isrc6",		TOK_PROXYADDR6,		NEXTADDR},
5268810c16bSdanmcd 	{"innerdst6",		TOK_IDSTADDR6,		NEXTADDR},
5278810c16bSdanmcd 	{"idst6",		TOK_IDSTADDR6,		NEXTADDR},
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	{"authkey",		TOK_AUTHKEY,		NEXTHEX},
5307c478bd9Sstevel@tonic-gate 	{"encrkey",		TOK_ENCRKEY,		NEXTHEX},
5317c478bd9Sstevel@tonic-gate 	{"srcidtype",		TOK_SRCIDTYPE,		NEXTIDENT},
5327c478bd9Sstevel@tonic-gate 	{"dstidtype",		TOK_DSTIDTYPE,		NEXTIDENT},
5337c478bd9Sstevel@tonic-gate 	{"dpd",			TOK_DPD,		NEXTNUM},
5347c478bd9Sstevel@tonic-gate 	{"sens_level",		TOK_SENS_LEVEL,		NEXTNUM},
5357c478bd9Sstevel@tonic-gate 	{"sens_map",		TOK_SENS_MAP,		NEXTHEX},
5367c478bd9Sstevel@tonic-gate 	{"integ_level",		TOK_INTEG_LEVEL,	NEXTNUM},
5377c478bd9Sstevel@tonic-gate 	{"integ_map",		TOK_INTEG_MAP,		NEXTHEX},
5387c478bd9Sstevel@tonic-gate 	{"nat_loc",		TOK_NATLOC,		NEXTADDR},
5397c478bd9Sstevel@tonic-gate 	{"nat_rem",		TOK_NATREM,		NEXTADDR},
5407c478bd9Sstevel@tonic-gate 	{"nat_lport",		TOK_NATLPORT,		NEXTNUM},
5417c478bd9Sstevel@tonic-gate 	{"nat_rport",		TOK_NATRPORT,		NEXTNUM},
5427c478bd9Sstevel@tonic-gate 	{"encap",		TOK_ENCAP,		NEXTNUMSTR},
54338d95a78Smarkfen 
54495c74518SToomas Soome 	{"outbound",		TOK_FLAG_OUTBOUND,	0},
54595c74518SToomas Soome 	{"inbound",		TOK_FLAG_INBOUND,	0},
5469c2c14abSThejaswini Singarajipura 
547628b0c67SMark Fenwick 	{"reserved_bits",	TOK_RESERVED,		NEXTNUM},
5489c2c14abSThejaswini Singarajipura 	{"replay_value",	TOK_REPLAY_VALUE,	NEXTNUM},
5499c2c14abSThejaswini Singarajipura 	{"idle_addtime",	TOK_IDLE_ADDTIME,	NEXTNUM},
5509c2c14abSThejaswini Singarajipura 	{"idle_usetime",	TOK_IDLE_USETIME,	NEXTNUM},
5515d3b8cb7SBill Sommerfeld 
5525d3b8cb7SBill Sommerfeld 	{"label",		TOK_LABEL,		NEXTLABEL},
5535d3b8cb7SBill Sommerfeld 	{"outer-label",		TOK_OLABEL,		NEXTLABEL},
5545d3b8cb7SBill Sommerfeld 	{"implicit-label",	TOK_IMPLABEL,		NEXTLABEL},
5555d3b8cb7SBill Sommerfeld 
5567c478bd9Sstevel@tonic-gate 	{NULL,			TOK_UNKNOWN,		NEXTEOF}
5577c478bd9Sstevel@tonic-gate };
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate /*
5607c478bd9Sstevel@tonic-gate  * Q:	Do I need stuff for proposals, combinations, supported algorithms,
5617c478bd9Sstevel@tonic-gate  *	or SPI ranges?
5627c478bd9Sstevel@tonic-gate  *
5637c478bd9Sstevel@tonic-gate  * A:	Probably not, but you never know.
5647c478bd9Sstevel@tonic-gate  *
5657c478bd9Sstevel@tonic-gate  * Parse out extension header type values.
5667c478bd9Sstevel@tonic-gate  */
5677c478bd9Sstevel@tonic-gate static int
parseextval(char * value,int * next)5687c478bd9Sstevel@tonic-gate parseextval(char *value, int *next)
5697c478bd9Sstevel@tonic-gate {
5707c478bd9Sstevel@tonic-gate 	struct toktable *tp;
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	if (value == NULL)
5737c478bd9Sstevel@tonic-gate 		return (TOK_EOF);
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	for (tp = tokens; tp->string != NULL; tp++)
5767c478bd9Sstevel@tonic-gate 		if (strcmp(value, tp->string) == 0)
5777c478bd9Sstevel@tonic-gate 			break;
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	/*
5807c478bd9Sstevel@tonic-gate 	 * Since the OS controls what extensions are available, we don't have
5817c478bd9Sstevel@tonic-gate 	 * to parse numeric values here.
5827c478bd9Sstevel@tonic-gate 	 */
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	*next = tp->next;
5857c478bd9Sstevel@tonic-gate 	return (tp->token);
5867c478bd9Sstevel@tonic-gate }
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate /*
5897c478bd9Sstevel@tonic-gate  * Parse possible state values.
5907c478bd9Sstevel@tonic-gate  */
5917c478bd9Sstevel@tonic-gate static uint8_t
parsestate(char * state,char * ebuf)592e3320f40Smarkfen parsestate(char *state, char *ebuf)
5937c478bd9Sstevel@tonic-gate {
5947c478bd9Sstevel@tonic-gate 	struct states {
5957c478bd9Sstevel@tonic-gate 		char *state;
5967c478bd9Sstevel@tonic-gate 		uint8_t retval;
5977c478bd9Sstevel@tonic-gate 	} states[] = {
5987c478bd9Sstevel@tonic-gate 		{"larval",	SADB_SASTATE_LARVAL},
5997c478bd9Sstevel@tonic-gate 		{"mature",	SADB_SASTATE_MATURE},
6007c478bd9Sstevel@tonic-gate 		{"dying",	SADB_SASTATE_DYING},
6017c478bd9Sstevel@tonic-gate 		{"dead",	SADB_SASTATE_DEAD},
6027c478bd9Sstevel@tonic-gate 		{NULL,		0}
6037c478bd9Sstevel@tonic-gate 	};
6047c478bd9Sstevel@tonic-gate 	struct states *sp;
605e3320f40Smarkfen 	char *ep = NULL;
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	if (state == NULL) {
608e3320f40Smarkfen 		FATAL(ep, ebuf, "Unexpected end of command line "
609e3320f40Smarkfen 		    "was expecting a state.\n");
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	for (sp = states; sp->state != NULL; sp++) {
6137c478bd9Sstevel@tonic-gate 		if (strcmp(sp->state, state) == 0)
6147c478bd9Sstevel@tonic-gate 			return (sp->retval);
6157c478bd9Sstevel@tonic-gate 	}
616e3320f40Smarkfen 	ERROR1(ep, ebuf, gettext("Unknown state type \"%s\"\n"), state);
617e3320f40Smarkfen 	handle_errors(ep, NULL, B_FALSE, B_FALSE);
618eeda67c6Sjojemann 	return (0);
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate /*
6227c478bd9Sstevel@tonic-gate  * Return the numerical algorithm identifier corresponding to the specified
6237c478bd9Sstevel@tonic-gate  * algorithm name.
6247c478bd9Sstevel@tonic-gate  */
6257c478bd9Sstevel@tonic-gate static uint8_t
parsealg(char * alg,int proto_num,char * ebuf)626e3320f40Smarkfen parsealg(char *alg, int proto_num, char *ebuf)
6277c478bd9Sstevel@tonic-gate {
6287c478bd9Sstevel@tonic-gate 	u_longlong_t invalue;
6297c478bd9Sstevel@tonic-gate 	struct ipsecalgent *algent;
630e3320f40Smarkfen 	char *ep = NULL;
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	if (alg == NULL) {
633e3320f40Smarkfen 		FATAL(ep, ebuf, gettext("Unexpected end of command line, "
634e3320f40Smarkfen 		    "was expecting an algorithm name.\n"));
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	algent = getipsecalgbyname(alg, proto_num, NULL);
6387c478bd9Sstevel@tonic-gate 	if (algent != NULL) {
6397c478bd9Sstevel@tonic-gate 		uint8_t alg_num;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 		alg_num = algent->a_alg_num;
642628b0c67SMark Fenwick 		if (ALG_FLAG_COUNTERMODE & algent->a_alg_flags)
643628b0c67SMark Fenwick 			WARN1(ep, ebuf, gettext(
644628b0c67SMark Fenwick 			    "Using manual keying with a Counter mode algorithm "
645628b0c67SMark Fenwick 			    "such as \"%s\" may be insecure!\n"),
646628b0c67SMark Fenwick 			    algent->a_names[0]);
6477c478bd9Sstevel@tonic-gate 		freeipsecalgent(algent);
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 		return (alg_num);
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	/*
6537c478bd9Sstevel@tonic-gate 	 * Since algorithms can be loaded during kernel run-time, check for
6547c478bd9Sstevel@tonic-gate 	 * numeric algorithm values too.  PF_KEY can catch bad ones with EINVAL.
6557c478bd9Sstevel@tonic-gate 	 */
656e3320f40Smarkfen 	invalue = parsenum(alg, B_FALSE, ebuf);
6577c478bd9Sstevel@tonic-gate 	if (invalue != (u_longlong_t)-1 &&
6587c478bd9Sstevel@tonic-gate 	    (u_longlong_t)(invalue & (u_longlong_t)0xff) == invalue)
6597c478bd9Sstevel@tonic-gate 		return ((uint8_t)invalue);
6607c478bd9Sstevel@tonic-gate 
661e3320f40Smarkfen 	if (proto_num == IPSEC_PROTO_ESP) {
662e3320f40Smarkfen 		ERROR1(ep, ebuf, gettext(
663e3320f40Smarkfen 		    "Unknown encryption algorithm type \"%s\"\n"), alg);
664e3320f40Smarkfen 	} else {
665e3320f40Smarkfen 		ERROR1(ep, ebuf, gettext(
666e3320f40Smarkfen 		    "Unknown authentication algorithm type \"%s\"\n"), alg);
667e3320f40Smarkfen 	}
668e3320f40Smarkfen 	handle_errors(ep, NULL, B_FALSE, B_FALSE);
669eeda67c6Sjojemann 	return (0);
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate /*
6737c478bd9Sstevel@tonic-gate  * Parse and reverse parse out a source/destination ID type.
6747c478bd9Sstevel@tonic-gate  */
6757c478bd9Sstevel@tonic-gate static struct idtypes {
6767c478bd9Sstevel@tonic-gate 	char *idtype;
6777c478bd9Sstevel@tonic-gate 	uint8_t retval;
6787c478bd9Sstevel@tonic-gate } idtypes[] = {
6797c478bd9Sstevel@tonic-gate 	{"prefix",	SADB_IDENTTYPE_PREFIX},
6807c478bd9Sstevel@tonic-gate 	{"fqdn",	SADB_IDENTTYPE_FQDN},
6817c478bd9Sstevel@tonic-gate 	{"domain",	SADB_IDENTTYPE_FQDN},
6827c478bd9Sstevel@tonic-gate 	{"domainname",	SADB_IDENTTYPE_FQDN},
6837c478bd9Sstevel@tonic-gate 	{"user_fqdn",	SADB_IDENTTYPE_USER_FQDN},
6847c478bd9Sstevel@tonic-gate 	{"mailbox",	SADB_IDENTTYPE_USER_FQDN},
6857c478bd9Sstevel@tonic-gate 	{"der_dn",	SADB_X_IDENTTYPE_DN},
6867c478bd9Sstevel@tonic-gate 	{"der_gn",	SADB_X_IDENTTYPE_GN},
6877c478bd9Sstevel@tonic-gate 	{NULL,		0}
6887c478bd9Sstevel@tonic-gate };
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate static uint16_t
parseidtype(char * type,char * ebuf)691e3320f40Smarkfen parseidtype(char *type, char *ebuf)
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 	struct idtypes *idp;
6947c478bd9Sstevel@tonic-gate 	u_longlong_t invalue;
695e3320f40Smarkfen 	char *ep = NULL;
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	if (type == NULL) {
6987c478bd9Sstevel@tonic-gate 		/* Shouldn't reach here, see callers for why. */
699e3320f40Smarkfen 		FATAL(ep, ebuf, gettext("Unexpected end of command line, "
700e3320f40Smarkfen 		    "was expecting a type.\n"));
7017c478bd9Sstevel@tonic-gate 	}
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	for (idp = idtypes; idp->idtype != NULL; idp++) {
7047c478bd9Sstevel@tonic-gate 		if (strcasecmp(idp->idtype, type) == 0)
7057c478bd9Sstevel@tonic-gate 			return (idp->retval);
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 	/*
7087c478bd9Sstevel@tonic-gate 	 * Since identity types are almost arbitrary, check for numeric
7097c478bd9Sstevel@tonic-gate 	 * algorithm values too.  PF_KEY can catch bad ones with EINVAL.
7107c478bd9Sstevel@tonic-gate 	 */
711e3320f40Smarkfen 	invalue = parsenum(type, B_FALSE, ebuf);
7127c478bd9Sstevel@tonic-gate 	if (invalue != (u_longlong_t)-1 &&
7137c478bd9Sstevel@tonic-gate 	    (u_longlong_t)(invalue & (u_longlong_t)0xffff) == invalue)
7147c478bd9Sstevel@tonic-gate 		return ((uint16_t)invalue);
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 
717e3320f40Smarkfen 	ERROR1(ep, ebuf, gettext("Unknown identity type \"%s\"\n"), type);
718e3320f40Smarkfen 
719e3320f40Smarkfen 	handle_errors(ep, NULL, B_FALSE, B_FALSE);
720eeda67c6Sjojemann 	return (0);
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate /*
7247c478bd9Sstevel@tonic-gate  * Parse an address off the command line.  Return length of sockaddr,
7257c478bd9Sstevel@tonic-gate  * and either return a hostent pointer (caller frees).  The new
7267c478bd9Sstevel@tonic-gate  * getipnodebyname() call does the Right Thing (TM), even with
7277c478bd9Sstevel@tonic-gate  * raw addresses (colon-separated IPv6 or dotted decimal IPv4).
7287c478bd9Sstevel@tonic-gate  */
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate static struct {
7317c478bd9Sstevel@tonic-gate 	struct hostent he;
7327c478bd9Sstevel@tonic-gate 	char *addtl[2];
7337c478bd9Sstevel@tonic-gate 	} dummy;
7347c478bd9Sstevel@tonic-gate static union {
7357c478bd9Sstevel@tonic-gate 	struct in6_addr ipv6;
7367c478bd9Sstevel@tonic-gate 	struct in_addr ipv4;
7377c478bd9Sstevel@tonic-gate 	uint64_t aligner;
7387c478bd9Sstevel@tonic-gate } addr1;
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate static int
parseaddr(char * addr,struct hostent ** hpp,boolean_t v6only,char * ebuf)741e3320f40Smarkfen parseaddr(char *addr, struct hostent **hpp, boolean_t v6only, char *ebuf)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate 	int hp_errno;
7447c478bd9Sstevel@tonic-gate 	struct hostent *hp = NULL;
745e3320f40Smarkfen 	char *ep = NULL;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	if (addr == NULL) {
748e3320f40Smarkfen 		FATAL(ep, ebuf, gettext("Unexpected end of command line, "
749e3320f40Smarkfen 		    "was expecting an address.\n"));
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	if (!nflag) {
7537c478bd9Sstevel@tonic-gate 		/*
7547c478bd9Sstevel@tonic-gate 		 * Try name->address first.  Assume AF_INET6, and
7557c478bd9Sstevel@tonic-gate 		 * get IPv4's, plus IPv6's if and only if IPv6 is configured.
7567c478bd9Sstevel@tonic-gate 		 * This means to add IPv6 SAs, you must have IPv6
7577c478bd9Sstevel@tonic-gate 		 * up-and-running.  (AI_DEFAULT works here.)
7587c478bd9Sstevel@tonic-gate 		 */
7597c478bd9Sstevel@tonic-gate 		hp = getipnodebyname(addr, AF_INET6,
7607c478bd9Sstevel@tonic-gate 		    (v6only ? AI_ADDRCONFIG : (AI_DEFAULT | AI_ALL)),
7617c478bd9Sstevel@tonic-gate 		    &hp_errno);
7627c478bd9Sstevel@tonic-gate 	} else {
7637c478bd9Sstevel@tonic-gate 		/*
7647c478bd9Sstevel@tonic-gate 		 * Try a normal address conversion only.  Use "dummy"
7657c478bd9Sstevel@tonic-gate 		 * to construct a fake hostent.  Caller will know not
7667c478bd9Sstevel@tonic-gate 		 * to free this one.
7677c478bd9Sstevel@tonic-gate 		 */
7687c478bd9Sstevel@tonic-gate 		if (inet_pton(AF_INET6, addr, &addr1) == 1) {
7697c478bd9Sstevel@tonic-gate 			dummy.he.h_addr_list = dummy.addtl;
7707c478bd9Sstevel@tonic-gate 			dummy.addtl[0] = (char *)&addr1;
7717c478bd9Sstevel@tonic-gate 			dummy.addtl[1] = NULL;
7727c478bd9Sstevel@tonic-gate 			hp = &dummy.he;
7737c478bd9Sstevel@tonic-gate 			dummy.he.h_addrtype = AF_INET6;
7747c478bd9Sstevel@tonic-gate 			dummy.he.h_length = sizeof (struct in6_addr);
7757c478bd9Sstevel@tonic-gate 		} else if (inet_pton(AF_INET, addr, &addr1) == 1) {
7767c478bd9Sstevel@tonic-gate 			/*
7778810c16bSdanmcd 			 * Remap to AF_INET6 anyway.
7787c478bd9Sstevel@tonic-gate 			 */
7797c478bd9Sstevel@tonic-gate 			dummy.he.h_addr_list = dummy.addtl;
7807c478bd9Sstevel@tonic-gate 			dummy.addtl[0] = (char *)&addr1;
7817c478bd9Sstevel@tonic-gate 			dummy.addtl[1] = NULL;
7827c478bd9Sstevel@tonic-gate 			hp = &dummy.he;
7837c478bd9Sstevel@tonic-gate 			dummy.he.h_addrtype = AF_INET6;
7847c478bd9Sstevel@tonic-gate 			dummy.he.h_length = sizeof (struct in6_addr);
7857c478bd9Sstevel@tonic-gate 			/*
7867c478bd9Sstevel@tonic-gate 			 * NOTE:  If macro changes to disallow in-place
7877c478bd9Sstevel@tonic-gate 			 * conversion, rewhack this.
7887c478bd9Sstevel@tonic-gate 			 */
7897c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&addr1.ipv4, &addr1.ipv6);
7907c478bd9Sstevel@tonic-gate 		} else {
7917c478bd9Sstevel@tonic-gate 			hp = NULL;
7927c478bd9Sstevel@tonic-gate 		}
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate 
795e3320f40Smarkfen 	if (hp == NULL)
796e3320f40Smarkfen 		WARN1(ep, ebuf, gettext("Unknown address %s."), addr);
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	*hpp = hp;
7998810c16bSdanmcd 	/* Always return sockaddr_in6 for now. */
800