xref: /titanic_51/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipsecalgs.c (revision 628b0c67908adce18522d53bb2bf8d6c3b321579)
1e3320f40Smarkfen /*
2e3320f40Smarkfen  * CDDL HEADER START
3e3320f40Smarkfen  *
4e3320f40Smarkfen  * The contents of this file are subject to the terms of the
5e3320f40Smarkfen  * Common Development and Distribution License (the "License").
6e3320f40Smarkfen  * You may not use this file except in compliance with the License.
7e3320f40Smarkfen  *
8e3320f40Smarkfen  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9e3320f40Smarkfen  * or http://www.opensolaris.org/os/licensing.
10e3320f40Smarkfen  * See the License for the specific language governing permissions
11e3320f40Smarkfen  * and limitations under the License.
12e3320f40Smarkfen  *
13e3320f40Smarkfen  * When distributing Covered Code, include this CDDL HEADER in each
14e3320f40Smarkfen  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15e3320f40Smarkfen  * If applicable, add the following below this CDDL HEADER, with the
16e3320f40Smarkfen  * fields enclosed by brackets "[]" replaced with your own identifying
17e3320f40Smarkfen  * information: Portions Copyright [yyyy] [name of copyright owner]
18e3320f40Smarkfen  *
19e3320f40Smarkfen  * CDDL HEADER END
20e3320f40Smarkfen  */
21e3320f40Smarkfen /*
22*628b0c67SMark Fenwick  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23e3320f40Smarkfen  * Use is subject to license terms.
24e3320f40Smarkfen  */
25e3320f40Smarkfen 
26e3320f40Smarkfen #include <ipsec_util.h>
27e3320f40Smarkfen #include <netdb.h>
28e3320f40Smarkfen #include <locale.h>
29e3320f40Smarkfen #include <stdlib.h>
30e3320f40Smarkfen #include <stdio.h>
31e3320f40Smarkfen #include <string.h>
32e3320f40Smarkfen #include <assert.h>
33e3320f40Smarkfen #include <unistd.h>
34e3320f40Smarkfen #include <net/pfpolicy.h>
35e3320f40Smarkfen #include <strings.h>
36e3320f40Smarkfen #include <errno.h>
37e3320f40Smarkfen #include <sys/crypto/common.h>
38e3320f40Smarkfen #include <zone.h>
39e3320f40Smarkfen 
40e3320f40Smarkfen #define	SPDSOCK_DIAG_BUF_LEN	128
41e3320f40Smarkfen 
42e3320f40Smarkfen typedef enum cmd_s {
43e3320f40Smarkfen 	CMD_NONE = 0,
44e3320f40Smarkfen 	CMD_ADD,
45e3320f40Smarkfen 	CMD_ADD_PROTO,
46e3320f40Smarkfen 	CMD_DEL,
47e3320f40Smarkfen 	CMD_DEL_PROTO,
48e3320f40Smarkfen 	CMD_EXEC_MODE,
49e3320f40Smarkfen 	CMD_LIST_KERNEL
50e3320f40Smarkfen } cmd_t;
51e3320f40Smarkfen 
52e3320f40Smarkfen static const char *comma = ",";
53e3320f40Smarkfen static int adddel_flags, increment = 0, default_keylen;
54e3320f40Smarkfen static boolean_t synch_kernel;
55e3320f40Smarkfen static cmd_t cmd = CMD_NONE;
56*628b0c67SMark Fenwick static int proto_number = -1, alg_number = -1, alg_flags = 0;
57e3320f40Smarkfen static char *proto_name, *alg_names_string, *block_sizes_string;
58e3320f40Smarkfen static char *key_sizes_string, *mech_name, *exec_mode_string;
59*628b0c67SMark Fenwick static char *flag_string;
60e3320f40Smarkfen static ipsecalgs_exec_mode_t proto_exec_mode = LIBIPSEC_ALGS_EXEC_SYNC;
61*628b0c67SMark Fenwick enum param_values {iv_len, mac_len, salt_bytes, max_param};
62*628b0c67SMark Fenwick static int mech_params[max_param];
63e3320f40Smarkfen 
64e3320f40Smarkfen /*
65e3320f40Smarkfen  * Used by the algorithm walker callback to populate a SPD_UPDATEALGS
66e3320f40Smarkfen  * request.
67e3320f40Smarkfen  */
68e3320f40Smarkfen 
69*628b0c67SMark Fenwick #define	SYNC_REQ_SIZE	4096
70e3320f40Smarkfen 
71e3320f40Smarkfen static uint64_t sync_req_buf[SYNC_REQ_SIZE];
72e3320f40Smarkfen static struct spd_attribute *sync_req_attr;
73e3320f40Smarkfen static uint_t sync_req_alg_count, sync_req_proto_count;
74e3320f40Smarkfen 
75e3320f40Smarkfen #define	EMIT(ap, tag, value) {					\
76e3320f40Smarkfen 		(ap)->spd_attr_tag = (tag);			\
77e3320f40Smarkfen 		(ap)->spd_attr_value = (value);			\
78e3320f40Smarkfen 		(ap)++;						\
79e3320f40Smarkfen 		if ((char *)(ap) + sizeof (*ap) -		\
80e3320f40Smarkfen 		    (char *)sync_req_buf > SYNC_REQ_SIZE)	\
81e3320f40Smarkfen 			bail_nomem();				\
82e3320f40Smarkfen 	}
83e3320f40Smarkfen 
84e3320f40Smarkfen static void dump_alg(struct ipsecalgent *);
85e3320f40Smarkfen static void algs_walker(void (*)(struct ipsecalgent *), void (*)(uint_t));
86e3320f40Smarkfen 
87*628b0c67SMark Fenwick static int
88*628b0c67SMark Fenwick parse_flag(char *flag_str, uint_t flag)
89*628b0c67SMark Fenwick {
90*628b0c67SMark Fenwick 	static struct flagtable {
91*628b0c67SMark Fenwick 		char *label;
92*628b0c67SMark Fenwick 		int token;
93*628b0c67SMark Fenwick 	} table[] = {
94*628b0c67SMark Fenwick 		{"VALID", 	ALG_FLAG_VALID},
95*628b0c67SMark Fenwick 		{"COUNTER",	ALG_FLAG_COUNTERMODE},
96*628b0c67SMark Fenwick 		{"COMBINED",	ALG_FLAG_COMBINED},
97*628b0c67SMark Fenwick 		{"CCM",		ALG_FLAG_CCM},
98*628b0c67SMark Fenwick 		{"GCM",		ALG_FLAG_GCM},
99*628b0c67SMark Fenwick 		{NULL,		0}
100*628b0c67SMark Fenwick 	};
101*628b0c67SMark Fenwick 	struct flagtable *ft = table;
102*628b0c67SMark Fenwick 
103*628b0c67SMark Fenwick 	if (flag_str == NULL) {
104*628b0c67SMark Fenwick 		/* Print out flag labels for each flag set. */
105*628b0c67SMark Fenwick 		if ((ALG_FLAG_KERNELCHECKED & flag) && !(ALG_FLAG_VALID & flag))
106*628b0c67SMark Fenwick 			(void) printf("INVALID ");
107*628b0c67SMark Fenwick 		while (ft->token != 0) {
108*628b0c67SMark Fenwick 			if (ft->token & flag) {
109*628b0c67SMark Fenwick 				(void) printf("%s ", ft->label);
110*628b0c67SMark Fenwick 			}
111*628b0c67SMark Fenwick 			ft++;
112*628b0c67SMark Fenwick 		}
113*628b0c67SMark Fenwick 		return (0);
114*628b0c67SMark Fenwick 	}
115*628b0c67SMark Fenwick 	/* Or, lookup flag for supplied label. */
116*628b0c67SMark Fenwick 	while (ft->label != NULL && strcmp(ft->label, flag_str) != 0)
117*628b0c67SMark Fenwick 		ft++;
118*628b0c67SMark Fenwick 	return (ft->token);
119*628b0c67SMark Fenwick }
120*628b0c67SMark Fenwick 
121e3320f40Smarkfen static void
122e3320f40Smarkfen usage(void)
123e3320f40Smarkfen {
124e3320f40Smarkfen 	errx(EXIT_FAILURE, gettext("Usage:\tipsecalgs\n"
125e3320f40Smarkfen 	    "\tipsecalgs -l\n"
126e3320f40Smarkfen 	    "\tipsecalgs -s\n"
127e3320f40Smarkfen 	    "\tipsecalgs -a [-P protocol-number | -p protocol-name]\n"
128e3320f40Smarkfen 	    "\t\t-k keylen-list [-i inc]\n"
129e3320f40Smarkfen 	    "\t\t[-K default-keylen] -b blocklen-list\n"
130*628b0c67SMark Fenwick 	    "\t\t-n alg-names -N alg-number -m mech-name\n"
131*628b0c67SMark Fenwick 	    "\t\t[-M MAC length] [-S salt length] [-I IV length]\n"
132*628b0c67SMark Fenwick 	    "\t\t[-F COMBINED,COUNTER,CCM|GCM ] [-f] [-s]\n"
133e3320f40Smarkfen 	    "\tipsecalgs -P protocol-number -p protocol-name\n"
134e3320f40Smarkfen 	    "\t\t[-e exec-mode] [-f] [-s]\n"
135e3320f40Smarkfen 	    "\tipsecalgs -r -p protocol-name -n alg-name [-s]\n"
136e3320f40Smarkfen 	    "\tipsecalgs -r -p protocol-name -N alg-number [-s]\n"
137e3320f40Smarkfen 	    "\tipsecalgs -R -P protocol-number [-s]\n"
138e3320f40Smarkfen 	    "\tipsecalgs -R -p protocol-name [-s]\n"
139e3320f40Smarkfen 	    "\tipsecalgs -e exec-mode -P protocol-number [-s]\n"
140e3320f40Smarkfen 	    "\tipsecalgs -e exec-mode -p protocol-number [-s]"));
141e3320f40Smarkfen }
142e3320f40Smarkfen 
143e3320f40Smarkfen static void
144e3320f40Smarkfen bail_nomem(void)
145e3320f40Smarkfen {
146e3320f40Smarkfen 	errx(EXIT_FAILURE, gettext("Out of memory."));
147e3320f40Smarkfen }
148e3320f40Smarkfen 
149e3320f40Smarkfen /*
150e3320f40Smarkfen  * Return the number of key or block sizes in the specified array.
151e3320f40Smarkfen  */
152e3320f40Smarkfen static uint_t
153e3320f40Smarkfen num_sizes(int *sizes)
154e3320f40Smarkfen {
155e3320f40Smarkfen 	uint_t nsizes = 0;
156e3320f40Smarkfen 
157e3320f40Smarkfen 	while (sizes[nsizes] != 0)
158e3320f40Smarkfen 		nsizes++;
159e3320f40Smarkfen 
160e3320f40Smarkfen 	return (nsizes);
161e3320f40Smarkfen }
162e3320f40Smarkfen 
163e3320f40Smarkfen /*
164e3320f40Smarkfen  * Algorithms walker callback. Adds an algorithm to the current SPD_UPDATEALGS
165e3320f40Smarkfen  * request.
166e3320f40Smarkfen  */
167e3320f40Smarkfen static void
168e3320f40Smarkfen synch_emit_alg(struct ipsecalgent *alg)
169e3320f40Smarkfen {
170e3320f40Smarkfen 	uint_t nkey_sizes, nblock_sizes, i;
171*628b0c67SMark Fenwick 	uint_t nparams;
172e3320f40Smarkfen 
173e3320f40Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_ALG_ID, alg->a_alg_num);
174e3320f40Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_ALG_PROTO, alg->a_proto_num);
175e3320f40Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_ALG_INCRBITS, alg->a_key_increment);
176e3320f40Smarkfen 
177e3320f40Smarkfen 	nkey_sizes = num_sizes(alg->a_key_sizes);
178e3320f40Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_ALG_NKEYSIZES, nkey_sizes);
179e3320f40Smarkfen 	for (i = 0; i < nkey_sizes; i++)
180e3320f40Smarkfen 		EMIT(sync_req_attr, SPD_ATTR_ALG_KEYSIZE, alg->a_key_sizes[i]);
181e3320f40Smarkfen 
182e3320f40Smarkfen 	nblock_sizes = num_sizes(alg->a_block_sizes);
183*628b0c67SMark Fenwick 	nparams = num_sizes(alg->a_mech_params);
184e3320f40Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_ALG_NBLOCKSIZES, nblock_sizes);
185e3320f40Smarkfen 	for (i = 0; i < nblock_sizes; i++) {
186e3320f40Smarkfen 		EMIT(sync_req_attr, SPD_ATTR_ALG_BLOCKSIZE,
187e3320f40Smarkfen 		    alg->a_block_sizes[i]);
188e3320f40Smarkfen 	}
189*628b0c67SMark Fenwick 	EMIT(sync_req_attr, SPD_ATTR_ALG_NPARAMS, nparams);
190*628b0c67SMark Fenwick 	for (i = 0; i < nparams; i++) {
191*628b0c67SMark Fenwick 		EMIT(sync_req_attr, SPD_ATTR_ALG_PARAMS,
192*628b0c67SMark Fenwick 		    alg->a_mech_params[i]);
193*628b0c67SMark Fenwick 	}
194*628b0c67SMark Fenwick 	EMIT(sync_req_attr, SPD_ATTR_ALG_FLAGS, alg->a_alg_flags);
195e3320f40Smarkfen 
196e3320f40Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_ALG_MECHNAME, CRYPTO_MAX_MECH_NAME);
197e3320f40Smarkfen 	(void) strncpy((char *)sync_req_attr, alg->a_mech_name,
198e3320f40Smarkfen 	    CRYPTO_MAX_MECH_NAME);
199e3320f40Smarkfen 	sync_req_attr = (struct spd_attribute *)((uint64_t *)sync_req_attr +
200e3320f40Smarkfen 	    SPD_8TO64(CRYPTO_MAX_MECH_NAME));
201e3320f40Smarkfen 
202e3320f40Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_NEXT, 0);
203e3320f40Smarkfen 
204e3320f40Smarkfen 	sync_req_alg_count++;
205e3320f40Smarkfen }
206e3320f40Smarkfen 
207e3320f40Smarkfen /*
208e3320f40Smarkfen  * Protocol walker callback. Add protocol related info to the current
209e3320f40Smarkfen  * SPD_UPDATEALGS request.
210e3320f40Smarkfen  */
211e3320f40Smarkfen static void
212e3320f40Smarkfen synch_emit_proto(uint_t proto_num)
213e3320f40Smarkfen {
214e3320f40Smarkfen 	ipsecalgs_exec_mode_t exec_mode;
215e3320f40Smarkfen 	uint32_t exec_mode_spdval;
216e3320f40Smarkfen 
217e3320f40Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_PROTO_ID, proto_num);
218e3320f40Smarkfen 
219e3320f40Smarkfen 	/* execution mode */
220e3320f40Smarkfen 	if (ipsecproto_get_exec_mode(proto_num, &exec_mode) != 0) {
221e3320f40Smarkfen 		errx(EXIT_FAILURE, gettext("cannot get execution mode for "
222e3320f40Smarkfen 		    "proto %d"), proto_num);
223e3320f40Smarkfen 	}
224e3320f40Smarkfen 
225e3320f40Smarkfen 	switch (exec_mode) {
226e3320f40Smarkfen 	case LIBIPSEC_ALGS_EXEC_SYNC:
227e3320f40Smarkfen 		exec_mode_spdval = SPD_ALG_EXEC_MODE_SYNC;
228e3320f40Smarkfen 		break;
229e3320f40Smarkfen 	case LIBIPSEC_ALGS_EXEC_ASYNC:
230e3320f40Smarkfen 		exec_mode_spdval = SPD_ALG_EXEC_MODE_ASYNC;
231e3320f40Smarkfen 		break;
232e3320f40Smarkfen 	}
233e3320f40Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_PROTO_EXEC_MODE, exec_mode_spdval);
234e3320f40Smarkfen 
235e3320f40Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_NEXT, 0);
236e3320f40Smarkfen 
237e3320f40Smarkfen 	sync_req_proto_count++;
238e3320f40Smarkfen }
239e3320f40Smarkfen 
240e3320f40Smarkfen /*
241e3320f40Smarkfen  * Causes the kernel to be re-synched with the contents of /etc/inet/algs
242e3320f40Smarkfen  */
243e3320f40Smarkfen static void
244e3320f40Smarkfen kernel_synch(void)
245e3320f40Smarkfen {
246e3320f40Smarkfen 	int sfd = socket(PF_POLICY, SOCK_RAW, PF_POLICY_V1);
247e3320f40Smarkfen 	int cnt, req_len;
248e3320f40Smarkfen 	struct spd_msg *msg;
249e3320f40Smarkfen 	struct spd_ext_actions *act;
250e3320f40Smarkfen 	struct spd_attribute *attr;
251e3320f40Smarkfen 
252e3320f40Smarkfen 	if (sfd < 0) {
253e3320f40Smarkfen 		err(EXIT_FAILURE, gettext("Unable to open policy socket"));
254e3320f40Smarkfen 	}
255e3320f40Smarkfen 
256e3320f40Smarkfen 	/*
257e3320f40Smarkfen 	 * Initialize the SPD message header and action. Some fields
258e3320f40Smarkfen 	 * are set after having walked through the algorithms (number
259e3320f40Smarkfen 	 * of algorithms, sizes, etc.)
260e3320f40Smarkfen 	 */
261e3320f40Smarkfen 	msg = (struct spd_msg *)sync_req_buf;
262e3320f40Smarkfen 	(void) memset(msg, 0, sizeof (*msg));
263e3320f40Smarkfen 	msg->spd_msg_version = PF_POLICY_V1;
264e3320f40Smarkfen 	msg->spd_msg_type = SPD_UPDATEALGS;
265e3320f40Smarkfen 
266e3320f40Smarkfen 	act = (struct spd_ext_actions *)(msg + 1);
267e3320f40Smarkfen 	act->spd_actions_exttype = SPD_EXT_ACTION;
268e3320f40Smarkfen 	act->spd_actions_reserved = 0;
269e3320f40Smarkfen 
270e3320f40Smarkfen 	/*
271e3320f40Smarkfen 	 * Walk through the algorithms defined and populate the
272e3320f40Smarkfen 	 * request buffer.
273e3320f40Smarkfen 	 */
274e3320f40Smarkfen 	sync_req_alg_count = 0;
275e3320f40Smarkfen 	sync_req_proto_count = 0;
276e3320f40Smarkfen 	sync_req_attr = (struct spd_attribute *)(act + 1);
277e3320f40Smarkfen 	algs_walker(synch_emit_alg, synch_emit_proto);
278e3320f40Smarkfen 	act->spd_actions_count = sync_req_alg_count + sync_req_proto_count;
279e3320f40Smarkfen 
280e3320f40Smarkfen 	/*
281e3320f40Smarkfen 	 * Replace the last SPD_ATTR_NEXT attribute by a SPD_ATTR_END.
282e3320f40Smarkfen 	 */
283e3320f40Smarkfen 	attr = sync_req_attr - 1;
284e3320f40Smarkfen 	attr->spd_attr_tag = SPD_ATTR_END;
285e3320f40Smarkfen 
286e3320f40Smarkfen 	/*
287e3320f40Smarkfen 	 * Now that the message is built, compute its total length and
288e3320f40Smarkfen 	 * update the length fields that depend on this value.
289e3320f40Smarkfen 	 */
290e3320f40Smarkfen 	req_len = (char *)sync_req_attr - (char *)sync_req_buf;
291e3320f40Smarkfen 	msg->spd_msg_len = SPD_8TO64(req_len);
292e3320f40Smarkfen 	act->spd_actions_len = SPD_8TO64(req_len - sizeof (*msg));
293e3320f40Smarkfen 
294e3320f40Smarkfen 	/* ship the update request to spdsock */
295e3320f40Smarkfen 	cnt = write(sfd, sync_req_buf, req_len);
296e3320f40Smarkfen 	if (cnt != req_len) {
297e3320f40Smarkfen 		if (cnt < 0) {
298e3320f40Smarkfen 			err(EXIT_FAILURE, gettext("algs update write failed"));
299e3320f40Smarkfen 		} else {
300e3320f40Smarkfen 			errx(EXIT_FAILURE, gettext("algs update short write"));
301e3320f40Smarkfen 		}
302e3320f40Smarkfen 		/* err/errx call exit(). */
303e3320f40Smarkfen 	}
304e3320f40Smarkfen 
305e3320f40Smarkfen 	cnt = read(sfd, sync_req_buf, req_len);
306e3320f40Smarkfen 
307e3320f40Smarkfen 	if (cnt == -1) {
308e3320f40Smarkfen 		err(EXIT_FAILURE, gettext("algs update read failed"));
309e3320f40Smarkfen 	}
310e3320f40Smarkfen 
311e3320f40Smarkfen 	if (cnt < sizeof (struct spd_msg)) {
312e3320f40Smarkfen 		errx(EXIT_FAILURE, gettext(
313e3320f40Smarkfen 		    "algs update failed while reading reply (short read)"));
314e3320f40Smarkfen 	}
315e3320f40Smarkfen 
316e3320f40Smarkfen 	msg = (struct spd_msg *)sync_req_buf;
317e3320f40Smarkfen 	if (msg->spd_msg_errno != 0) {
318e3320f40Smarkfen 		errno = msg->spd_msg_errno;
319e3320f40Smarkfen 		warn(gettext("algs update failed"));
320e3320f40Smarkfen 		if (msg->spd_msg_diagnostic != 0) {
321e3320f40Smarkfen 			warnx("%s", spdsock_diag(msg->spd_msg_diagnostic));
322e3320f40Smarkfen 		}
323e3320f40Smarkfen 		exit(EXIT_FAILURE);
324e3320f40Smarkfen 	}
325e3320f40Smarkfen 
326e3320f40Smarkfen 	(void) close(sfd);
327e3320f40Smarkfen }
328e3320f40Smarkfen 
329e3320f40Smarkfen static void
330e3320f40Smarkfen list_kernel_algs(void)
331e3320f40Smarkfen {
332e3320f40Smarkfen 	int sfd = socket(PF_POLICY, SOCK_RAW, PF_POLICY_V1);
333e3320f40Smarkfen 	int cnt, retval;
334e3320f40Smarkfen 	uint64_t reply_buf[2048];
335e3320f40Smarkfen 	spd_ext_t *exts[SPD_EXT_MAX+1];
336e3320f40Smarkfen 	struct spd_msg msg;
337e3320f40Smarkfen 	struct spd_ext_actions *actp;
338e3320f40Smarkfen 	struct spd_attribute *attr, *endattr;
339e3320f40Smarkfen 	uint64_t *start, *end;
340e3320f40Smarkfen 	struct ipsecalgent alg;
341e3320f40Smarkfen 	uint_t cur_key, cur_block;
342*628b0c67SMark Fenwick 	uint_t nkey_sizes, nblock_sizes, nparams;
343e3320f40Smarkfen 	char diag_buf[SPDSOCK_DIAG_BUF_LEN];
344e3320f40Smarkfen 
345e3320f40Smarkfen 	if (sfd < 0) {
346e3320f40Smarkfen 		err(EXIT_FAILURE, gettext("Unable to open policy socket"));
347e3320f40Smarkfen 	}
348e3320f40Smarkfen 
349e3320f40Smarkfen 	(void) memset(&msg, 0, sizeof (msg));
350e3320f40Smarkfen 	msg.spd_msg_version = PF_POLICY_V1;
351e3320f40Smarkfen 	msg.spd_msg_type = SPD_DUMPALGS;
352e3320f40Smarkfen 	msg.spd_msg_len = SPD_8TO64(sizeof (msg));
353e3320f40Smarkfen 
354e3320f40Smarkfen 	cnt = write(sfd, &msg, sizeof (msg));
355e3320f40Smarkfen 	if (cnt != sizeof (msg)) {
356e3320f40Smarkfen 		if (cnt < 0) {
357e3320f40Smarkfen 			err(EXIT_FAILURE, gettext("dump algs write failed"));
358e3320f40Smarkfen 		} else {
359e3320f40Smarkfen 			errx(EXIT_FAILURE, gettext("dump algs short write"));
360e3320f40Smarkfen 		}
361e3320f40Smarkfen 		/* err/errx call exit(). */
362e3320f40Smarkfen 	}
363e3320f40Smarkfen 
364e3320f40Smarkfen 	cnt = read(sfd, reply_buf, sizeof (reply_buf));
365e3320f40Smarkfen 
366e3320f40Smarkfen 	if (cnt == -1) {
367e3320f40Smarkfen 		err(EXIT_FAILURE, gettext("dump algs read failed"));
368e3320f40Smarkfen 	}
369e3320f40Smarkfen 
370e3320f40Smarkfen 	if (cnt < sizeof (struct spd_msg)) {
371e3320f40Smarkfen 		errx(EXIT_FAILURE, gettext(
372e3320f40Smarkfen 		    "dump algs failed while reading reply (short read)"));
373e3320f40Smarkfen 	}
374e3320f40Smarkfen 
375e3320f40Smarkfen 	(void) close(sfd);
376e3320f40Smarkfen 
377e3320f40Smarkfen 	retval = spdsock_get_ext(exts, (spd_msg_t *)reply_buf, SPD_8TO64(cnt),
378e3320f40Smarkfen 	    diag_buf, SPDSOCK_DIAG_BUF_LEN);
379e3320f40Smarkfen 
380e3320f40Smarkfen 	if (retval == KGE_LEN && exts[0]->spd_ext_len == 0) {
381e3320f40Smarkfen 		/*
382e3320f40Smarkfen 		 * No algorithms are defined in the kernel, which caused
383e3320f40Smarkfen 		 * the extension length to be zero, and spdsock_get_ext()
384e3320f40Smarkfen 		 * to fail with a KGE_LEN error. This is not an error
385e3320f40Smarkfen 		 * condition, so we return nicely.
386e3320f40Smarkfen 		 */
387e3320f40Smarkfen 		return;
388e3320f40Smarkfen 	} else if (retval != 0) {
389e3320f40Smarkfen 		if (strlen(diag_buf) != 0)
390e3320f40Smarkfen 			warnx("%s", diag_buf);
391e3320f40Smarkfen 		errx(EXIT_FAILURE, gettext("invalid extension "
392e3320f40Smarkfen 		    "in dump algs reply (%d)"), retval);
393e3320f40Smarkfen 	}
394e3320f40Smarkfen 
395e3320f40Smarkfen 	if (exts[SPD_EXT_ACTION] == NULL) {
396e3320f40Smarkfen 		errx(EXIT_FAILURE,
397e3320f40Smarkfen 		    gettext("action missing in dump algs reply"));
398e3320f40Smarkfen 	}
399e3320f40Smarkfen 
400e3320f40Smarkfen 	actp = (struct spd_ext_actions *)exts[SPD_EXT_ACTION];
401e3320f40Smarkfen 	start = (uint64_t *)actp;
402e3320f40Smarkfen 	end = (start + actp->spd_actions_len);
403e3320f40Smarkfen 	endattr = (struct spd_attribute *)end;
404e3320f40Smarkfen 	attr = (struct spd_attribute *)&actp[1];
405e3320f40Smarkfen 
406e3320f40Smarkfen 	bzero(&alg, sizeof (alg));
407e3320f40Smarkfen 	nkey_sizes = nblock_sizes = 0;
408e3320f40Smarkfen 
409e3320f40Smarkfen 	(void) printf("Kernel list of algorithms:\n\n");
410e3320f40Smarkfen 
411e3320f40Smarkfen 	while (attr < endattr) {
412e3320f40Smarkfen 		switch (attr->spd_attr_tag) {
413e3320f40Smarkfen 		case SPD_ATTR_NOP:
414e3320f40Smarkfen 		case SPD_ATTR_EMPTY:
415e3320f40Smarkfen 			break;
416e3320f40Smarkfen 		case SPD_ATTR_END:
417e3320f40Smarkfen 			attr = endattr;
418e3320f40Smarkfen 			/* FALLTHRU */
419e3320f40Smarkfen 		case SPD_ATTR_NEXT:
420e3320f40Smarkfen 			/*
421e3320f40Smarkfen 			 * Note that if the message received from the spdsock
422e3320f40Smarkfen 			 * has a premature SPD_ATTR_END or SPD_ATTR_NEXT, this
423e3320f40Smarkfen 			 * could cause the current algorithm to be only
424e3320f40Smarkfen 			 * partially initialized.
425e3320f40Smarkfen 			 */
426*628b0c67SMark Fenwick 			alg.a_alg_flags |= ALG_FLAG_KERNELCHECKED;
427e3320f40Smarkfen 			dump_alg(&alg);
428e3320f40Smarkfen 			free(alg.a_key_sizes);
429e3320f40Smarkfen 			free(alg.a_block_sizes);
430e3320f40Smarkfen 			free(alg.a_mech_name);
431*628b0c67SMark Fenwick 			free(alg.a_mech_params);
432e3320f40Smarkfen 			bzero(&alg, sizeof (alg));
433e3320f40Smarkfen 			nkey_sizes = nblock_sizes = 0;
434e3320f40Smarkfen 			break;
435e3320f40Smarkfen 
436e3320f40Smarkfen 		case SPD_ATTR_ALG_ID:
437e3320f40Smarkfen 			alg.a_alg_num = attr->spd_attr_value;
438e3320f40Smarkfen 			break;
439e3320f40Smarkfen 
440e3320f40Smarkfen 		case SPD_ATTR_ALG_PROTO:
441e3320f40Smarkfen 			alg.a_proto_num = attr->spd_attr_value;
442e3320f40Smarkfen 			break;
443e3320f40Smarkfen 
444e3320f40Smarkfen 		case SPD_ATTR_ALG_INCRBITS:
445e3320f40Smarkfen 			alg.a_key_increment = attr->spd_attr_value;
446e3320f40Smarkfen 			break;
447e3320f40Smarkfen 
448e3320f40Smarkfen 		case SPD_ATTR_ALG_NKEYSIZES:
449e3320f40Smarkfen 			nkey_sizes = attr->spd_attr_value;
450e3320f40Smarkfen 			if (alg.a_key_sizes != NULL) {
451e3320f40Smarkfen 				errx(EXIT_FAILURE, gettext("duplicate number "
452e3320f40Smarkfen 				    "of keys in dump algs reply"));
453e3320f40Smarkfen 			}
454e3320f40Smarkfen 			alg.a_key_sizes = calloc(nkey_sizes + 1, sizeof (int));
455e3320f40Smarkfen 			if (alg.a_key_sizes == NULL)
456e3320f40Smarkfen 				bail_nomem();
457e3320f40Smarkfen 			cur_key = 0;
458e3320f40Smarkfen 			break;
459e3320f40Smarkfen 
460e3320f40Smarkfen 		case SPD_ATTR_ALG_KEYSIZE:
461e3320f40Smarkfen 			if (cur_key >= nkey_sizes) {
462e3320f40Smarkfen 				errx(EXIT_FAILURE, gettext("too many key sizes"
463e3320f40Smarkfen 				    " in dump algs reply"));
464e3320f40Smarkfen 			}
465e3320f40Smarkfen 			alg.a_key_sizes[cur_key++] = attr->spd_attr_value;
466e3320f40Smarkfen 			break;
467e3320f40Smarkfen 
468e3320f40Smarkfen 		case SPD_ATTR_ALG_NBLOCKSIZES:
469e3320f40Smarkfen 			nblock_sizes = attr->spd_attr_value;
470e3320f40Smarkfen 			if (alg.a_block_sizes != NULL) {
471e3320f40Smarkfen 				errx(EXIT_FAILURE, gettext("duplicate number "
472e3320f40Smarkfen 				    "of blocks in dump algs reply"));
473e3320f40Smarkfen 			}
474e3320f40Smarkfen 			alg.a_block_sizes = calloc(nblock_sizes + 1,
475e3320f40Smarkfen 			    sizeof (int));
476e3320f40Smarkfen 			if (alg.a_block_sizes == NULL)
477e3320f40Smarkfen 				bail_nomem();
478e3320f40Smarkfen 			cur_block = 0;
479e3320f40Smarkfen 			break;
480e3320f40Smarkfen 
481e3320f40Smarkfen 		case SPD_ATTR_ALG_BLOCKSIZE:
482e3320f40Smarkfen 			if (cur_block >= nblock_sizes) {
483e3320f40Smarkfen 				errx(EXIT_FAILURE, gettext("too many block "
484e3320f40Smarkfen 				    "sizes in dump algs reply"));
485e3320f40Smarkfen 			}
486e3320f40Smarkfen 			alg.a_block_sizes[cur_block++] = attr->spd_attr_value;
487e3320f40Smarkfen 			break;
488e3320f40Smarkfen 
489*628b0c67SMark Fenwick 		case SPD_ATTR_ALG_NPARAMS:
490*628b0c67SMark Fenwick 			nparams = attr->spd_attr_value;
491*628b0c67SMark Fenwick 			if (alg.a_mech_params != NULL) {
492*628b0c67SMark Fenwick 				errx(EXIT_FAILURE, gettext("duplicate number "
493*628b0c67SMark Fenwick 				    "of params in dump algs reply"));
494*628b0c67SMark Fenwick 			}
495*628b0c67SMark Fenwick 			alg.a_mech_params = calloc(nparams + 1,
496*628b0c67SMark Fenwick 			    sizeof (int));
497*628b0c67SMark Fenwick 			if (alg.a_mech_params == NULL)
498*628b0c67SMark Fenwick 				bail_nomem();
499*628b0c67SMark Fenwick 			cur_block = 0;
500*628b0c67SMark Fenwick 			break;
501*628b0c67SMark Fenwick 
502*628b0c67SMark Fenwick 		case SPD_ATTR_ALG_PARAMS:
503*628b0c67SMark Fenwick 			if (cur_block >= nparams) {
504*628b0c67SMark Fenwick 				errx(EXIT_FAILURE, gettext("too many params "
505*628b0c67SMark Fenwick 				    "in dump algs reply"));
506*628b0c67SMark Fenwick 			}
507*628b0c67SMark Fenwick 			alg.a_mech_params[cur_block++] = attr->spd_attr_value;
508*628b0c67SMark Fenwick 			break;
509*628b0c67SMark Fenwick 
510*628b0c67SMark Fenwick 		case SPD_ATTR_ALG_FLAGS:
511*628b0c67SMark Fenwick 			alg.a_alg_flags = attr->spd_attr_value;
512*628b0c67SMark Fenwick 			break;
513*628b0c67SMark Fenwick 
514e3320f40Smarkfen 		case SPD_ATTR_ALG_MECHNAME: {
515e3320f40Smarkfen 			char *mech_name;
516e3320f40Smarkfen 
517e3320f40Smarkfen 			if (alg.a_mech_name != NULL) {
518e3320f40Smarkfen 				errx(EXIT_FAILURE, gettext(
519e3320f40Smarkfen 				    "duplicate mech name in dump algs reply"));
520e3320f40Smarkfen 			}
521e3320f40Smarkfen 
522e3320f40Smarkfen 			alg.a_mech_name = malloc(attr->spd_attr_value);
523e3320f40Smarkfen 			if (alg.a_mech_name == NULL)
524e3320f40Smarkfen 				bail_nomem();
525e3320f40Smarkfen 
526e3320f40Smarkfen 			mech_name = (char *)(attr + 1);
527e3320f40Smarkfen 			bcopy(mech_name, alg.a_mech_name, attr->spd_attr_value);
528e3320f40Smarkfen 			attr = (struct spd_attribute *)((uint64_t *)attr +
529e3320f40Smarkfen 			    SPD_8TO64(attr->spd_attr_value));
530e3320f40Smarkfen 			break;
531e3320f40Smarkfen 		}
532e3320f40Smarkfen 		}
533e3320f40Smarkfen 		attr++;
534e3320f40Smarkfen 	}
535e3320f40Smarkfen 
536e3320f40Smarkfen }
537e3320f40Smarkfen 
538e3320f40Smarkfen 
539e3320f40Smarkfen static int *
540e3320f40Smarkfen parse_intlist(char *args, int *num_args)
541e3320f40Smarkfen {
542e3320f40Smarkfen 	int *rc = NULL;
543e3320f40Smarkfen 	char *holder = NULL;
544e3320f40Smarkfen 
545e3320f40Smarkfen 	while ((holder = strtok((holder == NULL) ? args : NULL, comma)) !=
546e3320f40Smarkfen 	    NULL) {
547e3320f40Smarkfen 		(*num_args)++;
548e3320f40Smarkfen 		rc = realloc(rc, ((*num_args) + 1) * sizeof (int));
549e3320f40Smarkfen 		if (rc == NULL)
550e3320f40Smarkfen 			bail_nomem();
551e3320f40Smarkfen 		rc[(*num_args) - 1] = atoi(holder);
552e3320f40Smarkfen 		if (rc[(*num_args) - 1] == 0)
553e3320f40Smarkfen 			usage();	/* Malformed integer list! */
554e3320f40Smarkfen 		rc[*num_args] = 0;
555e3320f40Smarkfen 	}
556e3320f40Smarkfen 
557e3320f40Smarkfen 	return (rc);
558e3320f40Smarkfen }
559e3320f40Smarkfen 
560e3320f40Smarkfen static void
561e3320f40Smarkfen new_alg(void)
562e3320f40Smarkfen {
563e3320f40Smarkfen 	struct ipsecalgent newbie;
564e3320f40Smarkfen 	int num_names = 0, num_block_sizes = 0, num_key_sizes = 0;
565e3320f40Smarkfen 	int i, rc;
566e3320f40Smarkfen 	char *holder = NULL;
567e3320f40Smarkfen 
568e3320f40Smarkfen 	/* Parameter reality check... */
569e3320f40Smarkfen 	if (proto_number == -1) {
570e3320f40Smarkfen 		if (proto_name == NULL) {
571e3320f40Smarkfen 			warnx(gettext("Missing protocol number."));
572e3320f40Smarkfen 			usage();
573e3320f40Smarkfen 		}
574e3320f40Smarkfen 		proto_number = getipsecprotobyname(proto_name);
575e3320f40Smarkfen 		if (proto_number == -1) {
576e3320f40Smarkfen 			warnx(gettext("Unknown protocol."));
577e3320f40Smarkfen 			usage();
578e3320f40Smarkfen 		}
579e3320f40Smarkfen 	}
580e3320f40Smarkfen 	if (alg_number == -1) {
581e3320f40Smarkfen 		warnx(gettext("Missing algorithm number."));
582e3320f40Smarkfen 		usage();
583e3320f40Smarkfen 	}
584e3320f40Smarkfen 	if (key_sizes_string == NULL) {
585e3320f40Smarkfen 		warnx(gettext("Missing key size(s)."));
586e3320f40Smarkfen 		usage();
587e3320f40Smarkfen 	}
588e3320f40Smarkfen 	if (alg_names_string == NULL) {
589e3320f40Smarkfen 		warnx(gettext("Missing algorithm name(s)."));
590e3320f40Smarkfen 		usage();
591e3320f40Smarkfen 	}
592e3320f40Smarkfen 	if (block_sizes_string == NULL) {
593e3320f40Smarkfen 		warnx(gettext("Missing block/MAC lengths"));
594e3320f40Smarkfen 		usage();
595e3320f40Smarkfen 	}
596e3320f40Smarkfen 	if (mech_name == NULL) {
597e3320f40Smarkfen 		warnx(gettext("Missing mechanism name."));
598e3320f40Smarkfen 		usage();
599e3320f40Smarkfen 	}
600e3320f40Smarkfen 	newbie.a_proto_num = proto_number;
601e3320f40Smarkfen 	newbie.a_alg_num = alg_number;
602e3320f40Smarkfen 	newbie.a_key_increment = increment;
603e3320f40Smarkfen 	newbie.a_mech_name = mech_name;
604*628b0c67SMark Fenwick 	newbie.a_alg_flags = alg_flags;
605e3320f40Smarkfen 
606*628b0c67SMark Fenwick 	/*
607*628b0c67SMark Fenwick 	 * The ALG_FLAG_VALID is somewhat irrelevant as an input from the
608*628b0c67SMark Fenwick 	 * user, the kernel will decide if the algorithm description is
609*628b0c67SMark Fenwick 	 * valid or not and set the ALG_FLAG_VALID when the user dumps
610*628b0c67SMark Fenwick 	 * the kernel tables. To avoid confusion when the user dumps the
611*628b0c67SMark Fenwick 	 * contents off the ipsecalgs file, we set the ALG_FLAG_VALID here.
612*628b0c67SMark Fenwick 	 */
613*628b0c67SMark Fenwick 	newbie.a_alg_flags |= ALG_FLAG_VALID;
614*628b0c67SMark Fenwick 	while ((holder = strtok((holder == NULL) ? flag_string : NULL,
615*628b0c67SMark Fenwick 	    comma)) != NULL) {
616*628b0c67SMark Fenwick 		alg_flags = parse_flag(holder, 0);
617*628b0c67SMark Fenwick 		if (!alg_flags) {
618*628b0c67SMark Fenwick 			warnx(gettext("Invalid flag: %s\n"), holder);
619*628b0c67SMark Fenwick 			usage();
620*628b0c67SMark Fenwick 		}
621*628b0c67SMark Fenwick 		newbie.a_alg_flags |= alg_flags;
622*628b0c67SMark Fenwick 	}
623e3320f40Smarkfen 	newbie.a_names = NULL;
624e3320f40Smarkfen 	while ((holder = strtok((holder == NULL) ? alg_names_string : NULL,
625e3320f40Smarkfen 	    comma)) != NULL) {
626e3320f40Smarkfen 		newbie.a_names = realloc(newbie.a_names,
627e3320f40Smarkfen 		    sizeof (char *) * ((++num_names) + 1));
628e3320f40Smarkfen 		if (newbie.a_names == NULL)
629e3320f40Smarkfen 			bail_nomem();
630e3320f40Smarkfen 		newbie.a_names[num_names - 1] = holder;
631e3320f40Smarkfen 		newbie.a_names[num_names] = NULL;
632e3320f40Smarkfen 	}
633e3320f40Smarkfen 
634e3320f40Smarkfen 	/* Extract block sizes. */
635e3320f40Smarkfen 	newbie.a_block_sizes = parse_intlist(block_sizes_string,
636e3320f40Smarkfen 	    &num_block_sizes);
637*628b0c67SMark Fenwick 	newbie.a_mech_params = &mech_params[0];
638e3320f40Smarkfen 
639e3320f40Smarkfen 	/* Extract key sizes. */
640e3320f40Smarkfen 	if ((holder = strchr(key_sizes_string, '-')) != NULL) {
641e3320f40Smarkfen 		/* key sizes by range, key size increment required */
642e3320f40Smarkfen 		if (newbie.a_key_increment == 0) {
643e3320f40Smarkfen 			warnx(gettext("Missing key increment"));
644e3320f40Smarkfen 			usage();
645e3320f40Smarkfen 		}
646e3320f40Smarkfen 		newbie.a_key_sizes = calloc(sizeof (int),
647e3320f40Smarkfen 		    LIBIPSEC_ALGS_KEY_NUM_VAL);
648e3320f40Smarkfen 		if (newbie.a_key_sizes == NULL)
649e3320f40Smarkfen 			bail_nomem();
650e3320f40Smarkfen 		*holder = '\0';
651e3320f40Smarkfen 		holder++;
652e3320f40Smarkfen 		/*
653e3320f40Smarkfen 		 * At this point, holder points to high, key_sizes_string
654e3320f40Smarkfen 		 * points to low.
655e3320f40Smarkfen 		 */
656e3320f40Smarkfen 		newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] =
657e3320f40Smarkfen 		    atoi(key_sizes_string);
658e3320f40Smarkfen 		if (newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] == 0) {
659e3320f40Smarkfen 			warnx(gettext("Invalid lower key size range"));
660e3320f40Smarkfen 			usage();
661e3320f40Smarkfen 		}
662e3320f40Smarkfen 		newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] = atoi(holder);
663e3320f40Smarkfen 		if (newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] == 0) {
664e3320f40Smarkfen 			warnx(gettext("Invalid higher key size range"));
665e3320f40Smarkfen 			usage();
666e3320f40Smarkfen 		}
667e3320f40Smarkfen 
668e3320f40Smarkfen 		/* sanity check key range consistency */
669e3320f40Smarkfen 		if (newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] >=
670e3320f40Smarkfen 		    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX]) {
671e3320f40Smarkfen 			warnx(gettext("Invalid key size range (min >= max)"));
672e3320f40Smarkfen 			usage();
673e3320f40Smarkfen 		}
674e3320f40Smarkfen 
675e3320f40Smarkfen 		/* check key increment vs key range */
676e3320f40Smarkfen 		if (((newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] -
677e3320f40Smarkfen 		    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX]) %
678e3320f40Smarkfen 		    newbie.a_key_increment) != 0) {
679e3320f40Smarkfen 			warnx(gettext("Key size increment"
680e3320f40Smarkfen 			    " not consistent with key size range"));
681e3320f40Smarkfen 			usage();
682e3320f40Smarkfen 		}
683e3320f40Smarkfen 
684e3320f40Smarkfen 		/* default key size */
685e3320f40Smarkfen 		if (default_keylen != 0) {
686e3320f40Smarkfen 			/* check specified default key size */
687e3320f40Smarkfen 			if (default_keylen <
688e3320f40Smarkfen 			    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] ||
689e3320f40Smarkfen 			    default_keylen >
690e3320f40Smarkfen 			    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] ||
691e3320f40Smarkfen 			    ((default_keylen -
692e3320f40Smarkfen 			    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX]) %
693e3320f40Smarkfen 			    newbie.a_key_increment) != 0) {
694e3320f40Smarkfen 				warnx(gettext("Default key size not consistent"
695e3320f40Smarkfen 				    " with key size range"));
696e3320f40Smarkfen 				usage();
697e3320f40Smarkfen 			}
698e3320f40Smarkfen 			newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_DEF_IDX] =
699e3320f40Smarkfen 			    default_keylen;
700e3320f40Smarkfen 		} else {
701e3320f40Smarkfen 			/* min key size in range if not specified */
702e3320f40Smarkfen 			newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_DEF_IDX] =
703e3320f40Smarkfen 			    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX];
704e3320f40Smarkfen 		}
705e3320f40Smarkfen 	} else {
706e3320f40Smarkfen 		/* key sizes by enumeration */
707e3320f40Smarkfen 		if (newbie.a_key_increment != 0) {
708e3320f40Smarkfen 			warnx(gettext("Key increment must "
709e3320f40Smarkfen 			    "not be specified with key sizes enumeration"));
710e3320f40Smarkfen 			usage();
711e3320f40Smarkfen 		}
712e3320f40Smarkfen 		newbie.a_key_sizes = parse_intlist(key_sizes_string,
713e3320f40Smarkfen 		    &num_key_sizes);
714e3320f40Smarkfen 
715e3320f40Smarkfen 		/* default key size */
716e3320f40Smarkfen 		if (default_keylen != 0 && default_keylen !=
717e3320f40Smarkfen 		    newbie.a_key_sizes[0]) {
718e3320f40Smarkfen 			/*
719e3320f40Smarkfen 			 * The default key size is not at the front of the
720e3320f40Smarkfen 			 * list. Swap it with the first element of the list.
721e3320f40Smarkfen 			 */
722e3320f40Smarkfen 			for (i = 1; i < num_key_sizes; i++) {
723e3320f40Smarkfen 				if (newbie.a_key_sizes[i] == default_keylen)
724e3320f40Smarkfen 					break;
725e3320f40Smarkfen 				if (i >= num_key_sizes) {
726e3320f40Smarkfen 					warnx(gettext("Default key size not "
727e3320f40Smarkfen 					    "in list of key sizes"));
728e3320f40Smarkfen 					usage();
729e3320f40Smarkfen 				}
730e3320f40Smarkfen 				newbie.a_key_sizes[i] = newbie.a_key_sizes[0];
731e3320f40Smarkfen 				newbie.a_key_sizes[0] = default_keylen;
732e3320f40Smarkfen 			}
733e3320f40Smarkfen 		}
734e3320f40Smarkfen 	}
735e3320f40Smarkfen 
736e3320f40Smarkfen 	/* Call things! */
737e3320f40Smarkfen 	if ((rc = addipsecalg(&newbie, adddel_flags)) != 0) {
738e3320f40Smarkfen 		errx(EXIT_FAILURE, gettext("addipsecalg() call failed: "
739e3320f40Smarkfen 		    "%s"), ipsecalgs_diag(rc));
740e3320f40Smarkfen 	}
741e3320f40Smarkfen 
742e3320f40Smarkfen 	free(newbie.a_names);
743e3320f40Smarkfen 	free(newbie.a_block_sizes);
744e3320f40Smarkfen 	free(newbie.a_key_sizes);
745e3320f40Smarkfen }
746e3320f40Smarkfen 
747e3320f40Smarkfen static void
748e3320f40Smarkfen new_proto(void)
749e3320f40Smarkfen {
750e3320f40Smarkfen 	int rc;
751e3320f40Smarkfen 
752e3320f40Smarkfen 	if ((rc = addipsecproto(proto_name, proto_number, proto_exec_mode,
753e3320f40Smarkfen 	    adddel_flags))
754e3320f40Smarkfen 	    != 0) {
755e3320f40Smarkfen 		errx(EXIT_FAILURE, gettext(
756e3320f40Smarkfen 		    "Cannot add protocol %1$d \"%2$s\": %3$s"), proto_number,
757e3320f40Smarkfen 		    proto_name, ipsecalgs_diag(rc));
758e3320f40Smarkfen 	}
759e3320f40Smarkfen }
760e3320f40Smarkfen 
761e3320f40Smarkfen static void
762e3320f40Smarkfen remove_alg(void)
763e3320f40Smarkfen {
764e3320f40Smarkfen 	int rc;
765e3320f40Smarkfen 
766e3320f40Smarkfen 	if (proto_number == -1) {
767e3320f40Smarkfen 		if (proto_name == NULL) {
768e3320f40Smarkfen 			warnx(gettext("Missing protocol number."));
769e3320f40Smarkfen 			usage();
770e3320f40Smarkfen 		}
771e3320f40Smarkfen 		proto_number = getipsecprotobyname(proto_name);
772e3320f40Smarkfen 		if (proto_number == -1) {
773e3320f40Smarkfen 			errx(EXIT_FAILURE, gettext(
774e3320f40Smarkfen 			    "Unknown protocol \"%s\"."), proto_name);
775e3320f40Smarkfen 		}
776e3320f40Smarkfen 	}
777e3320f40Smarkfen 
778e3320f40Smarkfen 	if (alg_number == -1) {
779e3320f40Smarkfen 		if (alg_names_string == NULL) {
780e3320f40Smarkfen 			errx(EXIT_FAILURE, gettext("Missing algorithm ID."));
781e3320f40Smarkfen 		}
782e3320f40Smarkfen 		if (strchr(alg_names_string, ',') != NULL) {
783e3320f40Smarkfen 			errx(EXIT_FAILURE, gettext(
784e3320f40Smarkfen 			    "Specify a single algorithm name for removal, "
785e3320f40Smarkfen 			    "not a list."));
786e3320f40Smarkfen 		}
787e3320f40Smarkfen 		if ((rc = delipsecalgbyname(alg_names_string, proto_number))
788e3320f40Smarkfen 		    != 0) {
789e3320f40Smarkfen 			errx(EXIT_FAILURE, gettext(
790e3320f40Smarkfen 			    "Could not remove algorithm %1$s: %2$s"),
791e3320f40Smarkfen 			    alg_names_string, ipsecalgs_diag(rc));
792e3320f40Smarkfen 		}
793e3320f40Smarkfen 	} else {
794e3320f40Smarkfen 		if ((rc = delipsecalgbynum(alg_number, proto_number)) != 0) {
795e3320f40Smarkfen 			errx(EXIT_FAILURE, gettext(
796e3320f40Smarkfen 			    "Could not remove algorithm %1$d: %2$s"),
797e3320f40Smarkfen 			    alg_number, ipsecalgs_diag(rc));
798e3320f40Smarkfen 		}
799e3320f40Smarkfen 	}
800e3320f40Smarkfen }
801e3320f40Smarkfen 
802e3320f40Smarkfen static void
803e3320f40Smarkfen remove_proto(void)
804e3320f40Smarkfen {
805e3320f40Smarkfen 	int rc;
806e3320f40Smarkfen 
807e3320f40Smarkfen 	if (proto_number == -1) {
808e3320f40Smarkfen 		if (proto_name == NULL) {
809e3320f40Smarkfen 			warnx(gettext("Please specify protocol to remove."));
810e3320f40Smarkfen 			usage();
811e3320f40Smarkfen 		}
812e3320f40Smarkfen 		if ((rc = delipsecprotobyname(proto_name)) != 0) {
813e3320f40Smarkfen 			errx(EXIT_FAILURE, gettext(
814e3320f40Smarkfen 			    "Could not remove protocol %1$s: %2$s"),
815e3320f40Smarkfen 			    proto_name, ipsecalgs_diag(rc));
816e3320f40Smarkfen 		}
817e3320f40Smarkfen 	} else {
818e3320f40Smarkfen 		if ((rc = delipsecprotobynum(proto_number)) != 0) {
819e3320f40Smarkfen 			errx(EXIT_FAILURE, gettext(
820e3320f40Smarkfen 			    "Could not remove protocol %1$d: %2$s"),
821e3320f40Smarkfen 			    proto_number, ipsecalgs_diag(rc));
822e3320f40Smarkfen 		}
823e3320f40Smarkfen 	}
824e3320f40Smarkfen }
825e3320f40Smarkfen 
826e3320f40Smarkfen static void
827e3320f40Smarkfen set_exec_mode(void)
828e3320f40Smarkfen {
829e3320f40Smarkfen 	int rc;
830e3320f40Smarkfen 
831e3320f40Smarkfen 	if (proto_number == -1) {
832e3320f40Smarkfen 		if (proto_name == NULL) {
833e3320f40Smarkfen 			warnx(gettext(
834e3320f40Smarkfen 			    "Please specify protocol name or number."));
835e3320f40Smarkfen 			usage();
836e3320f40Smarkfen 		}
837e3320f40Smarkfen 		proto_number = getipsecprotobyname(proto_name);
838e3320f40Smarkfen 		if (proto_number == -1) {
839e3320f40Smarkfen 			errx(EXIT_FAILURE, gettext("Unknown protocol %s"),
840e3320f40Smarkfen 			    proto_name);
841e3320f40Smarkfen 		}
842e3320f40Smarkfen 	}
843e3320f40Smarkfen 
844e3320f40Smarkfen 	if ((rc = ipsecproto_set_exec_mode(proto_number, proto_exec_mode))
845e3320f40Smarkfen 	    != 0) {
846e3320f40Smarkfen 		errx(EXIT_FAILURE, gettext("Cannot set execution mode: %s"),
847e3320f40Smarkfen 		    ipsecalgs_diag(rc));
848e3320f40Smarkfen 	}
849e3320f40Smarkfen }
850e3320f40Smarkfen 
851e3320f40Smarkfen /*
852e3320f40Smarkfen  * Print a description of an algorithm to standard output.
853e3320f40Smarkfen  */
854e3320f40Smarkfen static void
855e3320f40Smarkfen dump_alg(struct ipsecalgent *alg)
856e3320f40Smarkfen {
857e3320f40Smarkfen 	int *ifloater;
858e3320f40Smarkfen 	char **floater;
859e3320f40Smarkfen 
860e3320f40Smarkfen 	/* protocol number */
861e3320f40Smarkfen 	(void) printf(gettext("\tProtocol number: %d\n"), alg->a_proto_num);
862e3320f40Smarkfen 
863e3320f40Smarkfen 	/* algorithm number */
864e3320f40Smarkfen 	(void) printf(gettext("\tAlgorithm number: %d\n"), alg->a_alg_num);
865e3320f40Smarkfen 
866e3320f40Smarkfen 	/* algorithm name(s) */
867e3320f40Smarkfen 	if (alg->a_names != NULL) {
868e3320f40Smarkfen 		(void) printf(gettext("\tAlgorithm names: "));
869e3320f40Smarkfen 		floater = alg->a_names;
870e3320f40Smarkfen 		assert(floater != NULL && *floater != NULL);
871e3320f40Smarkfen 		do {
872e3320f40Smarkfen 			/* Assume at least one string. */
873e3320f40Smarkfen 			(void) printf("%s", *floater);
874e3320f40Smarkfen 			if (*(++floater) != NULL)
875e3320f40Smarkfen 				(void) putchar(',');
876e3320f40Smarkfen 		} while (*floater != NULL);
877e3320f40Smarkfen 		(void) putchar('\n');
878e3320f40Smarkfen 	}
879e3320f40Smarkfen 
880e3320f40Smarkfen 	/* mechanism name */
881e3320f40Smarkfen 	(void) printf(gettext("\tMechanism Name: %s\n"), alg->a_mech_name);
882e3320f40Smarkfen 
883e3320f40Smarkfen 	/* block/MAC sizes */
884e3320f40Smarkfen 	(void) printf(gettext("\tBlock sizes or MAC sizes: "));
885e3320f40Smarkfen 	ifloater = alg->a_block_sizes;
886e3320f40Smarkfen 	(void) list_ints(stdout, ifloater);
887e3320f40Smarkfen 	(void) putchar('\n');
888e3320f40Smarkfen 
889e3320f40Smarkfen 	/* key sizes */
890e3320f40Smarkfen 	(void) printf(gettext("\tKey sizes: "));
891e3320f40Smarkfen 	if (alg->a_key_increment != 0)
892e3320f40Smarkfen 		/* key specified by range */
893e3320f40Smarkfen 		(void) printf(gettext(
894e3320f40Smarkfen 		    "%1$d-%2$d, increment %3$d, default %4$d"),
895e3320f40Smarkfen 		    alg->a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX],
896e3320f40Smarkfen 		    alg->a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX],
897e3320f40Smarkfen 		    alg->a_key_increment,
898e3320f40Smarkfen 		    alg->a_key_sizes[LIBIPSEC_ALGS_KEY_DEF_IDX]);
899e3320f40Smarkfen 	else
900e3320f40Smarkfen 		/* key specified by enumeration */
901e3320f40Smarkfen 		(void) list_ints(stdout, alg->a_key_sizes);
902e3320f40Smarkfen 	(void) putchar('\n');
903e3320f40Smarkfen 
904*628b0c67SMark Fenwick 	/* Alg parameters */
905*628b0c67SMark Fenwick 	(void) printf(gettext("\tAlgorithm parameters: "));
906*628b0c67SMark Fenwick 	ifloater = alg->a_mech_params;
907*628b0c67SMark Fenwick 	(void) list_ints(stdout, ifloater);
908*628b0c67SMark Fenwick 	(void) putchar('\n');
909*628b0c67SMark Fenwick 
910*628b0c67SMark Fenwick 	/* Alg flags */
911*628b0c67SMark Fenwick 	(void) printf(gettext("\tAlgorithm flags: "));
912*628b0c67SMark Fenwick 	(void) parse_flag(NULL, alg->a_alg_flags);
913*628b0c67SMark Fenwick 
914*628b0c67SMark Fenwick 	(void) putchar('\n');
915e3320f40Smarkfen 	(void) putchar('\n');
916e3320f40Smarkfen }
917e3320f40Smarkfen 
918e3320f40Smarkfen /*
919e3320f40Smarkfen  * Print the description of a protocol.
920e3320f40Smarkfen  */
921e3320f40Smarkfen static void
922e3320f40Smarkfen dump_proto(uint_t proto_id)
923e3320f40Smarkfen {
924e3320f40Smarkfen 	char *proto_name;
925e3320f40Smarkfen 	ipsecalgs_exec_mode_t exec_mode;
926e3320f40Smarkfen 
927e3320f40Smarkfen 	/* protocol name and number */
928e3320f40Smarkfen 	proto_name = getipsecprotobynum(proto_id);
929e3320f40Smarkfen 	(void) printf(gettext("Protocol %1$d/%2$s "),
930e3320f40Smarkfen 	    proto_id, proto_name != NULL ? proto_name : gettext("<unknown>"));
931e3320f40Smarkfen 
932e3320f40Smarkfen 	/* execution mode */
933e3320f40Smarkfen 	(void) printf("(%s", gettext("execution mode: "));
934e3320f40Smarkfen 
935e3320f40Smarkfen 	if (ipsecproto_get_exec_mode(proto_id, &exec_mode) != 0) {
936e3320f40Smarkfen 		(void) printf(gettext("<unknown>"));
937e3320f40Smarkfen 	} else {
938e3320f40Smarkfen 		switch (exec_mode) {
939e3320f40Smarkfen 		case LIBIPSEC_ALGS_EXEC_SYNC:
940e3320f40Smarkfen 			(void) printf("sync");
941e3320f40Smarkfen 			break;
942e3320f40Smarkfen 		case LIBIPSEC_ALGS_EXEC_ASYNC:
943e3320f40Smarkfen 			(void) printf("async");
944e3320f40Smarkfen 			break;
945e3320f40Smarkfen 		}
946e3320f40Smarkfen 	}
947e3320f40Smarkfen 
948e3320f40Smarkfen 	(void) printf(")\n\n");
949e3320f40Smarkfen 
950e3320f40Smarkfen 	free(proto_name);
951e3320f40Smarkfen }
952e3320f40Smarkfen 
953e3320f40Smarkfen 
954e3320f40Smarkfen /*
955e3320f40Smarkfen  * Algorithm walker table. Call proto_action() for each protocol,
956e3320f40Smarkfen  * and alg_action() for each algorithm.
957e3320f40Smarkfen  */
958e3320f40Smarkfen static void
959e3320f40Smarkfen algs_walker(void (*alg_action)(struct ipsecalgent *),
960e3320f40Smarkfen     void (*proto_action)(uint_t))
961e3320f40Smarkfen {
962e3320f40Smarkfen 	int *proto_nums, proto_count, i;
963e3320f40Smarkfen 	int *alg_nums, alg_count, j;
964e3320f40Smarkfen 	struct ipsecalgent *alg;
965e3320f40Smarkfen 
966e3320f40Smarkfen 	proto_nums = getipsecprotos(&proto_count);
967e3320f40Smarkfen 	if (proto_nums == NULL) {
968e3320f40Smarkfen 		errx(EXIT_FAILURE, gettext("getipsecprotos() failed."));
969e3320f40Smarkfen 	}
970e3320f40Smarkfen 
971e3320f40Smarkfen 	for (i = 0; i < proto_count; i++) {
972e3320f40Smarkfen 
973e3320f40Smarkfen 		if (proto_action != NULL)
974e3320f40Smarkfen 			proto_action(proto_nums[i]);
975e3320f40Smarkfen 
976e3320f40Smarkfen 		alg_nums = getipsecalgs(&alg_count, proto_nums[i]);
977e3320f40Smarkfen 		if (alg_nums == NULL) {
978e3320f40Smarkfen 			free(proto_nums);
979e3320f40Smarkfen 			errx(EXIT_FAILURE, gettext("getipsecalgs() failed."));
980e3320f40Smarkfen 		}
981e3320f40Smarkfen 
982e3320f40Smarkfen 		for (j = 0; j < alg_count; j++) {
983e3320f40Smarkfen 			alg = getipsecalgbynum(alg_nums[j], proto_nums[i],
984e3320f40Smarkfen 			    NULL);
985e3320f40Smarkfen 			if (alg == NULL)
986e3320f40Smarkfen 				continue;
987e3320f40Smarkfen 			if (alg_action != NULL)
988e3320f40Smarkfen 				alg_action(alg);
989e3320f40Smarkfen 			freeipsecalgent(alg);
990e3320f40Smarkfen 		}
991e3320f40Smarkfen 		free(alg_nums);
992e3320f40Smarkfen 	}
993e3320f40Smarkfen 	free(proto_nums);
994e3320f40Smarkfen }
995e3320f40Smarkfen 
996e3320f40Smarkfen /*
997e3320f40Smarkfen  * Use just the libnsl/libipsecutil APIs to dump out all of the algorithms.
998e3320f40Smarkfen  */
999e3320f40Smarkfen static void
1000e3320f40Smarkfen show_algs(void)
1001e3320f40Smarkfen {
1002e3320f40Smarkfen 	/* Yes, I'm aware that this'll produce TWO newlines. */
1003e3320f40Smarkfen 	(void) puts(gettext(
1004e3320f40Smarkfen 	    "List of algorithms, grouped by IPsec protocol:\n"));
1005e3320f40Smarkfen 
1006e3320f40Smarkfen 	algs_walker(dump_alg, dump_proto);
1007e3320f40Smarkfen }
1008e3320f40Smarkfen 
1009e3320f40Smarkfen static int
1010e3320f40Smarkfen try_int(char *optarg, const char *what)
1011e3320f40Smarkfen {
1012e3320f40Smarkfen 	int rc = atoi(optarg);
1013e3320f40Smarkfen 
1014e3320f40Smarkfen 	if (rc <= 0) {
1015e3320f40Smarkfen 		warnx(gettext("Invalid %s value"), what);
1016e3320f40Smarkfen 		usage();
1017e3320f40Smarkfen 	}
1018e3320f40Smarkfen 	return (rc);
1019e3320f40Smarkfen }
1020e3320f40Smarkfen 
1021e3320f40Smarkfen static void
1022e3320f40Smarkfen try_cmd(cmd_t newcmd)
1023e3320f40Smarkfen {
1024e3320f40Smarkfen 	if (cmd != CMD_NONE)
1025e3320f40Smarkfen 		usage();
1026e3320f40Smarkfen 	cmd = newcmd;
1027e3320f40Smarkfen }
1028e3320f40Smarkfen 
1029e3320f40Smarkfen int
1030e3320f40Smarkfen main(int argc, char *argv[])
1031e3320f40Smarkfen {
1032e3320f40Smarkfen 	int c;
1033e3320f40Smarkfen 	zoneid_t zoneid;
1034e3320f40Smarkfen 	ushort_t flags;
1035e3320f40Smarkfen 
1036e3320f40Smarkfen 	(void) setlocale(LC_ALL, "");
1037e3320f40Smarkfen #if !defined(TEXT_DOMAIN)
1038e3320f40Smarkfen #define	TEXT_DOMAIN "SYS_TEST"
1039e3320f40Smarkfen #endif
1040e3320f40Smarkfen 	(void) textdomain(TEXT_DOMAIN);
1041e3320f40Smarkfen 
1042e3320f40Smarkfen 	if (argc == 1) {
1043e3320f40Smarkfen 		show_algs();
1044e3320f40Smarkfen 		return (EXIT_SUCCESS);
1045e3320f40Smarkfen 	}
1046e3320f40Smarkfen 
1047e3320f40Smarkfen 	while ((c = getopt(argc, argv,
1048*628b0c67SMark Fenwick 	    "aflrRsb:p:P:i:k:K:m:n:N:e:S:M:I:F:")) != EOF) {
1049e3320f40Smarkfen 		switch (c) {
1050e3320f40Smarkfen 		case 'a':
1051e3320f40Smarkfen 			try_cmd(CMD_ADD);
1052e3320f40Smarkfen 			break;
1053e3320f40Smarkfen 		case 'f':
1054e3320f40Smarkfen 			/* multiple occurences of -f are harmless */
1055e3320f40Smarkfen 			adddel_flags = LIBIPSEC_ALGS_ADD_FORCE;
1056e3320f40Smarkfen 			break;
1057e3320f40Smarkfen 		case 'l':
1058e3320f40Smarkfen 			try_cmd(CMD_LIST_KERNEL);
1059e3320f40Smarkfen 			break;
1060e3320f40Smarkfen 		case 'r':
1061e3320f40Smarkfen 			try_cmd(CMD_DEL);
1062e3320f40Smarkfen 			break;
1063e3320f40Smarkfen 		case 'R':
1064e3320f40Smarkfen 			try_cmd(CMD_DEL_PROTO);
1065e3320f40Smarkfen 			break;
1066e3320f40Smarkfen 		case 's':
1067e3320f40Smarkfen 			/* multiple occurences of -s are harmless */
1068e3320f40Smarkfen 			synch_kernel = B_TRUE;
1069e3320f40Smarkfen 			break;
1070e3320f40Smarkfen 		case 'n':
1071e3320f40Smarkfen 			if (alg_names_string != NULL)
1072e3320f40Smarkfen 				usage();
1073e3320f40Smarkfen 			alg_names_string = optarg;
1074e3320f40Smarkfen 			break;
1075e3320f40Smarkfen 		case 'b':
1076e3320f40Smarkfen 			if (block_sizes_string != NULL)
1077e3320f40Smarkfen 				usage();
1078e3320f40Smarkfen 			block_sizes_string = optarg;
1079e3320f40Smarkfen 			break;
1080e3320f40Smarkfen 		case 'p':
1081e3320f40Smarkfen 			if (proto_name != NULL)
1082e3320f40Smarkfen 				usage();
1083e3320f40Smarkfen 			proto_name = optarg;
1084e3320f40Smarkfen 			break;
1085e3320f40Smarkfen 		case 'P':
1086e3320f40Smarkfen 			if (proto_number != -1)
1087e3320f40Smarkfen 				usage();
1088e3320f40Smarkfen 			proto_number = try_int(optarg,
1089e3320f40Smarkfen 			    gettext("protocol number"));
1090e3320f40Smarkfen 			break;
1091e3320f40Smarkfen 		case 'e':
1092e3320f40Smarkfen 			if (exec_mode_string != NULL)
1093e3320f40Smarkfen 				usage();
1094e3320f40Smarkfen 			exec_mode_string = optarg;
1095e3320f40Smarkfen 			if (_str_to_ipsec_exec_mode(exec_mode_string,
1096e3320f40Smarkfen 			    &proto_exec_mode) == -1) {
1097e3320f40Smarkfen 				warnx(gettext("Invalid execution mode \"%s\""),
1098e3320f40Smarkfen 				    exec_mode_string);
1099e3320f40Smarkfen 				usage();
1100e3320f40Smarkfen 			}
1101e3320f40Smarkfen 			break;
1102e3320f40Smarkfen 		case 'i':
1103e3320f40Smarkfen 			if (increment != 0)
1104e3320f40Smarkfen 				usage();
1105e3320f40Smarkfen 			increment = try_int(optarg,
1106e3320f40Smarkfen 			    gettext("key size increment"));
1107e3320f40Smarkfen 			break;
1108e3320f40Smarkfen 		case 'k':
1109e3320f40Smarkfen 			if (key_sizes_string != NULL)
1110e3320f40Smarkfen 				usage();
1111e3320f40Smarkfen 			key_sizes_string = optarg;
1112e3320f40Smarkfen 			break;
1113e3320f40Smarkfen 		case 'K':
1114e3320f40Smarkfen 			if (default_keylen != 0)
1115e3320f40Smarkfen 				usage();
1116e3320f40Smarkfen 			default_keylen = try_int(optarg,
1117e3320f40Smarkfen 			    gettext("default key size"));
1118e3320f40Smarkfen 			break;
1119e3320f40Smarkfen 		case 'm':
1120e3320f40Smarkfen 			if (mech_name != NULL)
1121e3320f40Smarkfen 				usage();
1122e3320f40Smarkfen 			mech_name = optarg;
1123e3320f40Smarkfen 			break;
1124e3320f40Smarkfen 		case 'N':
1125e3320f40Smarkfen 			if (alg_number != -1)
1126e3320f40Smarkfen 				usage();
1127e3320f40Smarkfen 			alg_number = try_int(optarg,
1128e3320f40Smarkfen 			    gettext("algorithm number"));
1129e3320f40Smarkfen 			break;
1130*628b0c67SMark Fenwick 		case 'I':
1131*628b0c67SMark Fenwick 			if (mech_params[iv_len] != 0)
1132*628b0c67SMark Fenwick 				usage();
1133*628b0c67SMark Fenwick 			mech_params[iv_len] = try_int(optarg,
1134*628b0c67SMark Fenwick 			    gettext("Initialization Vector length"));
1135*628b0c67SMark Fenwick 			break;
1136*628b0c67SMark Fenwick 		case 'M':
1137*628b0c67SMark Fenwick 			if (mech_params[mac_len] != 0)
1138*628b0c67SMark Fenwick 				usage();
1139*628b0c67SMark Fenwick 			mech_params[mac_len] = try_int(optarg,
1140*628b0c67SMark Fenwick 			    gettext("Integrity Check Vector length"));
1141*628b0c67SMark Fenwick 			break;
1142*628b0c67SMark Fenwick 		case 'S':
1143*628b0c67SMark Fenwick 			if (mech_params[salt_bytes] != 0)
1144*628b0c67SMark Fenwick 				usage();
1145*628b0c67SMark Fenwick 			mech_params[salt_bytes] = try_int(optarg,
1146*628b0c67SMark Fenwick 			    gettext("Salt length"));
1147*628b0c67SMark Fenwick 			break;
1148*628b0c67SMark Fenwick 		case 'F':
1149*628b0c67SMark Fenwick 			/*
1150*628b0c67SMark Fenwick 			 * Multiple flags can be specified, the results
1151*628b0c67SMark Fenwick 			 * are OR'd together.  Flags can be specified as
1152*628b0c67SMark Fenwick 			 * number or  a comma separated string
1153*628b0c67SMark Fenwick 			 */
1154*628b0c67SMark Fenwick 			flags = atoi(optarg);
1155*628b0c67SMark Fenwick 			if (flags) {
1156*628b0c67SMark Fenwick 				alg_flags |= flags;
1157*628b0c67SMark Fenwick 				flag_string = NULL;
1158*628b0c67SMark Fenwick 			} else {
1159*628b0c67SMark Fenwick 				flag_string = optarg;
1160*628b0c67SMark Fenwick 			}
1161*628b0c67SMark Fenwick 			break;
1162*628b0c67SMark Fenwick 		default:
1163*628b0c67SMark Fenwick 			usage();
1164e3320f40Smarkfen 		}
1165e3320f40Smarkfen 	}
1166e3320f40Smarkfen 
1167e3320f40Smarkfen 	/*
1168e3320f40Smarkfen 	 * When both protocol name (-p) and protocol number (-P) are
1169e3320f40Smarkfen 	 * specified, a new protocol is being defined.
1170e3320f40Smarkfen 	 */
1171e3320f40Smarkfen 	if (proto_number != -1 && proto_name != NULL)
1172e3320f40Smarkfen 		try_cmd(CMD_ADD_PROTO);
1173e3320f40Smarkfen 	else if (exec_mode_string != NULL)
1174e3320f40Smarkfen 		try_cmd(CMD_EXEC_MODE);
1175e3320f40Smarkfen 
1176e3320f40Smarkfen 	/*
1177e3320f40Smarkfen 	 * Process specified command.
1178e3320f40Smarkfen 	 */
1179e3320f40Smarkfen 	switch (cmd) {
1180e3320f40Smarkfen 	case CMD_ADD:
1181e3320f40Smarkfen 		new_alg();
1182e3320f40Smarkfen 		break;
1183e3320f40Smarkfen 	case CMD_ADD_PROTO:
1184e3320f40Smarkfen 		new_proto();
1185e3320f40Smarkfen 		break;
1186e3320f40Smarkfen 	case CMD_DEL:
1187e3320f40Smarkfen 		remove_alg();
1188e3320f40Smarkfen 		break;
1189e3320f40Smarkfen 	case CMD_DEL_PROTO:
1190e3320f40Smarkfen 		remove_proto();
1191e3320f40Smarkfen 		break;
1192e3320f40Smarkfen 	case CMD_EXEC_MODE:
1193e3320f40Smarkfen 		set_exec_mode();
1194e3320f40Smarkfen 		break;
1195e3320f40Smarkfen 	case CMD_LIST_KERNEL:
1196e3320f40Smarkfen 		if (synch_kernel)
1197e3320f40Smarkfen 			usage();
1198e3320f40Smarkfen 		list_kernel_algs();
1199e3320f40Smarkfen 		break;
1200e3320f40Smarkfen 	default:
1201e3320f40Smarkfen 		if (!synch_kernel)
1202e3320f40Smarkfen 			usage();
1203e3320f40Smarkfen 	}
1204e3320f40Smarkfen 
1205e3320f40Smarkfen 	if (synch_kernel) {
1206e3320f40Smarkfen 		/*
1207e3320f40Smarkfen 		 * This will only work in the global zone or
1208e3320f40Smarkfen 		 * a zone with an exclusive IP stack.
1209e3320f40Smarkfen 		 */
1210e3320f40Smarkfen 		if ((zoneid = getzoneid()) == 0) {
1211e3320f40Smarkfen 			kernel_synch();
1212e3320f40Smarkfen 		} else {
1213e3320f40Smarkfen 			if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
1214e3320f40Smarkfen 			    sizeof (flags)) < 0) {
1215e3320f40Smarkfen 				err(EXIT_FAILURE, gettext(
1216e3320f40Smarkfen 				    "Unable to determine zone IP type"));
1217e3320f40Smarkfen 			}
1218e3320f40Smarkfen 			if (flags & ZF_NET_EXCL) {
1219e3320f40Smarkfen 				kernel_synch();
1220e3320f40Smarkfen 			} else {
1221e3320f40Smarkfen 				(void) printf(gettext("Synchronization with "
1222e3320f40Smarkfen 				    "kernel not appropriate in this zone.\n"));
1223e3320f40Smarkfen 			}
1224e3320f40Smarkfen 		}
1225e3320f40Smarkfen 	}
1226e3320f40Smarkfen 
1227e3320f40Smarkfen 	return (EXIT_SUCCESS);
1228e3320f40Smarkfen }
1229