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