xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipsecalgs.c (revision 10824:c47254a96e5d)
14235Smarkfen /*
24235Smarkfen  * CDDL HEADER START
34235Smarkfen  *
44235Smarkfen  * The contents of this file are subject to the terms of the
54235Smarkfen  * Common Development and Distribution License (the "License").
64235Smarkfen  * You may not use this file except in compliance with the License.
74235Smarkfen  *
84235Smarkfen  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94235Smarkfen  * or http://www.opensolaris.org/os/licensing.
104235Smarkfen  * See the License for the specific language governing permissions
114235Smarkfen  * and limitations under the License.
124235Smarkfen  *
134235Smarkfen  * When distributing Covered Code, include this CDDL HEADER in each
144235Smarkfen  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154235Smarkfen  * If applicable, add the following below this CDDL HEADER, with the
164235Smarkfen  * fields enclosed by brackets "[]" replaced with your own identifying
174235Smarkfen  * information: Portions Copyright [yyyy] [name of copyright owner]
184235Smarkfen  *
194235Smarkfen  * CDDL HEADER END
204235Smarkfen  */
214235Smarkfen /*
22*10824SMark.Fenwick@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
234235Smarkfen  * Use is subject to license terms.
244235Smarkfen  */
254235Smarkfen 
264235Smarkfen #include <ipsec_util.h>
274235Smarkfen #include <netdb.h>
284235Smarkfen #include <locale.h>
294235Smarkfen #include <stdlib.h>
304235Smarkfen #include <stdio.h>
314235Smarkfen #include <string.h>
324235Smarkfen #include <assert.h>
334235Smarkfen #include <unistd.h>
344235Smarkfen #include <net/pfpolicy.h>
354235Smarkfen #include <strings.h>
364235Smarkfen #include <errno.h>
374235Smarkfen #include <sys/crypto/common.h>
384235Smarkfen #include <zone.h>
394235Smarkfen 
404235Smarkfen #define	SPDSOCK_DIAG_BUF_LEN	128
414235Smarkfen 
424235Smarkfen typedef enum cmd_s {
434235Smarkfen 	CMD_NONE = 0,
444235Smarkfen 	CMD_ADD,
454235Smarkfen 	CMD_ADD_PROTO,
464235Smarkfen 	CMD_DEL,
474235Smarkfen 	CMD_DEL_PROTO,
484235Smarkfen 	CMD_EXEC_MODE,
494235Smarkfen 	CMD_LIST_KERNEL
504235Smarkfen } cmd_t;
514235Smarkfen 
524235Smarkfen static const char *comma = ",";
534235Smarkfen static int adddel_flags, increment = 0, default_keylen;
544235Smarkfen static boolean_t synch_kernel;
554235Smarkfen static cmd_t cmd = CMD_NONE;
56*10824SMark.Fenwick@Sun.COM static int proto_number = -1, alg_number = -1, alg_flags = 0;
574235Smarkfen static char *proto_name, *alg_names_string, *block_sizes_string;
584235Smarkfen static char *key_sizes_string, *mech_name, *exec_mode_string;
59*10824SMark.Fenwick@Sun.COM static char *flag_string;
604235Smarkfen static ipsecalgs_exec_mode_t proto_exec_mode = LIBIPSEC_ALGS_EXEC_SYNC;
61*10824SMark.Fenwick@Sun.COM enum param_values {iv_len, mac_len, salt_bytes, max_param};
62*10824SMark.Fenwick@Sun.COM static int mech_params[max_param];
634235Smarkfen 
644235Smarkfen /*
654235Smarkfen  * Used by the algorithm walker callback to populate a SPD_UPDATEALGS
664235Smarkfen  * request.
674235Smarkfen  */
684235Smarkfen 
69*10824SMark.Fenwick@Sun.COM #define	SYNC_REQ_SIZE	4096
704235Smarkfen 
714235Smarkfen static uint64_t sync_req_buf[SYNC_REQ_SIZE];
724235Smarkfen static struct spd_attribute *sync_req_attr;
734235Smarkfen static uint_t sync_req_alg_count, sync_req_proto_count;
744235Smarkfen 
754235Smarkfen #define	EMIT(ap, tag, value) {					\
764235Smarkfen 		(ap)->spd_attr_tag = (tag);			\
774235Smarkfen 		(ap)->spd_attr_value = (value);			\
784235Smarkfen 		(ap)++;						\
794235Smarkfen 		if ((char *)(ap) + sizeof (*ap) -		\
804235Smarkfen 		    (char *)sync_req_buf > SYNC_REQ_SIZE)	\
814235Smarkfen 			bail_nomem();				\
824235Smarkfen 	}
834235Smarkfen 
844235Smarkfen static void dump_alg(struct ipsecalgent *);
854235Smarkfen static void algs_walker(void (*)(struct ipsecalgent *), void (*)(uint_t));
864235Smarkfen 
87*10824SMark.Fenwick@Sun.COM static int
parse_flag(char * flag_str,uint_t flag)88*10824SMark.Fenwick@Sun.COM parse_flag(char *flag_str, uint_t flag)
89*10824SMark.Fenwick@Sun.COM {
90*10824SMark.Fenwick@Sun.COM 	static struct flagtable {
91*10824SMark.Fenwick@Sun.COM 		char *label;
92*10824SMark.Fenwick@Sun.COM 		int token;
93*10824SMark.Fenwick@Sun.COM 	} table[] = {
94*10824SMark.Fenwick@Sun.COM 		{"VALID", 	ALG_FLAG_VALID},
95*10824SMark.Fenwick@Sun.COM 		{"COUNTER",	ALG_FLAG_COUNTERMODE},
96*10824SMark.Fenwick@Sun.COM 		{"COMBINED",	ALG_FLAG_COMBINED},
97*10824SMark.Fenwick@Sun.COM 		{"CCM",		ALG_FLAG_CCM},
98*10824SMark.Fenwick@Sun.COM 		{"GCM",		ALG_FLAG_GCM},
99*10824SMark.Fenwick@Sun.COM 		{NULL,		0}
100*10824SMark.Fenwick@Sun.COM 	};
101*10824SMark.Fenwick@Sun.COM 	struct flagtable *ft = table;
102*10824SMark.Fenwick@Sun.COM 
103*10824SMark.Fenwick@Sun.COM 	if (flag_str == NULL) {
104*10824SMark.Fenwick@Sun.COM 		/* Print out flag labels for each flag set. */
105*10824SMark.Fenwick@Sun.COM 		if ((ALG_FLAG_KERNELCHECKED & flag) && !(ALG_FLAG_VALID & flag))
106*10824SMark.Fenwick@Sun.COM 			(void) printf("INVALID ");
107*10824SMark.Fenwick@Sun.COM 		while (ft->token != 0) {
108*10824SMark.Fenwick@Sun.COM 			if (ft->token & flag) {
109*10824SMark.Fenwick@Sun.COM 				(void) printf("%s ", ft->label);
110*10824SMark.Fenwick@Sun.COM 			}
111*10824SMark.Fenwick@Sun.COM 			ft++;
112*10824SMark.Fenwick@Sun.COM 		}
113*10824SMark.Fenwick@Sun.COM 		return (0);
114*10824SMark.Fenwick@Sun.COM 	}
115*10824SMark.Fenwick@Sun.COM 	/* Or, lookup flag for supplied label. */
116*10824SMark.Fenwick@Sun.COM 	while (ft->label != NULL && strcmp(ft->label, flag_str) != 0)
117*10824SMark.Fenwick@Sun.COM 		ft++;
118*10824SMark.Fenwick@Sun.COM 	return (ft->token);
119*10824SMark.Fenwick@Sun.COM }
120*10824SMark.Fenwick@Sun.COM 
1214235Smarkfen static void
usage(void)1224235Smarkfen usage(void)
1234235Smarkfen {
1244235Smarkfen 	errx(EXIT_FAILURE, gettext("Usage:\tipsecalgs\n"
125*10824SMark.Fenwick@Sun.COM 	    "\tipsecalgs -l\n"
126*10824SMark.Fenwick@Sun.COM 	    "\tipsecalgs -s\n"
127*10824SMark.Fenwick@Sun.COM 	    "\tipsecalgs -a [-P protocol-number | -p protocol-name]\n"
128*10824SMark.Fenwick@Sun.COM 	    "\t\t-k keylen-list [-i inc]\n"
129*10824SMark.Fenwick@Sun.COM 	    "\t\t[-K default-keylen] -b blocklen-list\n"
130*10824SMark.Fenwick@Sun.COM 	    "\t\t-n alg-names -N alg-number -m mech-name\n"
131*10824SMark.Fenwick@Sun.COM 	    "\t\t[-M MAC length] [-S salt length] [-I IV length]\n"
132*10824SMark.Fenwick@Sun.COM 	    "\t\t[-F COMBINED,COUNTER,CCM|GCM ] [-f] [-s]\n"
133*10824SMark.Fenwick@Sun.COM 	    "\tipsecalgs -P protocol-number -p protocol-name\n"
134*10824SMark.Fenwick@Sun.COM 	    "\t\t[-e exec-mode] [-f] [-s]\n"
135*10824SMark.Fenwick@Sun.COM 	    "\tipsecalgs -r -p protocol-name -n alg-name [-s]\n"
136*10824SMark.Fenwick@Sun.COM 	    "\tipsecalgs -r -p protocol-name -N alg-number [-s]\n"
137*10824SMark.Fenwick@Sun.COM 	    "\tipsecalgs -R -P protocol-number [-s]\n"
138*10824SMark.Fenwick@Sun.COM 	    "\tipsecalgs -R -p protocol-name [-s]\n"
139*10824SMark.Fenwick@Sun.COM 	    "\tipsecalgs -e exec-mode -P protocol-number [-s]\n"
140*10824SMark.Fenwick@Sun.COM 	    "\tipsecalgs -e exec-mode -p protocol-number [-s]"));
1414235Smarkfen }
1424235Smarkfen 
1434235Smarkfen static void
bail_nomem(void)1444235Smarkfen bail_nomem(void)
1454235Smarkfen {
1464235Smarkfen 	errx(EXIT_FAILURE, gettext("Out of memory."));
1474235Smarkfen }
1484235Smarkfen 
1494235Smarkfen /*
1504235Smarkfen  * Return the number of key or block sizes in the specified array.
1514235Smarkfen  */
1524235Smarkfen static uint_t
num_sizes(int * sizes)1534235Smarkfen num_sizes(int *sizes)
1544235Smarkfen {
1554235Smarkfen 	uint_t nsizes = 0;
1564235Smarkfen 
1574235Smarkfen 	while (sizes[nsizes] != 0)
1584235Smarkfen 		nsizes++;
1594235Smarkfen 
1604235Smarkfen 	return (nsizes);
1614235Smarkfen }
1624235Smarkfen 
1634235Smarkfen /*
1644235Smarkfen  * Algorithms walker callback. Adds an algorithm to the current SPD_UPDATEALGS
1654235Smarkfen  * request.
1664235Smarkfen  */
1674235Smarkfen static void
synch_emit_alg(struct ipsecalgent * alg)1684235Smarkfen synch_emit_alg(struct ipsecalgent *alg)
1694235Smarkfen {
1704235Smarkfen 	uint_t nkey_sizes, nblock_sizes, i;
171*10824SMark.Fenwick@Sun.COM 	uint_t nparams;
1724235Smarkfen 
1734235Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_ALG_ID, alg->a_alg_num);
1744235Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_ALG_PROTO, alg->a_proto_num);
1754235Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_ALG_INCRBITS, alg->a_key_increment);
1764235Smarkfen 
1774235Smarkfen 	nkey_sizes = num_sizes(alg->a_key_sizes);
1784235Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_ALG_NKEYSIZES, nkey_sizes);
1794235Smarkfen 	for (i = 0; i < nkey_sizes; i++)
1804235Smarkfen 		EMIT(sync_req_attr, SPD_ATTR_ALG_KEYSIZE, alg->a_key_sizes[i]);
1814235Smarkfen 
1824235Smarkfen 	nblock_sizes = num_sizes(alg->a_block_sizes);
183*10824SMark.Fenwick@Sun.COM 	nparams = num_sizes(alg->a_mech_params);
1844235Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_ALG_NBLOCKSIZES, nblock_sizes);
1854235Smarkfen 	for (i = 0; i < nblock_sizes; i++) {
1864235Smarkfen 		EMIT(sync_req_attr, SPD_ATTR_ALG_BLOCKSIZE,
1874235Smarkfen 		    alg->a_block_sizes[i]);
1884235Smarkfen 	}
189*10824SMark.Fenwick@Sun.COM 	EMIT(sync_req_attr, SPD_ATTR_ALG_NPARAMS, nparams);
190*10824SMark.Fenwick@Sun.COM 	for (i = 0; i < nparams; i++) {
191*10824SMark.Fenwick@Sun.COM 		EMIT(sync_req_attr, SPD_ATTR_ALG_PARAMS,
192*10824SMark.Fenwick@Sun.COM 		    alg->a_mech_params[i]);
193*10824SMark.Fenwick@Sun.COM 	}
194*10824SMark.Fenwick@Sun.COM 	EMIT(sync_req_attr, SPD_ATTR_ALG_FLAGS, alg->a_alg_flags);
1954235Smarkfen 
1964235Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_ALG_MECHNAME, CRYPTO_MAX_MECH_NAME);
1974235Smarkfen 	(void) strncpy((char *)sync_req_attr, alg->a_mech_name,
1984235Smarkfen 	    CRYPTO_MAX_MECH_NAME);
1994235Smarkfen 	sync_req_attr = (struct spd_attribute *)((uint64_t *)sync_req_attr +
2004235Smarkfen 	    SPD_8TO64(CRYPTO_MAX_MECH_NAME));
2014235Smarkfen 
2024235Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_NEXT, 0);
2034235Smarkfen 
2044235Smarkfen 	sync_req_alg_count++;
2054235Smarkfen }
2064235Smarkfen 
2074235Smarkfen /*
2084235Smarkfen  * Protocol walker callback. Add protocol related info to the current
2094235Smarkfen  * SPD_UPDATEALGS request.
2104235Smarkfen  */
2114235Smarkfen static void
synch_emit_proto(uint_t proto_num)2124235Smarkfen synch_emit_proto(uint_t proto_num)
2134235Smarkfen {
2144235Smarkfen 	ipsecalgs_exec_mode_t exec_mode;
2154235Smarkfen 	uint32_t exec_mode_spdval;
2164235Smarkfen 
2174235Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_PROTO_ID, proto_num);
2184235Smarkfen 
2194235Smarkfen 	/* execution mode */
2204235Smarkfen 	if (ipsecproto_get_exec_mode(proto_num, &exec_mode) != 0) {
2214235Smarkfen 		errx(EXIT_FAILURE, gettext("cannot get execution mode for "
2224235Smarkfen 		    "proto %d"), proto_num);
2234235Smarkfen 	}
2244235Smarkfen 
2254235Smarkfen 	switch (exec_mode) {
2264235Smarkfen 	case LIBIPSEC_ALGS_EXEC_SYNC:
2274235Smarkfen 		exec_mode_spdval = SPD_ALG_EXEC_MODE_SYNC;
2284235Smarkfen 		break;
2294235Smarkfen 	case LIBIPSEC_ALGS_EXEC_ASYNC:
2304235Smarkfen 		exec_mode_spdval = SPD_ALG_EXEC_MODE_ASYNC;
2314235Smarkfen 		break;
2324235Smarkfen 	}
2334235Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_PROTO_EXEC_MODE, exec_mode_spdval);
2344235Smarkfen 
2354235Smarkfen 	EMIT(sync_req_attr, SPD_ATTR_NEXT, 0);
2364235Smarkfen 
2374235Smarkfen 	sync_req_proto_count++;
2384235Smarkfen }
2394235Smarkfen 
2404235Smarkfen /*
2414235Smarkfen  * Causes the kernel to be re-synched with the contents of /etc/inet/algs
2424235Smarkfen  */
2434235Smarkfen static void
kernel_synch(void)2444235Smarkfen kernel_synch(void)
2454235Smarkfen {
2464235Smarkfen 	int sfd = socket(PF_POLICY, SOCK_RAW, PF_POLICY_V1);
2474235Smarkfen 	int cnt, req_len;
2484235Smarkfen 	struct spd_msg *msg;
2494235Smarkfen 	struct spd_ext_actions *act;
2504235Smarkfen 	struct spd_attribute *attr;
2514235Smarkfen 
2524235Smarkfen 	if (sfd < 0) {
2534235Smarkfen 		err(EXIT_FAILURE, gettext("Unable to open policy socket"));
2544235Smarkfen 	}
2554235Smarkfen 
2564235Smarkfen 	/*
2574235Smarkfen 	 * Initialize the SPD message header and action. Some fields
2584235Smarkfen 	 * are set after having walked through the algorithms (number
2594235Smarkfen 	 * of algorithms, sizes, etc.)
2604235Smarkfen 	 */
2614235Smarkfen 	msg = (struct spd_msg *)sync_req_buf;
2624235Smarkfen 	(void) memset(msg, 0, sizeof (*msg));
2634235Smarkfen 	msg->spd_msg_version = PF_POLICY_V1;
2644235Smarkfen 	msg->spd_msg_type = SPD_UPDATEALGS;
2654235Smarkfen 
2664235Smarkfen 	act = (struct spd_ext_actions *)(msg + 1);
2674235Smarkfen 	act->spd_actions_exttype = SPD_EXT_ACTION;
2684235Smarkfen 	act->spd_actions_reserved = 0;
2694235Smarkfen 
2704235Smarkfen 	/*
2714235Smarkfen 	 * Walk through the algorithms defined and populate the
2724235Smarkfen 	 * request buffer.
2734235Smarkfen 	 */
2744235Smarkfen 	sync_req_alg_count = 0;
2754235Smarkfen 	sync_req_proto_count = 0;
2764235Smarkfen 	sync_req_attr = (struct spd_attribute *)(act + 1);
2774235Smarkfen 	algs_walker(synch_emit_alg, synch_emit_proto);
2784235Smarkfen 	act->spd_actions_count = sync_req_alg_count + sync_req_proto_count;
2794235Smarkfen 
2804235Smarkfen 	/*
2814235Smarkfen 	 * Replace the last SPD_ATTR_NEXT attribute by a SPD_ATTR_END.
2824235Smarkfen 	 */
2834235Smarkfen 	attr = sync_req_attr - 1;
2844235Smarkfen 	attr->spd_attr_tag = SPD_ATTR_END;
2854235Smarkfen 
2864235Smarkfen 	/*
2874235Smarkfen 	 * Now that the message is built, compute its total length and
2884235Smarkfen 	 * update the length fields that depend on this value.
2894235Smarkfen 	 */
2904235Smarkfen 	req_len = (char *)sync_req_attr - (char *)sync_req_buf;
2914235Smarkfen 	msg->spd_msg_len = SPD_8TO64(req_len);
2924235Smarkfen 	act->spd_actions_len = SPD_8TO64(req_len - sizeof (*msg));
2934235Smarkfen 
2944235Smarkfen 	/* ship the update request to spdsock */
2954235Smarkfen 	cnt = write(sfd, sync_req_buf, req_len);
2964235Smarkfen 	if (cnt != req_len) {
2974235Smarkfen 		if (cnt < 0) {
2984235Smarkfen 			err(EXIT_FAILURE, gettext("algs update write failed"));
2994235Smarkfen 		} else {
3004235Smarkfen 			errx(EXIT_FAILURE, gettext("algs update short write"));
3014235Smarkfen 		}
3024235Smarkfen 		/* err/errx call exit(). */
3034235Smarkfen 	}
3044235Smarkfen 
3054235Smarkfen 	cnt = read(sfd, sync_req_buf, req_len);
3064235Smarkfen 
3074235Smarkfen 	if (cnt == -1) {
3084235Smarkfen 		err(EXIT_FAILURE, gettext("algs update read failed"));
3094235Smarkfen 	}
3104235Smarkfen 
3114235Smarkfen 	if (cnt < sizeof (struct spd_msg)) {
3124235Smarkfen 		errx(EXIT_FAILURE, gettext(
3134235Smarkfen 		    "algs update failed while reading reply (short read)"));
3144235Smarkfen 	}
3154235Smarkfen 
3164235Smarkfen 	msg = (struct spd_msg *)sync_req_buf;
3174235Smarkfen 	if (msg->spd_msg_errno != 0) {
3184235Smarkfen 		errno = msg->spd_msg_errno;
3194235Smarkfen 		warn(gettext("algs update failed"));
3204235Smarkfen 		if (msg->spd_msg_diagnostic != 0) {
3214235Smarkfen 			warnx("%s", spdsock_diag(msg->spd_msg_diagnostic));
3224235Smarkfen 		}
3234235Smarkfen 		exit(EXIT_FAILURE);
3244235Smarkfen 	}
3254235Smarkfen 
3264235Smarkfen 	(void) close(sfd);
3274235Smarkfen }
3284235Smarkfen 
3294235Smarkfen static void
list_kernel_algs(void)3304235Smarkfen list_kernel_algs(void)
3314235Smarkfen {
3324235Smarkfen 	int sfd = socket(PF_POLICY, SOCK_RAW, PF_POLICY_V1);
3334235Smarkfen 	int cnt, retval;
3344235Smarkfen 	uint64_t reply_buf[2048];
3354235Smarkfen 	spd_ext_t *exts[SPD_EXT_MAX+1];
3364235Smarkfen 	struct spd_msg msg;
3374235Smarkfen 	struct spd_ext_actions *actp;
3384235Smarkfen 	struct spd_attribute *attr, *endattr;
3394235Smarkfen 	uint64_t *start, *end;
3404235Smarkfen 	struct ipsecalgent alg;
3414235Smarkfen 	uint_t cur_key, cur_block;
342*10824SMark.Fenwick@Sun.COM 	uint_t nkey_sizes, nblock_sizes, nparams;
3434235Smarkfen 	char diag_buf[SPDSOCK_DIAG_BUF_LEN];
3444235Smarkfen 
3454235Smarkfen 	if (sfd < 0) {
3464235Smarkfen 		err(EXIT_FAILURE, gettext("Unable to open policy socket"));
3474235Smarkfen 	}
3484235Smarkfen 
3494235Smarkfen 	(void) memset(&msg, 0, sizeof (msg));
3504235Smarkfen 	msg.spd_msg_version = PF_POLICY_V1;
3514235Smarkfen 	msg.spd_msg_type = SPD_DUMPALGS;
3524235Smarkfen 	msg.spd_msg_len = SPD_8TO64(sizeof (msg));
3534235Smarkfen 
3544235Smarkfen 	cnt = write(sfd, &msg, sizeof (msg));
3554235Smarkfen 	if (cnt != sizeof (msg)) {
3564235Smarkfen 		if (cnt < 0) {
3574235Smarkfen 			err(EXIT_FAILURE, gettext("dump algs write failed"));
3584235Smarkfen 		} else {
3594235Smarkfen 			errx(EXIT_FAILURE, gettext("dump algs short write"));
3604235Smarkfen 		}
3614235Smarkfen 		/* err/errx call exit(). */
3624235Smarkfen 	}
3634235Smarkfen 
3644235Smarkfen 	cnt = read(sfd, reply_buf, sizeof (reply_buf));
3654235Smarkfen 
3664235Smarkfen 	if (cnt == -1) {
3674235Smarkfen 		err(EXIT_FAILURE, gettext("dump algs read failed"));
3684235Smarkfen 	}
3694235Smarkfen 
3704235Smarkfen 	if (cnt < sizeof (struct spd_msg)) {
3714235Smarkfen 		errx(EXIT_FAILURE, gettext(
3724235Smarkfen 		    "dump algs failed while reading reply (short read)"));
3734235Smarkfen 	}
3744235Smarkfen 
3754235Smarkfen 	(void) close(sfd);
3764235Smarkfen 
3774235Smarkfen 	retval = spdsock_get_ext(exts, (spd_msg_t *)reply_buf, SPD_8TO64(cnt),
3784235Smarkfen 	    diag_buf, SPDSOCK_DIAG_BUF_LEN);
3794235Smarkfen 
3804235Smarkfen 	if (retval == KGE_LEN && exts[0]->spd_ext_len == 0) {
3814235Smarkfen 		/*
3824235Smarkfen 		 * No algorithms are defined in the kernel, which caused
3834235Smarkfen 		 * the extension length to be zero, and spdsock_get_ext()
3844235Smarkfen 		 * to fail with a KGE_LEN error. This is not an error
3854235Smarkfen 		 * condition, so we return nicely.
3864235Smarkfen 		 */
3874235Smarkfen 		return;
3884235Smarkfen 	} else if (retval != 0) {
3894235Smarkfen 		if (strlen(diag_buf) != 0)
3904235Smarkfen 			warnx("%s", diag_buf);
3914235Smarkfen 		errx(EXIT_FAILURE, gettext("invalid extension "
3924235Smarkfen 		    "in dump algs reply (%d)"), retval);
3934235Smarkfen 	}
3944235Smarkfen 
3954235Smarkfen 	if (exts[SPD_EXT_ACTION] == NULL) {
3964235Smarkfen 		errx(EXIT_FAILURE,
3974235Smarkfen 		    gettext("action missing in dump algs reply"));
3984235Smarkfen 	}
3994235Smarkfen 
4004235Smarkfen 	actp = (struct spd_ext_actions *)exts[SPD_EXT_ACTION];
4014235Smarkfen 	start = (uint64_t *)actp;
4024235Smarkfen 	end = (start + actp->spd_actions_len);
4034235Smarkfen 	endattr = (struct spd_attribute *)end;
4044235Smarkfen 	attr = (struct spd_attribute *)&actp[1];
4054235Smarkfen 
4064235Smarkfen 	bzero(&alg, sizeof (alg));
4074235Smarkfen 	nkey_sizes = nblock_sizes = 0;
4084235Smarkfen 
4094235Smarkfen 	(void) printf("Kernel list of algorithms:\n\n");
4104235Smarkfen 
4114235Smarkfen 	while (attr < endattr) {
4124235Smarkfen 		switch (attr->spd_attr_tag) {
4134235Smarkfen 		case SPD_ATTR_NOP:
4144235Smarkfen 		case SPD_ATTR_EMPTY:
4154235Smarkfen 			break;
4164235Smarkfen 		case SPD_ATTR_END:
4174235Smarkfen 			attr = endattr;
4184235Smarkfen 			/* FALLTHRU */
4194235Smarkfen 		case SPD_ATTR_NEXT:
4204235Smarkfen 			/*
4214235Smarkfen 			 * Note that if the message received from the spdsock
4224235Smarkfen 			 * has a premature SPD_ATTR_END or SPD_ATTR_NEXT, this
4234235Smarkfen 			 * could cause the current algorithm to be only
4244235Smarkfen 			 * partially initialized.
4254235Smarkfen 			 */
426*10824SMark.Fenwick@Sun.COM 			alg.a_alg_flags |= ALG_FLAG_KERNELCHECKED;
4274235Smarkfen 			dump_alg(&alg);
4284235Smarkfen 			free(alg.a_key_sizes);
4294235Smarkfen 			free(alg.a_block_sizes);
4304235Smarkfen 			free(alg.a_mech_name);
431*10824SMark.Fenwick@Sun.COM 			free(alg.a_mech_params);
4324235Smarkfen 			bzero(&alg, sizeof (alg));
4334235Smarkfen 			nkey_sizes = nblock_sizes = 0;
4344235Smarkfen 			break;
4354235Smarkfen 
4364235Smarkfen 		case SPD_ATTR_ALG_ID:
4374235Smarkfen 			alg.a_alg_num = attr->spd_attr_value;
4384235Smarkfen 			break;
4394235Smarkfen 
4404235Smarkfen 		case SPD_ATTR_ALG_PROTO:
4414235Smarkfen 			alg.a_proto_num = attr->spd_attr_value;
4424235Smarkfen 			break;
4434235Smarkfen 
4444235Smarkfen 		case SPD_ATTR_ALG_INCRBITS:
4454235Smarkfen 			alg.a_key_increment = attr->spd_attr_value;
4464235Smarkfen 			break;
4474235Smarkfen 
4484235Smarkfen 		case SPD_ATTR_ALG_NKEYSIZES:
4494235Smarkfen 			nkey_sizes = attr->spd_attr_value;
4504235Smarkfen 			if (alg.a_key_sizes != NULL) {
4514235Smarkfen 				errx(EXIT_FAILURE, gettext("duplicate number "
4524235Smarkfen 				    "of keys in dump algs reply"));
4534235Smarkfen 			}
4544235Smarkfen 			alg.a_key_sizes = calloc(nkey_sizes + 1, sizeof (int));
4554235Smarkfen 			if (alg.a_key_sizes == NULL)
4564235Smarkfen 				bail_nomem();
4574235Smarkfen 			cur_key = 0;
4584235Smarkfen 			break;
4594235Smarkfen 
4604235Smarkfen 		case SPD_ATTR_ALG_KEYSIZE:
4614235Smarkfen 			if (cur_key >= nkey_sizes) {
4624235Smarkfen 				errx(EXIT_FAILURE, gettext("too many key sizes"
4634235Smarkfen 				    " in dump algs reply"));
4644235Smarkfen 			}
4654235Smarkfen 			alg.a_key_sizes[cur_key++] = attr->spd_attr_value;
4664235Smarkfen 			break;
4674235Smarkfen 
4684235Smarkfen 		case SPD_ATTR_ALG_NBLOCKSIZES:
4694235Smarkfen 			nblock_sizes = attr->spd_attr_value;
4704235Smarkfen 			if (alg.a_block_sizes != NULL) {
4714235Smarkfen 				errx(EXIT_FAILURE, gettext("duplicate number "
4724235Smarkfen 				    "of blocks in dump algs reply"));
4734235Smarkfen 			}
4744235Smarkfen 			alg.a_block_sizes = calloc(nblock_sizes + 1,
4754235Smarkfen 			    sizeof (int));
4764235Smarkfen 			if (alg.a_block_sizes == NULL)
4774235Smarkfen 				bail_nomem();
4784235Smarkfen 			cur_block = 0;
4794235Smarkfen 			break;
4804235Smarkfen 
4814235Smarkfen 		case SPD_ATTR_ALG_BLOCKSIZE:
4824235Smarkfen 			if (cur_block >= nblock_sizes) {
4834235Smarkfen 				errx(EXIT_FAILURE, gettext("too many block "
4844235Smarkfen 				    "sizes in dump algs reply"));
4854235Smarkfen 			}
4864235Smarkfen 			alg.a_block_sizes[cur_block++] = attr->spd_attr_value;
4874235Smarkfen 			break;
4884235Smarkfen 
489*10824SMark.Fenwick@Sun.COM 		case SPD_ATTR_ALG_NPARAMS:
490*10824SMark.Fenwick@Sun.COM 			nparams = attr->spd_attr_value;
491*10824SMark.Fenwick@Sun.COM 			if (alg.a_mech_params != NULL) {
492*10824SMark.Fenwick@Sun.COM 				errx(EXIT_FAILURE, gettext("duplicate number "
493*10824SMark.Fenwick@Sun.COM 				    "of params in dump algs reply"));
494*10824SMark.Fenwick@Sun.COM 			}
495*10824SMark.Fenwick@Sun.COM 			alg.a_mech_params = calloc(nparams + 1,
496*10824SMark.Fenwick@Sun.COM 			    sizeof (int));
497*10824SMark.Fenwick@Sun.COM 			if (alg.a_mech_params == NULL)
498*10824SMark.Fenwick@Sun.COM 				bail_nomem();
499*10824SMark.Fenwick@Sun.COM 			cur_block = 0;
500*10824SMark.Fenwick@Sun.COM 			break;
501*10824SMark.Fenwick@Sun.COM 
502*10824SMark.Fenwick@Sun.COM 		case SPD_ATTR_ALG_PARAMS:
503*10824SMark.Fenwick@Sun.COM 			if (cur_block >= nparams) {
504*10824SMark.Fenwick@Sun.COM 				errx(EXIT_FAILURE, gettext("too many params "
505*10824SMark.Fenwick@Sun.COM 				    "in dump algs reply"));
506*10824SMark.Fenwick@Sun.COM 			}
507*10824SMark.Fenwick@Sun.COM 			alg.a_mech_params[cur_block++] = attr->spd_attr_value;
508*10824SMark.Fenwick@Sun.COM 			break;
509*10824SMark.Fenwick@Sun.COM 
510*10824SMark.Fenwick@Sun.COM 		case SPD_ATTR_ALG_FLAGS:
511*10824SMark.Fenwick@Sun.COM 			alg.a_alg_flags = attr->spd_attr_value;
512*10824SMark.Fenwick@Sun.COM 			break;
513*10824SMark.Fenwick@Sun.COM 
5144235Smarkfen 		case SPD_ATTR_ALG_MECHNAME: {
5154235Smarkfen 			char *mech_name;
5164235Smarkfen 
5174235Smarkfen 			if (alg.a_mech_name != NULL) {
5184235Smarkfen 				errx(EXIT_FAILURE, gettext(
5194235Smarkfen 				    "duplicate mech name in dump algs reply"));
5204235Smarkfen 			}
5214235Smarkfen 
5224235Smarkfen 			alg.a_mech_name = malloc(attr->spd_attr_value);
5234235Smarkfen 			if (alg.a_mech_name == NULL)
5244235Smarkfen 				bail_nomem();
5254235Smarkfen 
5264235Smarkfen 			mech_name = (char *)(attr + 1);
5274235Smarkfen 			bcopy(mech_name, alg.a_mech_name, attr->spd_attr_value);
5284235Smarkfen 			attr = (struct spd_attribute *)((uint64_t *)attr +
5294235Smarkfen 			    SPD_8TO64(attr->spd_attr_value));
5304235Smarkfen 			break;
5314235Smarkfen 		}
5324235Smarkfen 		}
5334235Smarkfen 		attr++;
5344235Smarkfen 	}
5354235Smarkfen 
5364235Smarkfen }
5374235Smarkfen 
5384235Smarkfen 
5394235Smarkfen static int *
parse_intlist(char * args,int * num_args)5404235Smarkfen parse_intlist(char *args, int *num_args)
5414235Smarkfen {
5424235Smarkfen 	int *rc = NULL;
5434235Smarkfen 	char *holder = NULL;
5444235Smarkfen 
5454235Smarkfen 	while ((holder = strtok((holder == NULL) ? args : NULL, comma)) !=
5464235Smarkfen 	    NULL) {
5474235Smarkfen 		(*num_args)++;
5484235Smarkfen 		rc = realloc(rc, ((*num_args) + 1) * sizeof (int));
5494235Smarkfen 		if (rc == NULL)
5504235Smarkfen 			bail_nomem();
5514235Smarkfen 		rc[(*num_args) - 1] = atoi(holder);
5524235Smarkfen 		if (rc[(*num_args) - 1] == 0)
5534235Smarkfen 			usage();	/* Malformed integer list! */
5544235Smarkfen 		rc[*num_args] = 0;
5554235Smarkfen 	}
5564235Smarkfen 
5574235Smarkfen 	return (rc);
5584235Smarkfen }
5594235Smarkfen 
5604235Smarkfen static void
new_alg(void)5614235Smarkfen new_alg(void)
5624235Smarkfen {
5634235Smarkfen 	struct ipsecalgent newbie;
5644235Smarkfen 	int num_names = 0, num_block_sizes = 0, num_key_sizes = 0;
5654235Smarkfen 	int i, rc;
5664235Smarkfen 	char *holder = NULL;
5674235Smarkfen 
5684235Smarkfen 	/* Parameter reality check... */
5694235Smarkfen 	if (proto_number == -1) {
5704235Smarkfen 		if (proto_name == NULL) {
5714235Smarkfen 			warnx(gettext("Missing protocol number."));
5724235Smarkfen 			usage();
5734235Smarkfen 		}
5744235Smarkfen 		proto_number = getipsecprotobyname(proto_name);
5754235Smarkfen 		if (proto_number == -1) {
5764235Smarkfen 			warnx(gettext("Unknown protocol."));
5774235Smarkfen 			usage();
5784235Smarkfen 		}
5794235Smarkfen 	}
5804235Smarkfen 	if (alg_number == -1) {
5814235Smarkfen 		warnx(gettext("Missing algorithm number."));
5824235Smarkfen 		usage();
5834235Smarkfen 	}
5844235Smarkfen 	if (key_sizes_string == NULL) {
5854235Smarkfen 		warnx(gettext("Missing key size(s)."));
5864235Smarkfen 		usage();
5874235Smarkfen 	}
5884235Smarkfen 	if (alg_names_string == NULL) {
5894235Smarkfen 		warnx(gettext("Missing algorithm name(s)."));
5904235Smarkfen 		usage();
5914235Smarkfen 	}
5924235Smarkfen 	if (block_sizes_string == NULL) {
5934235Smarkfen 		warnx(gettext("Missing block/MAC lengths"));
5944235Smarkfen 		usage();
5954235Smarkfen 	}
5964235Smarkfen 	if (mech_name == NULL) {
5974235Smarkfen 		warnx(gettext("Missing mechanism name."));
5984235Smarkfen 		usage();
5994235Smarkfen 	}
6004235Smarkfen 	newbie.a_proto_num = proto_number;
6014235Smarkfen 	newbie.a_alg_num = alg_number;
6024235Smarkfen 	newbie.a_key_increment = increment;
6034235Smarkfen 	newbie.a_mech_name = mech_name;
604*10824SMark.Fenwick@Sun.COM 	newbie.a_alg_flags = alg_flags;
6054235Smarkfen 
606*10824SMark.Fenwick@Sun.COM 	/*
607*10824SMark.Fenwick@Sun.COM 	 * The ALG_FLAG_VALID is somewhat irrelevant as an input from the
608*10824SMark.Fenwick@Sun.COM 	 * user, the kernel will decide if the algorithm description is
609*10824SMark.Fenwick@Sun.COM 	 * valid or not and set the ALG_FLAG_VALID when the user dumps
610*10824SMark.Fenwick@Sun.COM 	 * the kernel tables. To avoid confusion when the user dumps the
611*10824SMark.Fenwick@Sun.COM 	 * contents off the ipsecalgs file, we set the ALG_FLAG_VALID here.
612*10824SMark.Fenwick@Sun.COM 	 */
613*10824SMark.Fenwick@Sun.COM 	newbie.a_alg_flags |= ALG_FLAG_VALID;
614*10824SMark.Fenwick@Sun.COM 	while ((holder = strtok((holder == NULL) ? flag_string : NULL,
615*10824SMark.Fenwick@Sun.COM 	    comma)) != NULL) {
616*10824SMark.Fenwick@Sun.COM 		alg_flags = parse_flag(holder, 0);
617*10824SMark.Fenwick@Sun.COM 		if (!alg_flags) {
618*10824SMark.Fenwick@Sun.COM 			warnx(gettext("Invalid flag: %s\n"), holder);
619*10824SMark.Fenwick@Sun.COM 			usage();
620*10824SMark.Fenwick@Sun.COM 		}
621*10824SMark.Fenwick@Sun.COM 		newbie.a_alg_flags |= alg_flags;
622*10824SMark.Fenwick@Sun.COM 	}
6234235Smarkfen 	newbie.a_names = NULL;
6244235Smarkfen 	while ((holder = strtok((holder == NULL) ? alg_names_string : NULL,
625*10824SMark.Fenwick@Sun.COM 	    comma)) != NULL) {
6264235Smarkfen 		newbie.a_names = realloc(newbie.a_names,
6274235Smarkfen 		    sizeof (char *) * ((++num_names) + 1));
6284235Smarkfen 		if (newbie.a_names == NULL)
6294235Smarkfen 			bail_nomem();
6304235Smarkfen 		newbie.a_names[num_names - 1] = holder;
6314235Smarkfen 		newbie.a_names[num_names] = NULL;
6324235Smarkfen 	}
6334235Smarkfen 
6344235Smarkfen 	/* Extract block sizes. */
6354235Smarkfen 	newbie.a_block_sizes = parse_intlist(block_sizes_string,
6364235Smarkfen 	    &num_block_sizes);
637*10824SMark.Fenwick@Sun.COM 	newbie.a_mech_params = &mech_params[0];
6384235Smarkfen 
6394235Smarkfen 	/* Extract key sizes. */
6404235Smarkfen 	if ((holder = strchr(key_sizes_string, '-')) != NULL) {
6414235Smarkfen 		/* key sizes by range, key size increment required */
6424235Smarkfen 		if (newbie.a_key_increment == 0) {
6434235Smarkfen 			warnx(gettext("Missing key increment"));
6444235Smarkfen 			usage();
6454235Smarkfen 		}
6464235Smarkfen 		newbie.a_key_sizes = calloc(sizeof (int),
6474235Smarkfen 		    LIBIPSEC_ALGS_KEY_NUM_VAL);
6484235Smarkfen 		if (newbie.a_key_sizes == NULL)
6494235Smarkfen 			bail_nomem();
6504235Smarkfen 		*holder = '\0';
6514235Smarkfen 		holder++;
6524235Smarkfen 		/*
6534235Smarkfen 		 * At this point, holder points to high, key_sizes_string
6544235Smarkfen 		 * points to low.
6554235Smarkfen 		 */
6564235Smarkfen 		newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] =
6574235Smarkfen 		    atoi(key_sizes_string);
6584235Smarkfen 		if (newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] == 0) {
6594235Smarkfen 			warnx(gettext("Invalid lower key size range"));
6604235Smarkfen 			usage();
6614235Smarkfen 		}
6624235Smarkfen 		newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] = atoi(holder);
6634235Smarkfen 		if (newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] == 0) {
6644235Smarkfen 			warnx(gettext("Invalid higher key size range"));
6654235Smarkfen 			usage();
6664235Smarkfen 		}
6674235Smarkfen 
6684235Smarkfen 		/* sanity check key range consistency */
6694235Smarkfen 		if (newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] >=
6704235Smarkfen 		    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX]) {
6714235Smarkfen 			warnx(gettext("Invalid key size range (min >= max)"));
6724235Smarkfen 			usage();
6734235Smarkfen 		}
6744235Smarkfen 
6754235Smarkfen 		/* check key increment vs key range */
6764235Smarkfen 		if (((newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] -
6774235Smarkfen 		    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX]) %
6784235Smarkfen 		    newbie.a_key_increment) != 0) {
6794235Smarkfen 			warnx(gettext("Key size increment"
6804235Smarkfen 			    " not consistent with key size range"));
6814235Smarkfen 			usage();
6824235Smarkfen 		}
6834235Smarkfen 
6844235Smarkfen 		/* default key size */
6854235Smarkfen 		if (default_keylen != 0) {
6864235Smarkfen 			/* check specified default key size */
6874235Smarkfen 			if (default_keylen <
6884235Smarkfen 			    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] ||
6894235Smarkfen 			    default_keylen >
6904235Smarkfen 			    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] ||
6914235Smarkfen 			    ((default_keylen -
6924235Smarkfen 			    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX]) %
6934235Smarkfen 			    newbie.a_key_increment) != 0) {
6944235Smarkfen 				warnx(gettext("Default key size not consistent"
6954235Smarkfen 				    " with key size range"));
6964235Smarkfen 				usage();
6974235Smarkfen 			}
6984235Smarkfen 			newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_DEF_IDX] =
6994235Smarkfen 			    default_keylen;
7004235Smarkfen 		} else {
7014235Smarkfen 			/* min key size in range if not specified */
7024235Smarkfen 			newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_DEF_IDX] =
703*10824SMark.Fenwick@Sun.COM 			    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX];
7044235Smarkfen 		}
7054235Smarkfen 	} else {
7064235Smarkfen 		/* key sizes by enumeration */
7074235Smarkfen 		if (newbie.a_key_increment != 0) {
7084235Smarkfen 			warnx(gettext("Key increment must "
7094235Smarkfen 			    "not be specified with key sizes enumeration"));
7104235Smarkfen 			usage();
7114235Smarkfen 		}
7124235Smarkfen 		newbie.a_key_sizes = parse_intlist(key_sizes_string,
7134235Smarkfen 		    &num_key_sizes);
7144235Smarkfen 
7154235Smarkfen 		/* default key size */
7164235Smarkfen 		if (default_keylen != 0 && default_keylen !=
7174235Smarkfen 		    newbie.a_key_sizes[0]) {
7184235Smarkfen 			/*
7194235Smarkfen 			 * The default key size is not at the front of the
7204235Smarkfen 			 * list. Swap it with the first element of the list.
7214235Smarkfen 			 */
7224235Smarkfen 			for (i = 1; i < num_key_sizes; i++) {
7234235Smarkfen 				if (newbie.a_key_sizes[i] == default_keylen)
7244235Smarkfen 					break;
7254235Smarkfen 				if (i >= num_key_sizes) {
7264235Smarkfen 					warnx(gettext("Default key size not "
7274235Smarkfen 					    "in list of key sizes"));
7284235Smarkfen 					usage();
7294235Smarkfen 				}
7304235Smarkfen 				newbie.a_key_sizes[i] = newbie.a_key_sizes[0];
7314235Smarkfen 				newbie.a_key_sizes[0] = default_keylen;
7324235Smarkfen 			}
7334235Smarkfen 		}
7344235Smarkfen 	}
7354235Smarkfen 
7364235Smarkfen 	/* Call things! */
7374235Smarkfen 	if ((rc = addipsecalg(&newbie, adddel_flags)) != 0) {
7384235Smarkfen 		errx(EXIT_FAILURE, gettext("addipsecalg() call failed: "
7394235Smarkfen 		    "%s"), ipsecalgs_diag(rc));
7404235Smarkfen 	}
7414235Smarkfen 
7424235Smarkfen 	free(newbie.a_names);
7434235Smarkfen 	free(newbie.a_block_sizes);
7444235Smarkfen 	free(newbie.a_key_sizes);
7454235Smarkfen }
7464235Smarkfen 
7474235Smarkfen static void
new_proto(void)7484235Smarkfen new_proto(void)
7494235Smarkfen {
7504235Smarkfen 	int rc;
7514235Smarkfen 
7524235Smarkfen 	if ((rc = addipsecproto(proto_name, proto_number, proto_exec_mode,
7534235Smarkfen 	    adddel_flags))
7544235Smarkfen 	    != 0) {
7554235Smarkfen 		errx(EXIT_FAILURE, gettext(
7564235Smarkfen 		    "Cannot add protocol %1$d \"%2$s\": %3$s"), proto_number,
7574235Smarkfen 		    proto_name, ipsecalgs_diag(rc));
7584235Smarkfen 	}
7594235Smarkfen }
7604235Smarkfen 
7614235Smarkfen static void
remove_alg(void)7624235Smarkfen remove_alg(void)
7634235Smarkfen {
7644235Smarkfen 	int rc;
7654235Smarkfen 
7664235Smarkfen 	if (proto_number == -1) {
7674235Smarkfen 		if (proto_name == NULL) {
7684235Smarkfen 			warnx(gettext("Missing protocol number."));
7694235Smarkfen 			usage();
7704235Smarkfen 		}
7714235Smarkfen 		proto_number = getipsecprotobyname(proto_name);
7724235Smarkfen 		if (proto_number == -1) {
7734235Smarkfen 			errx(EXIT_FAILURE, gettext(
7744235Smarkfen 			    "Unknown protocol \"%s\"."), proto_name);
7754235Smarkfen 		}
7764235Smarkfen 	}
7774235Smarkfen 
7784235Smarkfen 	if (alg_number == -1) {
7794235Smarkfen 		if (alg_names_string == NULL) {
7804235Smarkfen 			errx(EXIT_FAILURE, gettext("Missing algorithm ID."));
7814235Smarkfen 		}
7824235Smarkfen 		if (strchr(alg_names_string, ',') != NULL) {
7834235Smarkfen 			errx(EXIT_FAILURE, gettext(
784*10824SMark.Fenwick@Sun.COM 			    "Specify a single algorithm name for removal, "
785*10824SMark.Fenwick@Sun.COM 			    "not a list."));
7864235Smarkfen 		}
7874235Smarkfen 		if ((rc = delipsecalgbyname(alg_names_string, proto_number))
7884235Smarkfen 		    != 0) {
7894235Smarkfen 			errx(EXIT_FAILURE, gettext(
7904235Smarkfen 			    "Could not remove algorithm %1$s: %2$s"),
7914235Smarkfen 			    alg_names_string, ipsecalgs_diag(rc));
7924235Smarkfen 		}
7934235Smarkfen 	} else {
7944235Smarkfen 		if ((rc = delipsecalgbynum(alg_number, proto_number)) != 0) {
7954235Smarkfen 			errx(EXIT_FAILURE, gettext(
7964235Smarkfen 			    "Could not remove algorithm %1$d: %2$s"),
7974235Smarkfen 			    alg_number, ipsecalgs_diag(rc));
7984235Smarkfen 		}
7994235Smarkfen 	}
8004235Smarkfen }
8014235Smarkfen 
8024235Smarkfen static void
remove_proto(void)8034235Smarkfen remove_proto(void)
8044235Smarkfen {
8054235Smarkfen 	int rc;
8064235Smarkfen 
8074235Smarkfen 	if (proto_number == -1) {
8084235Smarkfen 		if (proto_name == NULL) {
8094235Smarkfen 			warnx(gettext("Please specify protocol to remove."));
8104235Smarkfen 			usage();
8114235Smarkfen 		}
8124235Smarkfen 		if ((rc = delipsecprotobyname(proto_name)) != 0) {
8134235Smarkfen 			errx(EXIT_FAILURE, gettext(
8144235Smarkfen 			    "Could not remove protocol %1$s: %2$s"),
8154235Smarkfen 			    proto_name, ipsecalgs_diag(rc));
8164235Smarkfen 		}
8174235Smarkfen 	} else {
8184235Smarkfen 		if ((rc = delipsecprotobynum(proto_number)) != 0) {
8194235Smarkfen 			errx(EXIT_FAILURE, gettext(
8204235Smarkfen 			    "Could not remove protocol %1$d: %2$s"),
8214235Smarkfen 			    proto_number, ipsecalgs_diag(rc));
8224235Smarkfen 		}
8234235Smarkfen 	}
8244235Smarkfen }
8254235Smarkfen 
8264235Smarkfen static void
set_exec_mode(void)8274235Smarkfen set_exec_mode(void)
8284235Smarkfen {
8294235Smarkfen 	int rc;
8304235Smarkfen 
8314235Smarkfen 	if (proto_number == -1) {
8324235Smarkfen 		if (proto_name == NULL) {
8334235Smarkfen 			warnx(gettext(
8344235Smarkfen 			    "Please specify protocol name or number."));
8354235Smarkfen 			usage();
8364235Smarkfen 		}
8374235Smarkfen 		proto_number = getipsecprotobyname(proto_name);
8384235Smarkfen 		if (proto_number == -1) {
8394235Smarkfen 			errx(EXIT_FAILURE, gettext("Unknown protocol %s"),
8404235Smarkfen 			    proto_name);
8414235Smarkfen 		}
8424235Smarkfen 	}
8434235Smarkfen 
8444235Smarkfen 	if ((rc = ipsecproto_set_exec_mode(proto_number, proto_exec_mode))
8454235Smarkfen 	    != 0) {
8464235Smarkfen 		errx(EXIT_FAILURE, gettext("Cannot set execution mode: %s"),
8474235Smarkfen 		    ipsecalgs_diag(rc));
8484235Smarkfen 	}
8494235Smarkfen }
8504235Smarkfen 
8514235Smarkfen /*
8524235Smarkfen  * Print a description of an algorithm to standard output.
8534235Smarkfen  */
8544235Smarkfen static void
dump_alg(struct ipsecalgent * alg)8554235Smarkfen dump_alg(struct ipsecalgent *alg)
8564235Smarkfen {
8574235Smarkfen 	int *ifloater;
8584235Smarkfen 	char **floater;
8594235Smarkfen 
8604235Smarkfen 	/* protocol number */
8614235Smarkfen 	(void) printf(gettext("\tProtocol number: %d\n"), alg->a_proto_num);
8624235Smarkfen 
8634235Smarkfen 	/* algorithm number */
8644235Smarkfen 	(void) printf(gettext("\tAlgorithm number: %d\n"), alg->a_alg_num);
8654235Smarkfen 
8664235Smarkfen 	/* algorithm name(s) */
8674235Smarkfen 	if (alg->a_names != NULL) {
8684235Smarkfen 		(void) printf(gettext("\tAlgorithm names: "));
8694235Smarkfen 		floater = alg->a_names;
8704235Smarkfen 		assert(floater != NULL && *floater != NULL);
8714235Smarkfen 		do {
8724235Smarkfen 			/* Assume at least one string. */
8734235Smarkfen 			(void) printf("%s", *floater);
8744235Smarkfen 			if (*(++floater) != NULL)
8754235Smarkfen 				(void) putchar(',');
8764235Smarkfen 		} while (*floater != NULL);
8774235Smarkfen 		(void) putchar('\n');
8784235Smarkfen 	}
8794235Smarkfen 
8804235Smarkfen 	/* mechanism name */
8814235Smarkfen 	(void) printf(gettext("\tMechanism Name: %s\n"), alg->a_mech_name);
8824235Smarkfen 
8834235Smarkfen 	/* block/MAC sizes */
8844235Smarkfen 	(void) printf(gettext("\tBlock sizes or MAC sizes: "));
8854235Smarkfen 	ifloater = alg->a_block_sizes;
8864235Smarkfen 	(void) list_ints(stdout, ifloater);
8874235Smarkfen 	(void) putchar('\n');
8884235Smarkfen 
8894235Smarkfen 	/* key sizes */
8904235Smarkfen 	(void) printf(gettext("\tKey sizes: "));
8914235Smarkfen 	if (alg->a_key_increment != 0)
8924235Smarkfen 		/* key specified by range */
8934235Smarkfen 		(void) printf(gettext(
8944235Smarkfen 		    "%1$d-%2$d, increment %3$d, default %4$d"),
8954235Smarkfen 		    alg->a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX],
8964235Smarkfen 		    alg->a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX],
8974235Smarkfen 		    alg->a_key_increment,
8984235Smarkfen 		    alg->a_key_sizes[LIBIPSEC_ALGS_KEY_DEF_IDX]);
8994235Smarkfen 	else
9004235Smarkfen 		/* key specified by enumeration */
9014235Smarkfen 		(void) list_ints(stdout, alg->a_key_sizes);
9024235Smarkfen 	(void) putchar('\n');
9034235Smarkfen 
904*10824SMark.Fenwick@Sun.COM 	/* Alg parameters */
905*10824SMark.Fenwick@Sun.COM 	(void) printf(gettext("\tAlgorithm parameters: "));
906*10824SMark.Fenwick@Sun.COM 	ifloater = alg->a_mech_params;
907*10824SMark.Fenwick@Sun.COM 	(void) list_ints(stdout, ifloater);
908*10824SMark.Fenwick@Sun.COM 	(void) putchar('\n');
909*10824SMark.Fenwick@Sun.COM 
910*10824SMark.Fenwick@Sun.COM 	/* Alg flags */
911*10824SMark.Fenwick@Sun.COM 	(void) printf(gettext("\tAlgorithm flags: "));
912*10824SMark.Fenwick@Sun.COM 	(void) parse_flag(NULL, alg->a_alg_flags);
913*10824SMark.Fenwick@Sun.COM 
914*10824SMark.Fenwick@Sun.COM 	(void) putchar('\n');
9154235Smarkfen 	(void) putchar('\n');
9164235Smarkfen }
9174235Smarkfen 
9184235Smarkfen /*
9194235Smarkfen  * Print the description of a protocol.
9204235Smarkfen  */
9214235Smarkfen static void
dump_proto(uint_t proto_id)9224235Smarkfen dump_proto(uint_t proto_id)
9234235Smarkfen {
9244235Smarkfen 	char *proto_name;
9254235Smarkfen 	ipsecalgs_exec_mode_t exec_mode;
9264235Smarkfen 
9274235Smarkfen 	/* protocol name and number */
9284235Smarkfen 	proto_name = getipsecprotobynum(proto_id);
9294235Smarkfen 	(void) printf(gettext("Protocol %1$d/%2$s "),
9304235Smarkfen 	    proto_id, proto_name != NULL ? proto_name : gettext("<unknown>"));
9314235Smarkfen 
9324235Smarkfen 	/* execution mode */
9334235Smarkfen 	(void) printf("(%s", gettext("execution mode: "));
9344235Smarkfen 
9354235Smarkfen 	if (ipsecproto_get_exec_mode(proto_id, &exec_mode) != 0) {
9364235Smarkfen 		(void) printf(gettext("<unknown>"));
9374235Smarkfen 	} else {
9384235Smarkfen 		switch (exec_mode) {
9394235Smarkfen 		case LIBIPSEC_ALGS_EXEC_SYNC:
9404235Smarkfen 			(void) printf("sync");
9414235Smarkfen 			break;
9424235Smarkfen 		case LIBIPSEC_ALGS_EXEC_ASYNC:
9434235Smarkfen 			(void) printf("async");
9444235Smarkfen 			break;
9454235Smarkfen 		}
9464235Smarkfen 	}
9474235Smarkfen 
9484235Smarkfen 	(void) printf(")\n\n");
9494235Smarkfen 
9504235Smarkfen 	free(proto_name);
9514235Smarkfen }
9524235Smarkfen 
9534235Smarkfen 
9544235Smarkfen /*
9554235Smarkfen  * Algorithm walker table. Call proto_action() for each protocol,
9564235Smarkfen  * and alg_action() for each algorithm.
9574235Smarkfen  */
9584235Smarkfen static void
algs_walker(void (* alg_action)(struct ipsecalgent *),void (* proto_action)(uint_t))9594235Smarkfen algs_walker(void (*alg_action)(struct ipsecalgent *),
9604235Smarkfen     void (*proto_action)(uint_t))
9614235Smarkfen {
9624235Smarkfen 	int *proto_nums, proto_count, i;
9634235Smarkfen 	int *alg_nums, alg_count, j;
9644235Smarkfen 	struct ipsecalgent *alg;
9654235Smarkfen 
9664235Smarkfen 	proto_nums = getipsecprotos(&proto_count);
9674235Smarkfen 	if (proto_nums == NULL) {
9684235Smarkfen 		errx(EXIT_FAILURE, gettext("getipsecprotos() failed."));
9694235Smarkfen 	}
9704235Smarkfen 
9714235Smarkfen 	for (i = 0; i < proto_count; i++) {
9724235Smarkfen 
9734235Smarkfen 		if (proto_action != NULL)
9744235Smarkfen 			proto_action(proto_nums[i]);
9754235Smarkfen 
9764235Smarkfen 		alg_nums = getipsecalgs(&alg_count, proto_nums[i]);
9774235Smarkfen 		if (alg_nums == NULL) {
9784235Smarkfen 			free(proto_nums);
9794235Smarkfen 			errx(EXIT_FAILURE, gettext("getipsecalgs() failed."));
9804235Smarkfen 		}
9814235Smarkfen 
9824235Smarkfen 		for (j = 0; j < alg_count; j++) {
9834235Smarkfen 			alg = getipsecalgbynum(alg_nums[j], proto_nums[i],
9844235Smarkfen 			    NULL);
9854235Smarkfen 			if (alg == NULL)
9864235Smarkfen 				continue;
9874235Smarkfen 			if (alg_action != NULL)
9884235Smarkfen 				alg_action(alg);
9894235Smarkfen 			freeipsecalgent(alg);
9904235Smarkfen 		}
9914235Smarkfen 		free(alg_nums);
9924235Smarkfen 	}
9934235Smarkfen 	free(proto_nums);
9944235Smarkfen }
9954235Smarkfen 
9964235Smarkfen /*
9974235Smarkfen  * Use just the libnsl/libipsecutil APIs to dump out all of the algorithms.
9984235Smarkfen  */
9994235Smarkfen static void
show_algs(void)10004235Smarkfen show_algs(void)
10014235Smarkfen {
10024235Smarkfen 	/* Yes, I'm aware that this'll produce TWO newlines. */
10034235Smarkfen 	(void) puts(gettext(
10044235Smarkfen 	    "List of algorithms, grouped by IPsec protocol:\n"));
10054235Smarkfen 
10064235Smarkfen 	algs_walker(dump_alg, dump_proto);
10074235Smarkfen }
10084235Smarkfen 
10094235Smarkfen static int
try_int(char * optarg,const char * what)10104235Smarkfen try_int(char *optarg, const char *what)
10114235Smarkfen {
10124235Smarkfen 	int rc = atoi(optarg);
10134235Smarkfen 
10144235Smarkfen 	if (rc <= 0) {
10154235Smarkfen 		warnx(gettext("Invalid %s value"), what);
10164235Smarkfen 		usage();
10174235Smarkfen 	}
10184235Smarkfen 	return (rc);
10194235Smarkfen }
10204235Smarkfen 
10214235Smarkfen static void
try_cmd(cmd_t newcmd)10224235Smarkfen try_cmd(cmd_t newcmd)
10234235Smarkfen {
10244235Smarkfen 	if (cmd != CMD_NONE)
10254235Smarkfen 		usage();
10264235Smarkfen 	cmd = newcmd;
10274235Smarkfen }
10284235Smarkfen 
10294235Smarkfen int
main(int argc,char * argv[])10304235Smarkfen main(int argc, char *argv[])
10314235Smarkfen {
10324235Smarkfen 	int c;
10334235Smarkfen 	zoneid_t zoneid;
10344235Smarkfen 	ushort_t flags;
10354235Smarkfen 
10364235Smarkfen 	(void) setlocale(LC_ALL, "");
10374235Smarkfen #if !defined(TEXT_DOMAIN)
10384235Smarkfen #define	TEXT_DOMAIN "SYS_TEST"
10394235Smarkfen #endif
10404235Smarkfen 	(void) textdomain(TEXT_DOMAIN);
10414235Smarkfen 
10424235Smarkfen 	if (argc == 1) {
10434235Smarkfen 		show_algs();
10444235Smarkfen 		return (EXIT_SUCCESS);
10454235Smarkfen 	}
10464235Smarkfen 
10474235Smarkfen 	while ((c = getopt(argc, argv,
1048*10824SMark.Fenwick@Sun.COM 	    "aflrRsb:p:P:i:k:K:m:n:N:e:S:M:I:F:")) != EOF) {
10494235Smarkfen 		switch (c) {
10504235Smarkfen 		case 'a':
10514235Smarkfen 			try_cmd(CMD_ADD);
10524235Smarkfen 			break;
10534235Smarkfen 		case 'f':
10544235Smarkfen 			/* multiple occurences of -f are harmless */
10554235Smarkfen 			adddel_flags = LIBIPSEC_ALGS_ADD_FORCE;
10564235Smarkfen 			break;
10574235Smarkfen 		case 'l':
10584235Smarkfen 			try_cmd(CMD_LIST_KERNEL);
10594235Smarkfen 			break;
10604235Smarkfen 		case 'r':
10614235Smarkfen 			try_cmd(CMD_DEL);
10624235Smarkfen 			break;
10634235Smarkfen 		case 'R':
10644235Smarkfen 			try_cmd(CMD_DEL_PROTO);
10654235Smarkfen 			break;
10664235Smarkfen 		case 's':
10674235Smarkfen 			/* multiple occurences of -s are harmless */
10684235Smarkfen 			synch_kernel = B_TRUE;
10694235Smarkfen 			break;
10704235Smarkfen 		case 'n':
10714235Smarkfen 			if (alg_names_string != NULL)
10724235Smarkfen 				usage();
10734235Smarkfen 			alg_names_string = optarg;
10744235Smarkfen 			break;
10754235Smarkfen 		case 'b':
10764235Smarkfen 			if (block_sizes_string != NULL)
10774235Smarkfen 				usage();
10784235Smarkfen 			block_sizes_string = optarg;
10794235Smarkfen 			break;
10804235Smarkfen 		case 'p':
10814235Smarkfen 			if (proto_name != NULL)
10824235Smarkfen 				usage();
10834235Smarkfen 			proto_name = optarg;
10844235Smarkfen 			break;
10854235Smarkfen 		case 'P':
10864235Smarkfen 			if (proto_number != -1)
10874235Smarkfen 				usage();
10884235Smarkfen 			proto_number = try_int(optarg,
10894235Smarkfen 			    gettext("protocol number"));
10904235Smarkfen 			break;
10914235Smarkfen 		case 'e':
10924235Smarkfen 			if (exec_mode_string != NULL)
10934235Smarkfen 				usage();
10944235Smarkfen 			exec_mode_string = optarg;
10954235Smarkfen 			if (_str_to_ipsec_exec_mode(exec_mode_string,
10964235Smarkfen 			    &proto_exec_mode) == -1) {
10974235Smarkfen 				warnx(gettext("Invalid execution mode \"%s\""),
10984235Smarkfen 				    exec_mode_string);
10994235Smarkfen 				usage();
11004235Smarkfen 			}
11014235Smarkfen 			break;
11024235Smarkfen 		case 'i':
11034235Smarkfen 			if (increment != 0)
11044235Smarkfen 				usage();
11054235Smarkfen 			increment = try_int(optarg,
11064235Smarkfen 			    gettext("key size increment"));
11074235Smarkfen 			break;
11084235Smarkfen 		case 'k':
11094235Smarkfen 			if (key_sizes_string != NULL)
11104235Smarkfen 				usage();
11114235Smarkfen 			key_sizes_string = optarg;
11124235Smarkfen 			break;
11134235Smarkfen 		case 'K':
11144235Smarkfen 			if (default_keylen != 0)
11154235Smarkfen 				usage();
11164235Smarkfen 			default_keylen = try_int(optarg,
11174235Smarkfen 			    gettext("default key size"));
11184235Smarkfen 			break;
11194235Smarkfen 		case 'm':
11204235Smarkfen 			if (mech_name != NULL)
11214235Smarkfen 				usage();
11224235Smarkfen 			mech_name = optarg;
11234235Smarkfen 			break;
11244235Smarkfen 		case 'N':
11254235Smarkfen 			if (alg_number != -1)
11264235Smarkfen 				usage();
11274235Smarkfen 			alg_number = try_int(optarg,
11284235Smarkfen 			    gettext("algorithm number"));
11294235Smarkfen 			break;
1130*10824SMark.Fenwick@Sun.COM 		case 'I':
1131*10824SMark.Fenwick@Sun.COM 			if (mech_params[iv_len] != 0)
1132*10824SMark.Fenwick@Sun.COM 				usage();
1133*10824SMark.Fenwick@Sun.COM 			mech_params[iv_len] = try_int(optarg,
1134*10824SMark.Fenwick@Sun.COM 			    gettext("Initialization Vector length"));
1135*10824SMark.Fenwick@Sun.COM 			break;
1136*10824SMark.Fenwick@Sun.COM 		case 'M':
1137*10824SMark.Fenwick@Sun.COM 			if (mech_params[mac_len] != 0)
1138*10824SMark.Fenwick@Sun.COM 				usage();
1139*10824SMark.Fenwick@Sun.COM 			mech_params[mac_len] = try_int(optarg,
1140*10824SMark.Fenwick@Sun.COM 			    gettext("Integrity Check Vector length"));
1141*10824SMark.Fenwick@Sun.COM 			break;
1142*10824SMark.Fenwick@Sun.COM 		case 'S':
1143*10824SMark.Fenwick@Sun.COM 			if (mech_params[salt_bytes] != 0)
1144*10824SMark.Fenwick@Sun.COM 				usage();
1145*10824SMark.Fenwick@Sun.COM 			mech_params[salt_bytes] = try_int(optarg,
1146*10824SMark.Fenwick@Sun.COM 			    gettext("Salt length"));
1147*10824SMark.Fenwick@Sun.COM 			break;
1148*10824SMark.Fenwick@Sun.COM 		case 'F':
1149*10824SMark.Fenwick@Sun.COM 			/*
1150*10824SMark.Fenwick@Sun.COM 			 * Multiple flags can be specified, the results
1151*10824SMark.Fenwick@Sun.COM 			 * are OR'd together.  Flags can be specified as
1152*10824SMark.Fenwick@Sun.COM 			 * number or  a comma separated string
1153*10824SMark.Fenwick@Sun.COM 			 */
1154*10824SMark.Fenwick@Sun.COM 			flags = atoi(optarg);
1155*10824SMark.Fenwick@Sun.COM 			if (flags) {
1156*10824SMark.Fenwick@Sun.COM 				alg_flags |= flags;
1157*10824SMark.Fenwick@Sun.COM 				flag_string = NULL;
1158*10824SMark.Fenwick@Sun.COM 			} else {
1159*10824SMark.Fenwick@Sun.COM 				flag_string = optarg;
1160*10824SMark.Fenwick@Sun.COM 			}
1161*10824SMark.Fenwick@Sun.COM 			break;
1162*10824SMark.Fenwick@Sun.COM 		default:
1163*10824SMark.Fenwick@Sun.COM 			usage();
11644235Smarkfen 		}
11654235Smarkfen 	}
11664235Smarkfen 
11674235Smarkfen 	/*
11684235Smarkfen 	 * When both protocol name (-p) and protocol number (-P) are
11694235Smarkfen 	 * specified, a new protocol is being defined.
11704235Smarkfen 	 */
11714235Smarkfen 	if (proto_number != -1 && proto_name != NULL)
11724235Smarkfen 		try_cmd(CMD_ADD_PROTO);
11734235Smarkfen 	else if (exec_mode_string != NULL)
11744235Smarkfen 		try_cmd(CMD_EXEC_MODE);
11754235Smarkfen 
11764235Smarkfen 	/*
11774235Smarkfen 	 * Process specified command.
11784235Smarkfen 	 */
11794235Smarkfen 	switch (cmd) {
11804235Smarkfen 	case CMD_ADD:
11814235Smarkfen 		new_alg();
11824235Smarkfen 		break;
11834235Smarkfen 	case CMD_ADD_PROTO:
11844235Smarkfen 		new_proto();
11854235Smarkfen 		break;
11864235Smarkfen 	case CMD_DEL:
11874235Smarkfen 		remove_alg();
11884235Smarkfen 		break;
11894235Smarkfen 	case CMD_DEL_PROTO:
11904235Smarkfen 		remove_proto();
11914235Smarkfen 		break;
11924235Smarkfen 	case CMD_EXEC_MODE:
11934235Smarkfen 		set_exec_mode();
11944235Smarkfen 		break;
11954235Smarkfen 	case CMD_LIST_KERNEL:
11964235Smarkfen 		if (synch_kernel)
11974235Smarkfen 			usage();
11984235Smarkfen 		list_kernel_algs();
11994235Smarkfen 		break;
12004235Smarkfen 	default:
12014235Smarkfen 		if (!synch_kernel)
12024235Smarkfen 			usage();
12034235Smarkfen 	}
12044235Smarkfen 
12054235Smarkfen 	if (synch_kernel) {
12064235Smarkfen 		/*
12074235Smarkfen 		 * This will only work in the global zone or
12084235Smarkfen 		 * a zone with an exclusive IP stack.
12094235Smarkfen 		 */
12104235Smarkfen 		if ((zoneid = getzoneid()) == 0) {
12114235Smarkfen 			kernel_synch();
12124235Smarkfen 		} else {
12134235Smarkfen 			if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
12144235Smarkfen 			    sizeof (flags)) < 0) {
12154235Smarkfen 				err(EXIT_FAILURE, gettext(
12164235Smarkfen 				    "Unable to determine zone IP type"));
12174235Smarkfen 			}
12184235Smarkfen 			if (flags & ZF_NET_EXCL) {
12194235Smarkfen 				kernel_synch();
12204235Smarkfen 			} else {
12214235Smarkfen 				(void) printf(gettext("Synchronization with "
12224235Smarkfen 				    "kernel not appropriate in this zone.\n"));
12234235Smarkfen 			}
12244235Smarkfen 		}
12254235Smarkfen 	}
12264235Smarkfen 
12274235Smarkfen 	return (EXIT_SUCCESS);
12284235Smarkfen }
1229