17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5e3320f40Smarkfen  * Common Development and Distribution License (the "License").
6e3320f40Smarkfen  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*628b0c67SMark Fenwick  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <ipsec_util.h>
277c478bd9Sstevel@tonic-gate #include <netdb.h>
287c478bd9Sstevel@tonic-gate #include <locale.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include <assert.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <net/pfpolicy.h>
357c478bd9Sstevel@tonic-gate #include <strings.h>
367c478bd9Sstevel@tonic-gate #include <errno.h>
377c478bd9Sstevel@tonic-gate #include <sys/crypto/common.h>
38e3320f40Smarkfen #include <zone.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #define	SPDSOCK_DIAG_BUF_LEN	128
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate typedef enum cmd_s {
437c478bd9Sstevel@tonic-gate 	CMD_NONE = 0,
447c478bd9Sstevel@tonic-gate 	CMD_ADD,
457c478bd9Sstevel@tonic-gate 	CMD_ADD_PROTO,
467c478bd9Sstevel@tonic-gate 	CMD_DEL,
477c478bd9Sstevel@tonic-gate 	CMD_DEL_PROTO,
487c478bd9Sstevel@tonic-gate 	CMD_EXEC_MODE,
497c478bd9Sstevel@tonic-gate 	CMD_LIST_KERNEL
507c478bd9Sstevel@tonic-gate } cmd_t;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate static const char *comma = ",";
537c478bd9Sstevel@tonic-gate static int adddel_flags, increment = 0, default_keylen;
547c478bd9Sstevel@tonic-gate static boolean_t synch_kernel;
557c478bd9Sstevel@tonic-gate static cmd_t cmd = CMD_NONE;
56*628b0c67SMark Fenwick static int proto_number = -1, alg_number = -1, alg_flags = 0;
577c478bd9Sstevel@tonic-gate static char *proto_name, *alg_names_string, *block_sizes_string;
587c478bd9Sstevel@tonic-gate static char *key_sizes_string, *mech_name, *exec_mode_string;
59*628b0c67SMark Fenwick static char *flag_string;
607c478bd9Sstevel@tonic-gate static ipsecalgs_exec_mode_t proto_exec_mode = LIBIPSEC_ALGS_EXEC_SYNC;
61*628b0c67SMark Fenwick enum param_values {iv_len, mac_len, salt_bytes, max_param};
62*628b0c67SMark Fenwick static int mech_params[max_param];
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * Used by the algorithm walker callback to populate a SPD_UPDATEALGS
667c478bd9Sstevel@tonic-gate  * request.
677c478bd9Sstevel@tonic-gate  */
687c478bd9Sstevel@tonic-gate 
69*628b0c67SMark Fenwick #define	SYNC_REQ_SIZE	4096
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate static uint64_t sync_req_buf[SYNC_REQ_SIZE];
727c478bd9Sstevel@tonic-gate static struct spd_attribute *sync_req_attr;
737c478bd9Sstevel@tonic-gate static uint_t sync_req_alg_count, sync_req_proto_count;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate #define	EMIT(ap, tag, value) {					\
767c478bd9Sstevel@tonic-gate 		(ap)->spd_attr_tag = (tag);			\
777c478bd9Sstevel@tonic-gate 		(ap)->spd_attr_value = (value);			\
787c478bd9Sstevel@tonic-gate 		(ap)++;						\
797c478bd9Sstevel@tonic-gate 		if ((char *)(ap) + sizeof (*ap) -		\
807c478bd9Sstevel@tonic-gate 		    (char *)sync_req_buf > SYNC_REQ_SIZE)	\
817c478bd9Sstevel@tonic-gate 			bail_nomem();				\
827c478bd9Sstevel@tonic-gate 	}
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate static void dump_alg(struct ipsecalgent *);
857c478bd9Sstevel@tonic-gate static void algs_walker(void (*)(struct ipsecalgent *), void (*)(uint_t));
867c478bd9Sstevel@tonic-gate 
87*628b0c67SMark Fenwick static int
parse_flag(char * flag_str,uint_t flag)88*628b0c67SMark Fenwick parse_flag(char *flag_str, uint_t flag)
89*628b0c67SMark Fenwick {
90*628b0c67SMark Fenwick 	static struct flagtable {
91*628b0c67SMark Fenwick 		char *label;
92*628b0c67SMark Fenwick 		int token;
93*628b0c67SMark Fenwick 	} table[] = {
94*628b0c67SMark Fenwick 		{"VALID", 	ALG_FLAG_VALID},
95*628b0c67SMark Fenwick 		{"COUNTER",	ALG_FLAG_COUNTERMODE},
96*628b0c67SMark Fenwick 		{"COMBINED",	ALG_FLAG_COMBINED},
97*628b0c67SMark Fenwick 		{"CCM",		ALG_FLAG_CCM},
98*628b0c67SMark Fenwick 		{"GCM",		ALG_FLAG_GCM},
99*628b0c67SMark Fenwick 		{NULL,		0}
100*628b0c67SMark Fenwick 	};
101*628b0c67SMark Fenwick 	struct flagtable *ft = table;
102*628b0c67SMark Fenwick 
103*628b0c67SMark Fenwick 	if (flag_str == NULL) {
104*628b0c67SMark Fenwick 		/* Print out flag labels for each flag set. */
105*628b0c67SMark Fenwick 		if ((ALG_FLAG_KERNELCHECKED & flag) && !(ALG_FLAG_VALID & flag))
106*628b0c67SMark Fenwick 			(void) printf("INVALID ");
107*628b0c67SMark Fenwick 		while (ft->token != 0) {
108*628b0c67SMark Fenwick 			if (ft->token & flag) {
109*628b0c67SMark Fenwick 				(void) printf("%s ", ft->label);
110*628b0c67SMark Fenwick 			}
111*628b0c67SMark Fenwick 			ft++;
112*628b0c67SMark Fenwick 		}
113*628b0c67SMark Fenwick 		return (0);
114*628b0c67SMark Fenwick 	}
115*628b0c67SMark Fenwick 	/* Or, lookup flag for supplied label. */
116*628b0c67SMark Fenwick 	while (ft->label != NULL && strcmp(ft->label, flag_str) != 0)
117*628b0c67SMark Fenwick 		ft++;
118*628b0c67SMark Fenwick 	return (ft->token);
119*628b0c67SMark Fenwick }
120*628b0c67SMark Fenwick 
1217c478bd9Sstevel@tonic-gate static void
usage(void)1227c478bd9Sstevel@tonic-gate usage(void)
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate 	errx(EXIT_FAILURE, gettext("Usage:\tipsecalgs\n"
125*628b0c67SMark Fenwick 	    "\tipsecalgs -l\n"
126*628b0c67SMark Fenwick 	    "\tipsecalgs -s\n"
127*628b0c67SMark Fenwick 	    "\tipsecalgs -a [-P protocol-number | -p protocol-name]\n"
128*628b0c67SMark Fenwick 	    "\t\t-k keylen-list [-i inc]\n"
129*628b0c67SMark Fenwick 	    "\t\t[-K default-keylen] -b blocklen-list\n"
130*628b0c67SMark Fenwick 	    "\t\t-n alg-names -N alg-number -m mech-name\n"
131*628b0c67SMark Fenwick 	    "\t\t[-M MAC length] [-S salt length] [-I IV length]\n"
132*628b0c67SMark Fenwick 	    "\t\t[-F COMBINED,COUNTER,CCM|GCM ] [-f] [-s]\n"
133*628b0c67SMark Fenwick 	    "\tipsecalgs -P protocol-number -p protocol-name\n"
134*628b0c67SMark Fenwick 	    "\t\t[-e exec-mode] [-f] [-s]\n"
135*628b0c67SMark Fenwick 	    "\tipsecalgs -r -p protocol-name -n alg-name [-s]\n"
136*628b0c67SMark Fenwick 	    "\tipsecalgs -r -p protocol-name -N alg-number [-s]\n"
137*628b0c67SMark Fenwick 	    "\tipsecalgs -R -P protocol-number [-s]\n"
138*628b0c67SMark Fenwick 	    "\tipsecalgs -R -p protocol-name [-s]\n"
139*628b0c67SMark Fenwick 	    "\tipsecalgs -e exec-mode -P protocol-number [-s]\n"
140*628b0c67SMark Fenwick 	    "\tipsecalgs -e exec-mode -p protocol-number [-s]"));
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate static void
bail_nomem(void)1447c478bd9Sstevel@tonic-gate bail_nomem(void)
1457c478bd9Sstevel@tonic-gate {
1467c478bd9Sstevel@tonic-gate 	errx(EXIT_FAILURE, gettext("Out of memory."));
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * Return the number of key or block sizes in the specified array.
1517c478bd9Sstevel@tonic-gate  */
1527c478bd9Sstevel@tonic-gate static uint_t
num_sizes(int * sizes)1537c478bd9Sstevel@tonic-gate num_sizes(int *sizes)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate 	uint_t nsizes = 0;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	while (sizes[nsizes] != 0)
1587c478bd9Sstevel@tonic-gate 		nsizes++;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	return (nsizes);
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate  * Algorithms walker callback. Adds an algorithm to the current SPD_UPDATEALGS
1657c478bd9Sstevel@tonic-gate  * request.
1667c478bd9Sstevel@tonic-gate  */
1677c478bd9Sstevel@tonic-gate static void
synch_emit_alg(struct ipsecalgent * alg)1687c478bd9Sstevel@tonic-gate synch_emit_alg(struct ipsecalgent *alg)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	uint_t nkey_sizes, nblock_sizes, i;
171*628b0c67SMark Fenwick 	uint_t nparams;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	EMIT(sync_req_attr, SPD_ATTR_ALG_ID, alg->a_alg_num);
1747c478bd9Sstevel@tonic-gate 	EMIT(sync_req_attr, SPD_ATTR_ALG_PROTO, alg->a_proto_num);
1757c478bd9Sstevel@tonic-gate 	EMIT(sync_req_attr, SPD_ATTR_ALG_INCRBITS, alg->a_key_increment);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	nkey_sizes = num_sizes(alg->a_key_sizes);
1787c478bd9Sstevel@tonic-gate 	EMIT(sync_req_attr, SPD_ATTR_ALG_NKEYSIZES, nkey_sizes);
1797c478bd9Sstevel@tonic-gate 	for (i = 0; i < nkey_sizes; i++)
1807c478bd9Sstevel@tonic-gate 		EMIT(sync_req_attr, SPD_ATTR_ALG_KEYSIZE, alg->a_key_sizes[i]);
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	nblock_sizes = num_sizes(alg->a_block_sizes);
183*628b0c67SMark Fenwick 	nparams = num_sizes(alg->a_mech_params);
1847c478bd9Sstevel@tonic-gate 	EMIT(sync_req_attr, SPD_ATTR_ALG_NBLOCKSIZES, nblock_sizes);
1857c478bd9Sstevel@tonic-gate 	for (i = 0; i < nblock_sizes; i++) {
1867c478bd9Sstevel@tonic-gate 		EMIT(sync_req_attr, SPD_ATTR_ALG_BLOCKSIZE,
1877c478bd9Sstevel@tonic-gate 		    alg->a_block_sizes[i]);
1887c478bd9Sstevel@tonic-gate 	}
189*628b0c67SMark Fenwick 	EMIT(sync_req_attr, SPD_ATTR_ALG_NPARAMS, nparams);
190*628b0c67SMark Fenwick 	for (i = 0; i < nparams; i++) {
191*628b0c67SMark Fenwick 		EMIT(sync_req_attr, SPD_ATTR_ALG_PARAMS,
192*628b0c67SMark Fenwick 		    alg->a_mech_params[i]);
193*628b0c67SMark Fenwick 	}
194*628b0c67SMark Fenwick 	EMIT(sync_req_attr, SPD_ATTR_ALG_FLAGS, alg->a_alg_flags);
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	EMIT(sync_req_attr, SPD_ATTR_ALG_MECHNAME, CRYPTO_MAX_MECH_NAME);
1977c478bd9Sstevel@tonic-gate 	(void) strncpy((char *)sync_req_attr, alg->a_mech_name,
1987c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
1997c478bd9Sstevel@tonic-gate 	sync_req_attr = (struct spd_attribute *)((uint64_t *)sync_req_attr +
2007c478bd9Sstevel@tonic-gate 	    SPD_8TO64(CRYPTO_MAX_MECH_NAME));
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	EMIT(sync_req_attr, SPD_ATTR_NEXT, 0);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	sync_req_alg_count++;
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate /*
2087c478bd9Sstevel@tonic-gate  * Protocol walker callback. Add protocol related info to the current
2097c478bd9Sstevel@tonic-gate  * SPD_UPDATEALGS request.
2107c478bd9Sstevel@tonic-gate  */
2117c478bd9Sstevel@tonic-gate static void
synch_emit_proto(uint_t proto_num)2127c478bd9Sstevel@tonic-gate synch_emit_proto(uint_t proto_num)
2137c478bd9Sstevel@tonic-gate {
2147c478bd9Sstevel@tonic-gate 	ipsecalgs_exec_mode_t exec_mode;
2157c478bd9Sstevel@tonic-gate 	uint32_t exec_mode_spdval;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	EMIT(sync_req_attr, SPD_ATTR_PROTO_ID, proto_num);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/* execution mode */
2207c478bd9Sstevel@tonic-gate 	if (ipsecproto_get_exec_mode(proto_num, &exec_mode) != 0) {
2217c478bd9Sstevel@tonic-gate 		errx(EXIT_FAILURE, gettext("cannot get execution mode for "
2227c478bd9Sstevel@tonic-gate 		    "proto %d"), proto_num);
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	switch (exec_mode) {
2267c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_EXEC_SYNC:
2277c478bd9Sstevel@tonic-gate 		exec_mode_spdval = SPD_ALG_EXEC_MODE_SYNC;
2287c478bd9Sstevel@tonic-gate 		break;
2297c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_EXEC_ASYNC:
2307c478bd9Sstevel@tonic-gate 		exec_mode_spdval = SPD_ALG_EXEC_MODE_ASYNC;
2317c478bd9Sstevel@tonic-gate 		break;
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 	EMIT(sync_req_attr, SPD_ATTR_PROTO_EXEC_MODE, exec_mode_spdval);
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	EMIT(sync_req_attr, SPD_ATTR_NEXT, 0);
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	sync_req_proto_count++;
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate /*
2417c478bd9Sstevel@tonic-gate  * Causes the kernel to be re-synched with the contents of /etc/inet/algs
2427c478bd9Sstevel@tonic-gate  */
2437c478bd9Sstevel@tonic-gate static void
kernel_synch(void)2447c478bd9Sstevel@tonic-gate kernel_synch(void)
2457c478bd9Sstevel@tonic-gate {
2467c478bd9Sstevel@tonic-gate 	int sfd = socket(PF_POLICY, SOCK_RAW, PF_POLICY_V1);
2477c478bd9Sstevel@tonic-gate 	int cnt, req_len;
2487c478bd9Sstevel@tonic-gate 	struct spd_msg *msg;
2497c478bd9Sstevel@tonic-gate 	struct spd_ext_actions *act;
2507c478bd9Sstevel@tonic-gate 	struct spd_attribute *attr;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	if (sfd < 0) {
2537c478bd9Sstevel@tonic-gate 		err(EXIT_FAILURE, gettext("Unable to open policy socket"));
2547c478bd9Sstevel@tonic-gate 	}
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	/*
2577c478bd9Sstevel@tonic-gate 	 * Initialize the SPD message header and action. Some fields
2587c478bd9Sstevel@tonic-gate 	 * are set after having walked through the algorithms (number
2597c478bd9Sstevel@tonic-gate 	 * of algorithms, sizes, etc.)
2607c478bd9Sstevel@tonic-gate 	 */
2617c478bd9Sstevel@tonic-gate 	msg = (struct spd_msg *)sync_req_buf;
2627c478bd9Sstevel@tonic-gate 	(void) memset(msg, 0, sizeof (*msg));
2637c478bd9Sstevel@tonic-gate 	msg->spd_msg_version = PF_POLICY_V1;
2647c478bd9Sstevel@tonic-gate 	msg->spd_msg_type = SPD_UPDATEALGS;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	act = (struct spd_ext_actions *)(msg + 1);
2677c478bd9Sstevel@tonic-gate 	act->spd_actions_exttype = SPD_EXT_ACTION;
2687c478bd9Sstevel@tonic-gate 	act->spd_actions_reserved = 0;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	/*
2717c478bd9Sstevel@tonic-gate 	 * Walk through the algorithms defined and populate the
2727c478bd9Sstevel@tonic-gate 	 * request buffer.
2737c478bd9Sstevel@tonic-gate 	 */
2747c478bd9Sstevel@tonic-gate 	sync_req_alg_count = 0;
2757c478bd9Sstevel@tonic-gate 	sync_req_proto_count = 0;
2767c478bd9Sstevel@tonic-gate 	sync_req_attr = (struct spd_attribute *)(act + 1);
2777c478bd9Sstevel@tonic-gate 	algs_walker(synch_emit_alg, synch_emit_proto);
2787c478bd9Sstevel@tonic-gate 	act->spd_actions_count = sync_req_alg_count + sync_req_proto_count;
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	/*
2817c478bd9Sstevel@tonic-gate 	 * Replace the last SPD_ATTR_NEXT attribute by a SPD_ATTR_END.
2827c478bd9Sstevel@tonic-gate 	 */
2837c478bd9Sstevel@tonic-gate 	attr = sync_req_attr - 1;
2847c478bd9Sstevel@tonic-gate 	attr->spd_attr_tag = SPD_ATTR_END;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	/*
2877c478bd9Sstevel@tonic-gate 	 * Now that the message is built, compute its total length and
2887c478bd9Sstevel@tonic-gate 	 * update the length fields that depend on this value.
2897c478bd9Sstevel@tonic-gate 	 */
2907c478bd9Sstevel@tonic-gate 	req_len = (char *)sync_req_attr - (char *)sync_req_buf;
2917c478bd9Sstevel@tonic-gate 	msg->spd_msg_len = SPD_8TO64(req_len);
2927c478bd9Sstevel@tonic-gate 	act->spd_actions_len = SPD_8TO64(req_len - sizeof (*msg));
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	/* ship the update request to spdsock */
2957c478bd9Sstevel@tonic-gate 	cnt = write(sfd, sync_req_buf, req_len);
2967c478bd9Sstevel@tonic-gate 	if (cnt != req_len) {
2977c478bd9Sstevel@tonic-gate 		if (cnt < 0) {
2987c478bd9Sstevel@tonic-gate 			err(EXIT_FAILURE, gettext("algs update write failed"));
2997c478bd9Sstevel@tonic-gate 		} else {
3007c478bd9Sstevel@tonic-gate 			errx(EXIT_FAILURE, gettext("algs update short write"));
3017c478bd9Sstevel@tonic-gate 		}
3027c478bd9Sstevel@tonic-gate 		/* err/errx call exit(). */
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	cnt = read(sfd, sync_req_buf, req_len);
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	if (cnt == -1) {
3087c478bd9Sstevel@tonic-gate 		err(EXIT_FAILURE, gettext("algs update read failed"));
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	if (cnt < sizeof (struct spd_msg)) {
3127c478bd9Sstevel@tonic-gate 		errx(EXIT_FAILURE, gettext(
3137c478bd9Sstevel@tonic-gate 		    "algs update failed while reading reply (short read)"));
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	msg = (struct spd_msg *)sync_req_buf;
3177c478bd9Sstevel@tonic-gate 	if (msg->spd_msg_errno != 0) {
3187c478bd9Sstevel@tonic-gate 		errno = msg->spd_msg_errno;
3197c478bd9Sstevel@tonic-gate 		warn(gettext("algs update failed"));
3207c478bd9Sstevel@tonic-gate 		if (msg->spd_msg_diagnostic != 0) {
3217c478bd9Sstevel@tonic-gate 			warnx("%s", spdsock_diag(msg->spd_msg_diagnostic));
3227c478bd9Sstevel@tonic-gate 		}
3237c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	(void) close(sfd);
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate static void
list_kernel_algs(void)3307c478bd9Sstevel@tonic-gate list_kernel_algs(void)
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate 	int sfd = socket(PF_POLICY, SOCK_RAW, PF_POLICY_V1);
3337c478bd9Sstevel@tonic-gate 	int cnt, retval;
3347c478bd9Sstevel@tonic-gate 	uint64_t reply_buf[2048];
3357c478bd9Sstevel@tonic-gate 	spd_ext_t *exts[SPD_EXT_MAX+1];
3367c478bd9Sstevel@tonic-gate 	struct spd_msg msg;
3377c478bd9Sstevel@tonic-gate 	struct spd_ext_actions *actp;
3387c478bd9Sstevel@tonic-gate 	struct spd_attribute *attr, *endattr;
3397c478bd9Sstevel@tonic-gate 	uint64_t *start, *end;
3407c478bd9Sstevel@tonic-gate 	struct ipsecalgent alg;
3417c478bd9Sstevel@tonic-gate 	uint_t cur_key, cur_block;
342*628b0c67SMark Fenwick 	uint_t nkey_sizes, nblock_sizes, nparams;
3437c478bd9Sstevel@tonic-gate 	char diag_buf[SPDSOCK_DIAG_BUF_LEN];
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	if (sfd < 0) {
3467c478bd9Sstevel@tonic-gate 		err(EXIT_FAILURE, gettext("Unable to open policy socket"));
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	(void) memset(&msg, 0, sizeof (msg));
3507c478bd9Sstevel@tonic-gate 	msg.spd_msg_version = PF_POLICY_V1;
3517c478bd9Sstevel@tonic-gate 	msg.spd_msg_type = SPD_DUMPALGS;
3527c478bd9Sstevel@tonic-gate 	msg.spd_msg_len = SPD_8TO64(sizeof (msg));
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	cnt = write(sfd, &msg, sizeof (msg));
3557c478bd9Sstevel@tonic-gate 	if (cnt != sizeof (msg)) {
3567c478bd9Sstevel@tonic-gate 		if (cnt < 0) {
3577c478bd9Sstevel@tonic-gate 			err(EXIT_FAILURE, gettext("dump algs write failed"));
3587c478bd9Sstevel@tonic-gate 		} else {
3597c478bd9Sstevel@tonic-gate 			errx(EXIT_FAILURE, gettext("dump algs short write"));
3607c478bd9Sstevel@tonic-gate 		}
3617c478bd9Sstevel@tonic-gate 		/* err/errx call exit(). */
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	cnt = read(sfd, reply_buf, sizeof (reply_buf));
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	if (cnt == -1) {
3677c478bd9Sstevel@tonic-gate 		err(EXIT_FAILURE, gettext("dump algs read failed"));
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	if (cnt < sizeof (struct spd_msg)) {
3717c478bd9Sstevel@tonic-gate 		errx(EXIT_FAILURE, gettext(
3727c478bd9Sstevel@tonic-gate 		    "dump algs failed while reading reply (short read)"));
3737c478bd9Sstevel@tonic-gate 	}
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	(void) close(sfd);
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	retval = spdsock_get_ext(exts, (spd_msg_t *)reply_buf, SPD_8TO64(cnt),
3787c478bd9Sstevel@tonic-gate 	    diag_buf, SPDSOCK_DIAG_BUF_LEN);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	if (retval == KGE_LEN && exts[0]->spd_ext_len == 0) {
3817c478bd9Sstevel@tonic-gate 		/*
3827c478bd9Sstevel@tonic-gate 		 * No algorithms are defined in the kernel, which caused
3837c478bd9Sstevel@tonic-gate 		 * the extension length to be zero, and spdsock_get_ext()
3847c478bd9Sstevel@tonic-gate 		 * to fail with a KGE_LEN error. This is not an error
3857c478bd9Sstevel@tonic-gate 		 * condition, so we return nicely.
3867c478bd9Sstevel@tonic-gate 		 */
3877c478bd9Sstevel@tonic-gate 		return;
3887c478bd9Sstevel@tonic-gate 	} else if (retval != 0) {
3897c478bd9Sstevel@tonic-gate 		if (strlen(diag_buf) != 0)
3907c478bd9Sstevel@tonic-gate 			warnx("%s", diag_buf);
3917c478bd9Sstevel@tonic-gate 		errx(EXIT_FAILURE, gettext("invalid extension "
3927c478bd9Sstevel@tonic-gate 		    "in dump algs reply (%d)"), retval);
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	if (exts[SPD_EXT_ACTION] == NULL) {
3967c478bd9Sstevel@tonic-gate 		errx(EXIT_FAILURE,
3977c478bd9Sstevel@tonic-gate 		    gettext("action missing in dump algs reply"));
3987c478bd9Sstevel@tonic-gate 	}
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	actp = (struct spd_ext_actions *)exts[SPD_EXT_ACTION];
4017c478bd9Sstevel@tonic-gate 	start = (uint64_t *)actp;
4027c478bd9Sstevel@tonic-gate 	end = (start + actp->spd_actions_len);
4037c478bd9Sstevel@tonic-gate 	endattr = (struct spd_attribute *)end;
4047c478bd9Sstevel@tonic-gate 	attr = (struct spd_attribute *)&actp[1];
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	bzero(&alg, sizeof (alg));
4077c478bd9Sstevel@tonic-gate 	nkey_sizes = nblock_sizes = 0;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	(void) printf("Kernel list of algorithms:\n\n");
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	while (attr < endattr) {
4127c478bd9Sstevel@tonic-gate 		switch (attr->spd_attr_tag) {
4137c478bd9Sstevel@tonic-gate 		case SPD_ATTR_NOP:
4147c478bd9Sstevel@tonic-gate 		case SPD_ATTR_EMPTY:
4157c478bd9Sstevel@tonic-gate 			break;
4167c478bd9Sstevel@tonic-gate 		case SPD_ATTR_END:
4177c478bd9Sstevel@tonic-gate 			attr = endattr;
4187c478bd9Sstevel@tonic-gate 			/* FALLTHRU */
4197c478bd9Sstevel@tonic-gate 		case SPD_ATTR_NEXT:
4207c478bd9Sstevel@tonic-gate 			/*
4217c478bd9Sstevel@tonic-gate 			 * Note that if the message received from the spdsock
4227c478bd9Sstevel@tonic-gate 			 * has a premature SPD_ATTR_END or SPD_ATTR_NEXT, this
4237c478bd9Sstevel@tonic-gate 			 * could cause the current algorithm to be only
4247c478bd9Sstevel@tonic-gate 			 * partially initialized.
4257c478bd9Sstevel@tonic-gate 			 */
426*628b0c67SMark Fenwick 			alg.a_alg_flags |= ALG_FLAG_KERNELCHECKED;
4277c478bd9Sstevel@tonic-gate 			dump_alg(&alg);
4287c478bd9Sstevel@tonic-gate 			free(alg.a_key_sizes);
4297c478bd9Sstevel@tonic-gate 			free(alg.a_block_sizes);
4307c478bd9Sstevel@tonic-gate 			free(alg.a_mech_name);
431*628b0c67SMark Fenwick 			free(alg.a_mech_params);
4327c478bd9Sstevel@tonic-gate 			bzero(&alg, sizeof (alg));
4337c478bd9Sstevel@tonic-gate 			nkey_sizes = nblock_sizes = 0;
4347c478bd9Sstevel@tonic-gate 			break;
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ALG_ID:
4377c478bd9Sstevel@tonic-gate 			alg.a_alg_num = attr->spd_attr_value;
4387c478bd9Sstevel@tonic-gate 			break;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ALG_PROTO:
4417c478bd9Sstevel@tonic-gate 			alg.a_proto_num = attr->spd_attr_value;
4427c478bd9Sstevel@tonic-gate 			break;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ALG_INCRBITS:
4457c478bd9Sstevel@tonic-gate 			alg.a_key_increment = attr->spd_attr_value;
4467c478bd9Sstevel@tonic-gate 			break;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ALG_NKEYSIZES:
4497c478bd9Sstevel@tonic-gate 			nkey_sizes = attr->spd_attr_value;
4507c478bd9Sstevel@tonic-gate 			if (alg.a_key_sizes != NULL) {
4517c478bd9Sstevel@tonic-gate 				errx(EXIT_FAILURE, gettext("duplicate number "
4527c478bd9Sstevel@tonic-gate 				    "of keys in dump algs reply"));
4537c478bd9Sstevel@tonic-gate 			}
4547c478bd9Sstevel@tonic-gate 			alg.a_key_sizes = calloc(nkey_sizes + 1, sizeof (int));
4557c478bd9Sstevel@tonic-gate 			if (alg.a_key_sizes == NULL)
4567c478bd9Sstevel@tonic-gate 				bail_nomem();
4577c478bd9Sstevel@tonic-gate 			cur_key = 0;
4587c478bd9Sstevel@tonic-gate 			break;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ALG_KEYSIZE:
4617c478bd9Sstevel@tonic-gate 			if (cur_key >= nkey_sizes) {
4627c478bd9Sstevel@tonic-gate 				errx(EXIT_FAILURE, gettext("too many key sizes"
4637c478bd9Sstevel@tonic-gate 				    " in dump algs reply"));
4647c478bd9Sstevel@tonic-gate 			}
4657c478bd9Sstevel@tonic-gate 			alg.a_key_sizes[cur_key++] = attr->spd_attr_value;
4667c478bd9Sstevel@tonic-gate 			break;
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ALG_NBLOCKSIZES:
4697c478bd9Sstevel@tonic-gate 			nblock_sizes = attr->spd_attr_value;
4707c478bd9Sstevel@tonic-gate 			if (alg.a_block_sizes != NULL) {
4717c478bd9Sstevel@tonic-gate 				errx(EXIT_FAILURE, gettext("duplicate number "
4727c478bd9Sstevel@tonic-gate 				    "of blocks in dump algs reply"));
4737c478bd9Sstevel@tonic-gate 			}
4747c478bd9Sstevel@tonic-gate 			alg.a_block_sizes = calloc(nblock_sizes + 1,
4757c478bd9Sstevel@tonic-gate 			    sizeof (int));
4767c478bd9Sstevel@tonic-gate 			if (alg.a_block_sizes == NULL)
4777c478bd9Sstevel@tonic-gate 				bail_nomem();
4787c478bd9Sstevel@tonic-gate 			cur_block = 0;
4797c478bd9Sstevel@tonic-gate 			break;
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ALG_BLOCKSIZE:
4827c478bd9Sstevel@tonic-gate 			if (cur_block >= nblock_sizes) {
4837c478bd9Sstevel@tonic-gate 				errx(EXIT_FAILURE, gettext("too many block "
4847c478bd9Sstevel@tonic-gate 				    "sizes in dump algs reply"));
4857c478bd9Sstevel@tonic-gate 			}
4867c478bd9Sstevel@tonic-gate 			alg.a_block_sizes[cur_block++] = attr->spd_attr_value;
4877c478bd9Sstevel@tonic-gate 			break;
4887c478bd9Sstevel@tonic-gate 
489*628b0c67SMark Fenwick 		case SPD_ATTR_ALG_NPARAMS:
490*628b0c67SMark Fenwick 			nparams = attr->spd_attr_value;
491*628b0c67SMark Fenwick 			if (alg.a_mech_params != NULL) {
492*628b0c67SMark Fenwick 				errx(EXIT_FAILURE, gettext("duplicate number "
493*628b0c67SMark Fenwick 				    "of params in dump algs reply"));
494*628b0c67SMark Fenwick 			}
495*628b0c67SMark Fenwick 			alg.a_mech_params = calloc(nparams + 1,
496*628b0c67SMark Fenwick 			    sizeof (int));
497*628b0c67SMark Fenwick 			if (alg.a_mech_params == NULL)
498*628b0c67SMark Fenwick 				bail_nomem();
499*628b0c67SMark Fenwick 			cur_block = 0;
500*628b0c67SMark Fenwick 			break;
501*628b0c67SMark Fenwick 
502*628b0c67SMark Fenwick 		case SPD_ATTR_ALG_PARAMS:
503*628b0c67SMark Fenwick 			if (cur_block >= nparams) {
504*628b0c67SMark Fenwick 				errx(EXIT_FAILURE, gettext("too many params "
505*628b0c67SMark Fenwick 				    "in dump algs reply"));
506*628b0c67SMark Fenwick 			}
507*628b0c67SMark Fenwick 			alg.a_mech_params[cur_block++] = attr->spd_attr_value;
508*628b0c67SMark Fenwick 			break;
509*628b0c67SMark Fenwick 
510*628b0c67SMark Fenwick 		case SPD_ATTR_ALG_FLAGS:
511*628b0c67SMark Fenwick 			alg.a_alg_flags = attr->spd_attr_value;
512*628b0c67SMark Fenwick 			break;
513*628b0c67SMark Fenwick 
5147c478bd9Sstevel@tonic-gate 		case SPD_ATTR_ALG_MECHNAME: {
5157c478bd9Sstevel@tonic-gate 			char *mech_name;
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 			if (alg.a_mech_name != NULL) {
5187c478bd9Sstevel@tonic-gate 				errx(EXIT_FAILURE, gettext(
5197c478bd9Sstevel@tonic-gate 				    "duplicate mech name in dump algs reply"));
5207c478bd9Sstevel@tonic-gate 			}
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 			alg.a_mech_name = malloc(attr->spd_attr_value);
5237c478bd9Sstevel@tonic-gate 			if (alg.a_mech_name == NULL)
5247c478bd9Sstevel@tonic-gate 				bail_nomem();
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 			mech_name = (char *)(attr + 1);
5277c478bd9Sstevel@tonic-gate 			bcopy(mech_name, alg.a_mech_name, attr->spd_attr_value);
5287c478bd9Sstevel@tonic-gate 			attr = (struct spd_attribute *)((uint64_t *)attr +
5297c478bd9Sstevel@tonic-gate 			    SPD_8TO64(attr->spd_attr_value));
5307c478bd9Sstevel@tonic-gate 			break;
5317c478bd9Sstevel@tonic-gate 		}
5327c478bd9Sstevel@tonic-gate 		}
5337c478bd9Sstevel@tonic-gate 		attr++;
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate static int *
parse_intlist(char * args,int * num_args)5407c478bd9Sstevel@tonic-gate parse_intlist(char *args, int *num_args)
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate 	int *rc = NULL;
5437c478bd9Sstevel@tonic-gate 	char *holder = NULL;
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	while ((holder = strtok((holder == NULL) ? args : NULL, comma)) !=
5467c478bd9Sstevel@tonic-gate 	    NULL) {
5477c478bd9Sstevel@tonic-gate 		(*num_args)++;
5487c478bd9Sstevel@tonic-gate 		rc = realloc(rc, ((*num_args) + 1) * sizeof (int));
5497c478bd9Sstevel@tonic-gate 		if (rc == NULL)
5507c478bd9Sstevel@tonic-gate 			bail_nomem();
5517c478bd9Sstevel@tonic-gate 		rc[(*num_args) - 1] = atoi(holder);
5527c478bd9Sstevel@tonic-gate 		if (rc[(*num_args) - 1] == 0)
5537c478bd9Sstevel@tonic-gate 			usage();	/* Malformed integer list! */
5547c478bd9Sstevel@tonic-gate 		rc[*num_args] = 0;
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	return (rc);
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate static void
new_alg(void)5617c478bd9Sstevel@tonic-gate new_alg(void)
5627c478bd9Sstevel@tonic-gate {
5637c478bd9Sstevel@tonic-gate 	struct ipsecalgent newbie;
5647c478bd9Sstevel@tonic-gate 	int num_names = 0, num_block_sizes = 0, num_key_sizes = 0;
5657c478bd9Sstevel@tonic-gate 	int i, rc;
5667c478bd9Sstevel@tonic-gate 	char *holder = NULL;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	/* Parameter reality check... */
5697c478bd9Sstevel@tonic-gate 	if (proto_number == -1) {
5707c478bd9Sstevel@tonic-gate 		if (proto_name == NULL) {
5717c478bd9Sstevel@tonic-gate 			warnx(gettext("Missing protocol number."));
5727c478bd9Sstevel@tonic-gate 			usage();
5737c478bd9Sstevel@tonic-gate 		}
5747c478bd9Sstevel@tonic-gate 		proto_number = getipsecprotobyname(proto_name);
5757c478bd9Sstevel@tonic-gate 		if (proto_number == -1) {
5767c478bd9Sstevel@tonic-gate 			warnx(gettext("Unknown protocol."));
5777c478bd9Sstevel@tonic-gate 			usage();
5787c478bd9Sstevel@tonic-gate 		}
5797c478bd9Sstevel@tonic-gate 	}
5807c478bd9Sstevel@tonic-gate 	if (alg_number == -1) {
5817c478bd9Sstevel@tonic-gate 		warnx(gettext("Missing algorithm number."));
5827c478bd9Sstevel@tonic-gate 		usage();
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 	if (key_sizes_string == NULL) {
5857c478bd9Sstevel@tonic-gate 		warnx(gettext("Missing key size(s)."));
5867c478bd9Sstevel@tonic-gate 		usage();
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 	if (alg_names_string == NULL) {
5897c478bd9Sstevel@tonic-gate 		warnx(gettext("Missing algorithm name(s)."));
5907c478bd9Sstevel@tonic-gate 		usage();
5917c478bd9Sstevel@tonic-gate 	}
5927c478bd9Sstevel@tonic-gate 	if (block_sizes_string == NULL) {
5937c478bd9Sstevel@tonic-gate 		warnx(gettext("Missing block/MAC lengths"));
5947c478bd9Sstevel@tonic-gate 		usage();
5957c478bd9Sstevel@tonic-gate 	}
5967c478bd9Sstevel@tonic-gate 	if (mech_name == NULL) {
5977c478bd9Sstevel@tonic-gate 		warnx(gettext("Missing mechanism name."));
5987c478bd9Sstevel@tonic-gate 		usage();
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 	newbie.a_proto_num = proto_number;
6017c478bd9Sstevel@tonic-gate 	newbie.a_alg_num = alg_number;
6027c478bd9Sstevel@tonic-gate 	newbie.a_key_increment = increment;
6037c478bd9Sstevel@tonic-gate 	newbie.a_mech_name = mech_name;
604*628b0c67SMark Fenwick 	newbie.a_alg_flags = alg_flags;
6057c478bd9Sstevel@tonic-gate 
606*628b0c67SMark Fenwick 	/*
607*628b0c67SMark Fenwick 	 * The ALG_FLAG_VALID is somewhat irrelevant as an input from the
608*628b0c67SMark Fenwick 	 * user, the kernel will decide if the algorithm description is
609*628b0c67SMark Fenwick 	 * valid or not and set the ALG_FLAG_VALID when the user dumps
610*628b0c67SMark Fenwick 	 * the kernel tables. To avoid confusion when the user dumps the
611*628b0c67SMark Fenwick 	 * contents off the ipsecalgs file, we set the ALG_FLAG_VALID here.
612*628b0c67SMark Fenwick 	 */
613*628b0c67SMark Fenwick 	newbie.a_alg_flags |= ALG_FLAG_VALID;
614*628b0c67SMark Fenwick 	while ((holder = strtok((holder == NULL) ? flag_string : NULL,
615*628b0c67SMark Fenwick 	    comma)) != NULL) {
616*628b0c67SMark Fenwick 		alg_flags = parse_flag(holder, 0);
617*628b0c67SMark Fenwick 		if (!alg_flags) {
618*628b0c67SMark Fenwick 			warnx(gettext("Invalid flag: %s\n"), holder);
619*628b0c67SMark Fenwick 			usage();
620*628b0c67SMark Fenwick 		}
621*628b0c67SMark Fenwick 		newbie.a_alg_flags |= alg_flags;
622*628b0c67SMark Fenwick 	}
6237c478bd9Sstevel@tonic-gate 	newbie.a_names = NULL;
6247c478bd9Sstevel@tonic-gate 	while ((holder = strtok((holder == NULL) ? alg_names_string : NULL,
625*628b0c67SMark Fenwick 	    comma)) != NULL) {
6267c478bd9Sstevel@tonic-gate 		newbie.a_names = realloc(newbie.a_names,
6277c478bd9Sstevel@tonic-gate 		    sizeof (char *) * ((++num_names) + 1));
6287c478bd9Sstevel@tonic-gate 		if (newbie.a_names == NULL)
6297c478bd9Sstevel@tonic-gate 			bail_nomem();
6307c478bd9Sstevel@tonic-gate 		newbie.a_names[num_names - 1] = holder;
6317c478bd9Sstevel@tonic-gate 		newbie.a_names[num_names] = NULL;
6327c478bd9Sstevel@tonic-gate 	}
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	/* Extract block sizes. */
6357c478bd9Sstevel@tonic-gate 	newbie.a_block_sizes = parse_intlist(block_sizes_string,
6367c478bd9Sstevel@tonic-gate 	    &num_block_sizes);
637*628b0c67SMark Fenwick 	newbie.a_mech_params = &mech_params[0];
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	/* Extract key sizes. */
6407c478bd9Sstevel@tonic-gate 	if ((holder = strchr(key_sizes_string, '-')) != NULL) {
6417c478bd9Sstevel@tonic-gate 		/* key sizes by range, key size increment required */
6427c478bd9Sstevel@tonic-gate 		if (newbie.a_key_increment == 0) {
6437c478bd9Sstevel@tonic-gate 			warnx(gettext("Missing key increment"));
6447c478bd9Sstevel@tonic-gate 			usage();
6457c478bd9Sstevel@tonic-gate 		}
6467c478bd9Sstevel@tonic-gate 		newbie.a_key_sizes = calloc(sizeof (int),
6477c478bd9Sstevel@tonic-gate 		    LIBIPSEC_ALGS_KEY_NUM_VAL);
6487c478bd9Sstevel@tonic-gate 		if (newbie.a_key_sizes == NULL)
6497c478bd9Sstevel@tonic-gate 			bail_nomem();
6507c478bd9Sstevel@tonic-gate 		*holder = '\0';
6517c478bd9Sstevel@tonic-gate 		holder++;
6527c478bd9Sstevel@tonic-gate 		/*
6537c478bd9Sstevel@tonic-gate 		 * At this point, holder points to high, key_sizes_string
6547c478bd9Sstevel@tonic-gate 		 * points to low.
6557c478bd9Sstevel@tonic-gate 		 */
6567c478bd9Sstevel@tonic-gate 		newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] =
6577c478bd9Sstevel@tonic-gate 		    atoi(key_sizes_string);
6587c478bd9Sstevel@tonic-gate 		if (newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] == 0) {
6597c478bd9Sstevel@tonic-gate 			warnx(gettext("Invalid lower key size range"));
6607c478bd9Sstevel@tonic-gate 			usage();
6617c478bd9Sstevel@tonic-gate 		}
6627c478bd9Sstevel@tonic-gate 		newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] = atoi(holder);
6637c478bd9Sstevel@tonic-gate 		if (newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] == 0) {
6647c478bd9Sstevel@tonic-gate 			warnx(gettext("Invalid higher key size range"));
6657c478bd9Sstevel@tonic-gate 			usage();
6667c478bd9Sstevel@tonic-gate 		}
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 		/* sanity check key range consistency */
6697c478bd9Sstevel@tonic-gate 		if (newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] >=
6707c478bd9Sstevel@tonic-gate 		    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX]) {
6717c478bd9Sstevel@tonic-gate 			warnx(gettext("Invalid key size range (min >= max)"));
6727c478bd9Sstevel@tonic-gate 			usage();
6737c478bd9Sstevel@tonic-gate 		}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 		/* check key increment vs key range */
6767c478bd9Sstevel@tonic-gate 		if (((newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] -
6777c478bd9Sstevel@tonic-gate 		    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX]) %
6787c478bd9Sstevel@tonic-gate 		    newbie.a_key_increment) != 0) {
6797c478bd9Sstevel@tonic-gate 			warnx(gettext("Key size increment"
6807c478bd9Sstevel@tonic-gate 			    " not consistent with key size range"));
6817c478bd9Sstevel@tonic-gate 			usage();
6827c478bd9Sstevel@tonic-gate 		}
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 		/* default key size */
6857c478bd9Sstevel@tonic-gate 		if (default_keylen != 0) {
6867c478bd9Sstevel@tonic-gate 			/* check specified default key size */
6877c478bd9Sstevel@tonic-gate 			if (default_keylen <
6887c478bd9Sstevel@tonic-gate 			    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] ||
6897c478bd9Sstevel@tonic-gate 			    default_keylen >
6907c478bd9Sstevel@tonic-gate 			    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] ||
6917c478bd9Sstevel@tonic-gate 			    ((default_keylen -
6927c478bd9Sstevel@tonic-gate 			    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX]) %
6937c478bd9Sstevel@tonic-gate 			    newbie.a_key_increment) != 0) {
6947c478bd9Sstevel@tonic-gate 				warnx(gettext("Default key size not consistent"
6957c478bd9Sstevel@tonic-gate 				    " with key size range"));
6967c478bd9Sstevel@tonic-gate 				usage();
6977c478bd9Sstevel@tonic-gate 			}
6987c478bd9Sstevel@tonic-gate 			newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_DEF_IDX] =
6997c478bd9Sstevel@tonic-gate 			    default_keylen;
7007c478bd9Sstevel@tonic-gate 		} else {
7017c478bd9Sstevel@tonic-gate 			/* min key size in range if not specified */
7027c478bd9Sstevel@tonic-gate 			newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_DEF_IDX] =
703*628b0c67SMark Fenwick 			    newbie.a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX];
7047c478bd9Sstevel@tonic-gate 		}
7057c478bd9Sstevel@tonic-gate 	} else {
7067c478bd9Sstevel@tonic-gate 		/* key sizes by enumeration */
7077c478bd9Sstevel@tonic-gate 		if (newbie.a_key_increment != 0) {
7087c478bd9Sstevel@tonic-gate 			warnx(gettext("Key increment must "
7097c478bd9Sstevel@tonic-gate 			    "not be specified with key sizes enumeration"));
7107c478bd9Sstevel@tonic-gate 			usage();
7117c478bd9Sstevel@tonic-gate 		}
7127c478bd9Sstevel@tonic-gate 		newbie.a_key_sizes = parse_intlist(key_sizes_string,
7137c478bd9Sstevel@tonic-gate 		    &num_key_sizes);
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 		/* default key size */
7167c478bd9Sstevel@tonic-gate 		if (default_keylen != 0 && default_keylen !=
7177c478bd9Sstevel@tonic-gate 		    newbie.a_key_sizes[0]) {
7187c478bd9Sstevel@tonic-gate 			/*
7197c478bd9Sstevel@tonic-gate 			 * The default key size is not at the front of the
7207c478bd9Sstevel@tonic-gate 			 * list. Swap it with the first element of the list.
7217c478bd9Sstevel@tonic-gate 			 */
7227c478bd9Sstevel@tonic-gate 			for (i = 1; i < num_key_sizes; i++) {
7237c478bd9Sstevel@tonic-gate 				if (newbie.a_key_sizes[i] == default_keylen)
7247c478bd9Sstevel@tonic-gate 					break;
7257c478bd9Sstevel@tonic-gate 				if (i >= num_key_sizes) {
7267c478bd9Sstevel@tonic-gate 					warnx(gettext("Default key size not "
7277c478bd9Sstevel@tonic-gate 					    "in list of key sizes"));
7287c478bd9Sstevel@tonic-gate 					usage();
7297c478bd9Sstevel@tonic-gate 				}
7307c478bd9Sstevel@tonic-gate 				newbie.a_key_sizes[i] = newbie.a_key_sizes[0];
7317c478bd9Sstevel@tonic-gate 				newbie.a_key_sizes[0] = default_keylen;
7327c478bd9Sstevel@tonic-gate 			}
7337c478bd9Sstevel@tonic-gate 		}
7347c478bd9Sstevel@tonic-gate 	}
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	/* Call things! */
7377c478bd9Sstevel@tonic-gate 	if ((rc = addipsecalg(&newbie, adddel_flags)) != 0) {
7387c478bd9Sstevel@tonic-gate 		errx(EXIT_FAILURE, gettext("addipsecalg() call failed: "
7397c478bd9Sstevel@tonic-gate 		    "%s"), ipsecalgs_diag(rc));
7407c478bd9Sstevel@tonic-gate 	}
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	free(newbie.a_names);
7437c478bd9Sstevel@tonic-gate 	free(newbie.a_block_sizes);
7447c478bd9Sstevel@tonic-gate 	free(newbie.a_key_sizes);
7457c478bd9Sstevel@tonic-gate }
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate static void
new_proto(void)7487c478bd9Sstevel@tonic-gate new_proto(void)
7497c478bd9Sstevel@tonic-gate {
7507c478bd9Sstevel@tonic-gate 	int rc;
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	if ((rc = addipsecproto(proto_name, proto_number, proto_exec_mode,
7537c478bd9Sstevel@tonic-gate 	    adddel_flags))
7547c478bd9Sstevel@tonic-gate 	    != 0) {
7557c478bd9Sstevel@tonic-gate 		errx(EXIT_FAILURE, gettext(
7567c478bd9Sstevel@tonic-gate 		    "Cannot add protocol %1$d \"%2$s\": %3$s"), proto_number,
7577c478bd9Sstevel@tonic-gate 		    proto_name, ipsecalgs_diag(rc));
7587c478bd9Sstevel@tonic-gate 	}
7597c478bd9Sstevel@tonic-gate }
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate static void
remove_alg(void)7627c478bd9Sstevel@tonic-gate remove_alg(void)
7637c478bd9Sstevel@tonic-gate {
7647c478bd9Sstevel@tonic-gate 	int rc;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	if (proto_number == -1) {
7677c478bd9Sstevel@tonic-gate 		if (proto_name == NULL) {
7687c478bd9Sstevel@tonic-gate 			warnx(gettext("Missing protocol number."));
7697c478bd9Sstevel@tonic-gate 			usage();
7707c478bd9Sstevel@tonic-gate 		}
7717c478bd9Sstevel@tonic-gate 		proto_number = getipsecprotobyname(proto_name);
7727c478bd9Sstevel@tonic-gate 		if (proto_number == -1) {
7737c478bd9Sstevel@tonic-gate 			errx(EXIT_FAILURE, gettext(
7747c478bd9Sstevel@tonic-gate 			    "Unknown protocol \"%s\"."), proto_name);
7757c478bd9Sstevel@tonic-gate 		}
7767c478bd9Sstevel@tonic-gate 	}
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	if (alg_number == -1) {
7797c478bd9Sstevel@tonic-gate 		if (alg_names_string == NULL) {
7807c478bd9Sstevel@tonic-gate 			errx(EXIT_FAILURE, gettext("Missing algorithm ID."));
7817c478bd9Sstevel@tonic-gate 		}
7827c478bd9Sstevel@tonic-gate 		if (strchr(alg_names_string, ',') != NULL) {
7837c478bd9Sstevel@tonic-gate 			errx(EXIT_FAILURE, gettext(
784*628b0c67SMark Fenwick 			    "Specify a single algorithm name for removal, "
785*628b0c67SMark Fenwick 			    "not a list."));
7867c478bd9Sstevel@tonic-gate 		}
7877c478bd9Sstevel@tonic-gate 		if ((rc = delipsecalgbyname(alg_names_string, proto_number))
7887c478bd9Sstevel@tonic-gate 		    != 0) {
7897c478bd9Sstevel@tonic-gate 			errx(EXIT_FAILURE, gettext(
7907c478bd9Sstevel@tonic-gate 			    "Could not remove algorithm %1$s: %2$s"),
7917c478bd9Sstevel@tonic-gate 			    alg_names_string, ipsecalgs_diag(rc));
7927c478bd9Sstevel@tonic-gate 		}
7937c478bd9Sstevel@tonic-gate 	} else {
7947c478bd9Sstevel@tonic-gate 		if ((rc = delipsecalgbynum(alg_number, proto_number)) != 0) {
7957c478bd9Sstevel@tonic-gate 			errx(EXIT_FAILURE, gettext(
7967c478bd9Sstevel@tonic-gate 			    "Could not remove algorithm %1$d: %2$s"),
7977c478bd9Sstevel@tonic-gate 			    alg_number, ipsecalgs_diag(rc));
7987c478bd9Sstevel@tonic-gate 		}
7997c478bd9Sstevel@tonic-gate 	}
8007c478bd9Sstevel@tonic-gate }
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate static void
remove_proto(void)8037c478bd9Sstevel@tonic-gate remove_proto(void)
8047c478bd9Sstevel@tonic-gate {
8057c478bd9Sstevel@tonic-gate 	int rc;
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	if (proto_number == -1) {
8087c478bd9Sstevel@tonic-gate 		if (proto_name == NULL) {
8097c478bd9Sstevel@tonic-gate 			warnx(gettext("Please specify protocol to remove."));
8107c478bd9Sstevel@tonic-gate 			usage();
8117c478bd9Sstevel@tonic-gate 		}
8127c478bd9Sstevel@tonic-gate 		if ((rc = delipsecprotobyname(proto_name)) != 0) {
8137c478bd9Sstevel@tonic-gate 			errx(EXIT_FAILURE, gettext(
8147c478bd9Sstevel@tonic-gate 			    "Could not remove protocol %1$s: %2$s"),
8157c478bd9Sstevel@tonic-gate 			    proto_name, ipsecalgs_diag(rc));
8167c478bd9Sstevel@tonic-gate 		}
8177c478bd9Sstevel@tonic-gate 	} else {
8187c478bd9Sstevel@tonic-gate 		if ((rc = delipsecprotobynum(proto_number)) != 0) {
8197c478bd9Sstevel@tonic-gate 			errx(EXIT_FAILURE, gettext(
8207c478bd9Sstevel@tonic-gate 			    "Could not remove protocol %1$d: %2$s"),
8217c478bd9Sstevel@tonic-gate 			    proto_number, ipsecalgs_diag(rc));
8227c478bd9Sstevel@tonic-gate 		}
8237c478bd9Sstevel@tonic-gate 	}
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate static void
set_exec_mode(void)8277c478bd9Sstevel@tonic-gate set_exec_mode(void)
8287c478bd9Sstevel@tonic-gate {
8297c478bd9Sstevel@tonic-gate 	int rc;
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	if (proto_number == -1) {
8327c478bd9Sstevel@tonic-gate 		if (proto_name == NULL) {
8337c478bd9Sstevel@tonic-gate 			warnx(gettext(
8347c478bd9Sstevel@tonic-gate 			    "Please specify protocol name or number."));
8357c478bd9Sstevel@tonic-gate 			usage();
8367c478bd9Sstevel@tonic-gate 		}
8377c478bd9Sstevel@tonic-gate 		proto_number = getipsecprotobyname(proto_name);
8387c478bd9Sstevel@tonic-gate 		if (proto_number == -1) {
8397c478bd9Sstevel@tonic-gate 			errx(EXIT_FAILURE, gettext("Unknown protocol %s"),
8407c478bd9Sstevel@tonic-gate 			    proto_name);
8417c478bd9Sstevel@tonic-gate 		}
8427c478bd9Sstevel@tonic-gate 	}
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	if ((rc = ipsecproto_set_exec_mode(proto_number, proto_exec_mode))
8457c478bd9Sstevel@tonic-gate 	    != 0) {
8467c478bd9Sstevel@tonic-gate 		errx(EXIT_FAILURE, gettext("Cannot set execution mode: %s"),
8477c478bd9Sstevel@tonic-gate 		    ipsecalgs_diag(rc));
8487c478bd9Sstevel@tonic-gate 	}
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate /*
8527c478bd9Sstevel@tonic-gate  * Print a description of an algorithm to standard output.
8537c478bd9Sstevel@tonic-gate  */
8547c478bd9Sstevel@tonic-gate static void
dump_alg(struct ipsecalgent * alg)8557c478bd9Sstevel@tonic-gate dump_alg(struct ipsecalgent *alg)
8567c478bd9Sstevel@tonic-gate {
8577c478bd9Sstevel@tonic-gate 	int *ifloater;
8587c478bd9Sstevel@tonic-gate 	char **floater;
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	/* protocol number */
8617c478bd9Sstevel@tonic-gate 	(void) printf(gettext("\tProtocol number: %d\n"), alg->a_proto_num);
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	/* algorithm number */
8647c478bd9Sstevel@tonic-gate 	(void) printf(gettext("\tAlgorithm number: %d\n"), alg->a_alg_num);
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	/* algorithm name(s) */
8677c478bd9Sstevel@tonic-gate 	if (alg->a_names != NULL) {
8687c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\tAlgorithm names: "));
8697c478bd9Sstevel@tonic-gate 		floater = alg->a_names;
8707c478bd9Sstevel@tonic-gate 		assert(floater != NULL && *floater != NULL);
8717c478bd9Sstevel@tonic-gate 		do {
8727c478bd9Sstevel@tonic-gate 			/* Assume at least one string. */
8737c478bd9Sstevel@tonic-gate 			(void) printf("%s", *floater);
8747c478bd9Sstevel@tonic-gate 			if (*(++floater) != NULL)
8757c478bd9Sstevel@tonic-gate 				(void) putchar(',');
8767c478bd9Sstevel@tonic-gate 		} while (*floater != NULL);
8777c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
8787c478bd9Sstevel@tonic-gate 	}
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	/* mechanism name */
8817c478bd9Sstevel@tonic-gate 	(void) printf(gettext("\tMechanism Name: %s\n"), alg->a_mech_name);
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	/* block/MAC sizes */
8847c478bd9Sstevel@tonic-gate 	(void) printf(gettext("\tBlock sizes or MAC sizes: "));
8857c478bd9Sstevel@tonic-gate 	ifloater = alg->a_block_sizes;
8867c478bd9Sstevel@tonic-gate 	(void) list_ints(stdout, ifloater);
8877c478bd9Sstevel@tonic-gate 	(void) putchar('\n');
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	/* key sizes */
8907c478bd9Sstevel@tonic-gate 	(void) printf(gettext("\tKey sizes: "));
8917c478bd9Sstevel@tonic-gate 	if (alg->a_key_increment != 0)
8927c478bd9Sstevel@tonic-gate 		/* key specified by range */
8937c478bd9Sstevel@tonic-gate 		(void) printf(gettext(
8947c478bd9Sstevel@tonic-gate 		    "%1$d-%2$d, increment %3$d, default %4$d"),
8957c478bd9Sstevel@tonic-gate 		    alg->a_key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX],
8967c478bd9Sstevel@tonic-gate 		    alg->a_key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX],
8977c478bd9Sstevel@tonic-gate 		    alg->a_key_increment,
8987c478bd9Sstevel@tonic-gate 		    alg->a_key_sizes[LIBIPSEC_ALGS_KEY_DEF_IDX]);
8997c478bd9Sstevel@tonic-gate 	else
9007c478bd9Sstevel@tonic-gate 		/* key specified by enumeration */
9017c478bd9Sstevel@tonic-gate 		(void) list_ints(stdout, alg->a_key_sizes);
9027c478bd9Sstevel@tonic-gate 	(void) putchar('\n');
9037c478bd9Sstevel@tonic-gate 
904*628b0c67SMark Fenwick 	/* Alg parameters */
905*628b0c67SMark Fenwick 	(void) printf(gettext("\tAlgorithm parameters: "));
906*628b0c67SMark Fenwick 	ifloater = alg->a_mech_params;
907*628b0c67SMark Fenwick 	(void) list_ints(stdout, ifloater);
908*628b0c67SMark Fenwick 	(void) putchar('\n');
909*628b0c67SMark Fenwick 
910*628b0c67SMark Fenwick 	/* Alg flags */
911*628b0c67SMark Fenwick 	(void) printf(gettext("\tAlgorithm flags: "));
912*628b0c67SMark Fenwick 	(void) parse_flag(NULL, alg->a_alg_flags);
913*628b0c67SMark Fenwick 
914*628b0c67SMark Fenwick 	(void) putchar('\n');
9157c478bd9Sstevel@tonic-gate 	(void) putchar('\n');
9167c478bd9Sstevel@tonic-gate }
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate /*
9197c478bd9Sstevel@tonic-gate  * Print the description of a protocol.
9207c478bd9Sstevel@tonic-gate  */
9217c478bd9Sstevel@tonic-gate static void
dump_proto(uint_t proto_id)9227c478bd9Sstevel@tonic-gate dump_proto(uint_t proto_id)
9237c478bd9Sstevel@tonic-gate {
9247c478bd9Sstevel@tonic-gate 	char *proto_name;
9257c478bd9Sstevel@tonic-gate 	ipsecalgs_exec_mode_t exec_mode;
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	/* protocol name and number */
9287c478bd9Sstevel@tonic-gate 	proto_name = getipsecprotobynum(proto_id);
9297c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Protocol %1$d/%2$s "),
9307c478bd9Sstevel@tonic-gate 	    proto_id, proto_name != NULL ? proto_name : gettext("<unknown>"));
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	/* execution mode */
9337c478bd9Sstevel@tonic-gate 	(void) printf("(%s", gettext("execution mode: "));
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	if (ipsecproto_get_exec_mode(proto_id, &exec_mode) != 0) {
9367c478bd9Sstevel@tonic-gate 		(void) printf(gettext("<unknown>"));
9377c478bd9Sstevel@tonic-gate 	} else {
9387c478bd9Sstevel@tonic-gate 		switch (exec_mode) {
9397c478bd9Sstevel@tonic-gate 		case LIBIPSEC_ALGS_EXEC_SYNC:
9407c478bd9Sstevel@tonic-gate 			(void) printf("sync");
9417c478bd9Sstevel@tonic-gate 			break;
9427c478bd9Sstevel@tonic-gate 		case LIBIPSEC_ALGS_EXEC_ASYNC:
9437c478bd9Sstevel@tonic-gate 			(void) printf("async");
9447c478bd9Sstevel@tonic-gate 			break;
9457c478bd9Sstevel@tonic-gate 		}
9467c478bd9Sstevel@tonic-gate 	}
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	(void) printf(")\n\n");
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	free(proto_name);
9517c478bd9Sstevel@tonic-gate }
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate /*
9557c478bd9Sstevel@tonic-gate  * Algorithm walker table. Call proto_action() for each protocol,
9567c478bd9Sstevel@tonic-gate  * and alg_action() for each algorithm.
9577c478bd9Sstevel@tonic-gate  */
9587c478bd9Sstevel@tonic-gate static void
algs_walker(void (* alg_action)(struct ipsecalgent *),void (* proto_action)(uint_t))9597c478bd9Sstevel@tonic-gate algs_walker(void (*alg_action)(struct ipsecalgent *),
9607c478bd9Sstevel@tonic-gate     void (*proto_action)(uint_t))
9617c478bd9Sstevel@tonic-gate {
9627c478bd9Sstevel@tonic-gate 	int *proto_nums, proto_count, i;
9637c478bd9Sstevel@tonic-gate 	int *alg_nums, alg_count, j;
9647c478bd9Sstevel@tonic-gate 	struct ipsecalgent *alg;
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	proto_nums = getipsecprotos(&proto_count);
9677c478bd9Sstevel@tonic-gate 	if (proto_nums == NULL) {
9687c478bd9Sstevel@tonic-gate 		errx(EXIT_FAILURE, gettext("getipsecprotos() failed."));
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	for (i = 0; i < proto_count; i++) {
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 		if (proto_action != NULL)
9747c478bd9Sstevel@tonic-gate 			proto_action(proto_nums[i]);
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 		alg_nums = getipsecalgs(&alg_count, proto_nums[i]);
9777c478bd9Sstevel@tonic-gate 		if (alg_nums == NULL) {
9787c478bd9Sstevel@tonic-gate 			free(proto_nums);
9797c478bd9Sstevel@tonic-gate 			errx(EXIT_FAILURE, gettext("getipsecalgs() failed."));
9807c478bd9Sstevel@tonic-gate 		}
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 		for (j = 0; j < alg_count; j++) {
9837c478bd9Sstevel@tonic-gate 			alg = getipsecalgbynum(alg_nums[j], proto_nums[i],
9847c478bd9Sstevel@tonic-gate 			    NULL);
9857c478bd9Sstevel@tonic-gate 			if (alg == NULL)
9867c478bd9Sstevel@tonic-gate 				continue;
9877c478bd9Sstevel@tonic-gate 			if (alg_action != NULL)
9887c478bd9Sstevel@tonic-gate 				alg_action(alg);
9897c478bd9Sstevel@tonic-gate 			freeipsecalgent(alg);
9907c478bd9Sstevel@tonic-gate 		}
9917c478bd9Sstevel@tonic-gate 		free(alg_nums);
9927c478bd9Sstevel@tonic-gate 	}
9937c478bd9Sstevel@tonic-gate 	free(proto_nums);
9947c478bd9Sstevel@tonic-gate }
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate /*
9977c478bd9Sstevel@tonic-gate  * Use just the libnsl/libipsecutil APIs to dump out all of the algorithms.
9987c478bd9Sstevel@tonic-gate  */
9997c478bd9Sstevel@tonic-gate static void
show_algs(void)10007c478bd9Sstevel@tonic-gate show_algs(void)
10017c478bd9Sstevel@tonic-gate {
10027c478bd9Sstevel@tonic-gate 	/* Yes, I'm aware that this'll produce TWO newlines. */
10037c478bd9Sstevel@tonic-gate 	(void) puts(gettext(
10047c478bd9Sstevel@tonic-gate 	    "List of algorithms, grouped by IPsec protocol:\n"));
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	algs_walker(dump_alg, dump_proto);
10077c478bd9Sstevel@tonic-gate }
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate static int
try_int(char * optarg,const char * what)10107c478bd9Sstevel@tonic-gate try_int(char *optarg, const char *what)
10117c478bd9Sstevel@tonic-gate {
10127c478bd9Sstevel@tonic-gate 	int rc = atoi(optarg);
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 	if (rc <= 0) {
10157c478bd9Sstevel@tonic-gate 		warnx(gettext("Invalid %s value"), what);
10167c478bd9Sstevel@tonic-gate 		usage();
10177c478bd9Sstevel@tonic-gate 	}
10187c478bd9Sstevel@tonic-gate 	return (rc);
10197c478bd9Sstevel@tonic-gate }
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate static void
try_cmd(cmd_t newcmd)10227c478bd9Sstevel@tonic-gate try_cmd(cmd_t newcmd)
10237c478bd9Sstevel@tonic-gate {
10247c478bd9Sstevel@tonic-gate 	if (cmd != CMD_NONE)
10257c478bd9Sstevel@tonic-gate 		usage();
10267c478bd9Sstevel@tonic-gate 	cmd = newcmd;
10277c478bd9Sstevel@tonic-gate }
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])10307c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
10317c478bd9Sstevel@tonic-gate {
10327c478bd9Sstevel@tonic-gate 	int c;
1033e3320f40Smarkfen 	zoneid_t zoneid;
1034e3320f40Smarkfen 	ushort_t flags;
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
10377c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
10387c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
10397c478bd9Sstevel@tonic-gate #endif
10407c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	if (argc == 1) {
10437c478bd9Sstevel@tonic-gate 		show_algs();
10447c478bd9Sstevel@tonic-gate 		return (EXIT_SUCCESS);
10457c478bd9Sstevel@tonic-gate 	}
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv,
1048*628b0c67SMark Fenwick 	    "aflrRsb:p:P:i:k:K:m:n:N:e:S:M:I:F:")) != EOF) {
10497c478bd9Sstevel@tonic-gate 		switch (c) {
10507c478bd9Sstevel@tonic-gate 		case 'a':
10517c478bd9Sstevel@tonic-gate 			try_cmd(CMD_ADD);
10527c478bd9Sstevel@tonic-gate 			break;
10537c478bd9Sstevel@tonic-gate 		case 'f':
10547c478bd9Sstevel@tonic-gate 			/* multiple occurences of -f are harmless */
10557c478bd9Sstevel@tonic-gate 			adddel_flags = LIBIPSEC_ALGS_ADD_FORCE;
10567c478bd9Sstevel@tonic-gate 			break;
10577c478bd9Sstevel@tonic-gate 		case 'l':
10587c478bd9Sstevel@tonic-gate 			try_cmd(CMD_LIST_KERNEL);
10597c478bd9Sstevel@tonic-gate 			break;
10607c478bd9Sstevel@tonic-gate 		case 'r':
10617c478bd9Sstevel@tonic-gate 			try_cmd(CMD_DEL);
10627c478bd9Sstevel@tonic-gate 			break;
10637c478bd9Sstevel@tonic-gate 		case 'R':
10647c478bd9Sstevel@tonic-gate 			try_cmd(CMD_DEL_PROTO);
10657c478bd9Sstevel@tonic-gate 			break;
10667c478bd9Sstevel@tonic-gate 		case 's':
10677c478bd9Sstevel@tonic-gate 			/* multiple occurences of -s are harmless */
10687c478bd9Sstevel@tonic-gate 			synch_kernel = B_TRUE;
10697c478bd9Sstevel@tonic-gate 			break;
10707c478bd9Sstevel@tonic-gate 		case 'n':
10717c478bd9Sstevel@tonic-gate 			if (alg_names_string != NULL)
10727c478bd9Sstevel@tonic-gate 				usage();
10737c478bd9Sstevel@tonic-gate 			alg_names_string = optarg;
10747c478bd9Sstevel@tonic-gate 			break;
10757c478bd9Sstevel@tonic-gate 		case 'b':
10767c478bd9Sstevel@tonic-gate 			if (block_sizes_string != NULL)
10777c478bd9Sstevel@tonic-gate 				usage();
10787c478bd9Sstevel@tonic-gate 			block_sizes_string = optarg;
10797c478bd9Sstevel@tonic-gate 			break;
10807c478bd9Sstevel@tonic-gate 		case 'p':
10817c478bd9Sstevel@tonic-gate 			if (proto_name != NULL)
10827c478bd9Sstevel@tonic-gate 				usage();
10837c478bd9Sstevel@tonic-gate 			proto_name = optarg;
10847c478bd9Sstevel@tonic-gate 			break;
10857c478bd9Sstevel@tonic-gate 		case 'P':
10867c478bd9Sstevel@tonic-gate 			if (proto_number != -1)
10877c478bd9Sstevel@tonic-gate 				usage();
10887c478bd9Sstevel@tonic-gate 			proto_number = try_int(optarg,
10897c478bd9Sstevel@tonic-gate 			    gettext("protocol number"));
10907c478bd9Sstevel@tonic-gate 			break;
10917c478bd9Sstevel@tonic-gate 		case 'e':
10927c478bd9Sstevel@tonic-gate 			if (exec_mode_string != NULL)
10937c478bd9Sstevel@tonic-gate 				usage();
10947c478bd9Sstevel@tonic-gate 			exec_mode_string = optarg;
10957c478bd9Sstevel@tonic-gate 			if (_str_to_ipsec_exec_mode(exec_mode_string,
10967c478bd9Sstevel@tonic-gate 			    &proto_exec_mode) == -1) {
10977c478bd9Sstevel@tonic-gate 				warnx(gettext("Invalid execution mode \"%s\""),
10987c478bd9Sstevel@tonic-gate 				    exec_mode_string);
10997c478bd9Sstevel@tonic-gate 				usage();
11007c478bd9Sstevel@tonic-gate 			}
11017c478bd9Sstevel@tonic-gate 			break;
11027c478bd9Sstevel@tonic-gate 		case 'i':
11037c478bd9Sstevel@tonic-gate 			if (increment != 0)
11047c478bd9Sstevel@tonic-gate 				usage();
11057c478bd9Sstevel@tonic-gate 			increment = try_int(optarg,
11067c478bd9Sstevel@tonic-gate 			    gettext("key size increment"));
11077c478bd9Sstevel@tonic-gate 			break;
11087c478bd9Sstevel@tonic-gate 		case 'k':
11097c478bd9Sstevel@tonic-gate 			if (key_sizes_string != NULL)
11107c478bd9Sstevel@tonic-gate 				usage();
11117c478bd9Sstevel@tonic-gate 			key_sizes_string = optarg;
11127c478bd9Sstevel@tonic-gate 			break;
11137c478bd9Sstevel@tonic-gate 		case 'K':
11147c478bd9Sstevel@tonic-gate 			if (default_keylen != 0)
11157c478bd9Sstevel@tonic-gate 				usage();
11167c478bd9Sstevel@tonic-gate 			default_keylen = try_int(optarg,
11177c478bd9Sstevel@tonic-gate 			    gettext("default key size"));
11187c478bd9Sstevel@tonic-gate 			break;
11197c478bd9Sstevel@tonic-gate 		case 'm':
11207c478bd9Sstevel@tonic-gate 			if (mech_name != NULL)
11217c478bd9Sstevel@tonic-gate 				usage();
11227c478bd9Sstevel@tonic-gate 			mech_name = optarg;
11237c478bd9Sstevel@tonic-gate 			break;
11247c478bd9Sstevel@tonic-gate 		case 'N':
11257c478bd9Sstevel@tonic-gate 			if (alg_number != -1)
11267c478bd9Sstevel@tonic-gate 				usage();
11277c478bd9Sstevel@tonic-gate 			alg_number = try_int(optarg,
11287c478bd9Sstevel@tonic-gate 			    gettext("algorithm number"));
11297c478bd9Sstevel@tonic-gate 			break;
1130*628b0c67SMark Fenwick 		case 'I':
1131*628b0c67SMark Fenwick 			if (mech_params[iv_len] != 0)
1132*628b0c67SMark Fenwick 				usage();
1133*628b0c67SMark Fenwick 			mech_params[iv_len] = try_int(optarg,
1134*628b0c67SMark Fenwick 			    gettext("Initialization Vector length"));
1135*628b0c67SMark Fenwick 			break;
1136*628b0c67SMark Fenwick 		case 'M':
1137*628b0c67SMark Fenwick 			if (mech_params[mac_len] != 0)
1138*628b0c67SMark Fenwick 				usage();
1139*628b0c67SMark Fenwick 			mech_params[mac_len] = try_int(optarg,
1140*628b0c67SMark Fenwick 			    gettext("Integrity Check Vector length"));
1141*628b0c67SMark Fenwick 			break;
1142*628b0c67SMark Fenwick 		case 'S':
1143*628b0c67SMark Fenwick 			if (mech_params[salt_bytes] != 0)
1144*628b0c67SMark Fenwick 				usage();
1145*628b0c67SMark Fenwick 			mech_params[salt_bytes] = try_int(optarg,
1146*628b0c67SMark Fenwick 			    gettext("Salt length"));
1147*628b0c67SMark Fenwick 			break;
1148*628b0c67SMark Fenwick 		case 'F':
1149*628b0c67SMark Fenwick 			/*
1150*628b0c67SMark Fenwick 			 * Multiple flags can be specified, the results
1151*628b0c67SMark Fenwick 			 * are OR'd together.  Flags can be specified as
1152*628b0c67SMark Fenwick 			 * number or  a comma separated string
1153*628b0c67SMark Fenwick 			 */
1154*628b0c67SMark Fenwick 			flags = atoi(optarg);
1155*628b0c67SMark Fenwick 			if (flags) {
1156*628b0c67SMark Fenwick 				alg_flags |= flags;
1157*628b0c67SMark Fenwick 				flag_string = NULL;
1158*628b0c67SMark Fenwick 			} else {
1159*628b0c67SMark Fenwick 				flag_string = optarg;
1160*628b0c67SMark Fenwick 			}
1161*628b0c67SMark Fenwick 			break;
1162*628b0c67SMark Fenwick 		default:
1163*628b0c67SMark Fenwick 			usage();
11647c478bd9Sstevel@tonic-gate 		}
11657c478bd9Sstevel@tonic-gate 	}
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 	/*
11687c478bd9Sstevel@tonic-gate 	 * When both protocol name (-p) and protocol number (-P) are
11697c478bd9Sstevel@tonic-gate 	 * specified, a new protocol is being defined.
11707c478bd9Sstevel@tonic-gate 	 */
11717c478bd9Sstevel@tonic-gate 	if (proto_number != -1 && proto_name != NULL)
11727c478bd9Sstevel@tonic-gate 		try_cmd(CMD_ADD_PROTO);
11737c478bd9Sstevel@tonic-gate 	else if (exec_mode_string != NULL)
11747c478bd9Sstevel@tonic-gate 		try_cmd(CMD_EXEC_MODE);
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	/*
11777c478bd9Sstevel@tonic-gate 	 * Process specified command.
11787c478bd9Sstevel@tonic-gate 	 */
11797c478bd9Sstevel@tonic-gate 	switch (cmd) {
11807c478bd9Sstevel@tonic-gate 	case CMD_ADD:
11817c478bd9Sstevel@tonic-gate 		new_alg();
11827c478bd9Sstevel@tonic-gate 		break;
11837c478bd9Sstevel@tonic-gate 	case CMD_ADD_PROTO:
11847c478bd9Sstevel@tonic-gate 		new_proto();
11857c478bd9Sstevel@tonic-gate 		break;
11867c478bd9Sstevel@tonic-gate 	case CMD_DEL:
11877c478bd9Sstevel@tonic-gate 		remove_alg();
11887c478bd9Sstevel@tonic-gate 		break;
11897c478bd9Sstevel@tonic-gate 	case CMD_DEL_PROTO:
11907c478bd9Sstevel@tonic-gate 		remove_proto();
11917c478bd9Sstevel@tonic-gate 		break;
11927c478bd9Sstevel@tonic-gate 	case CMD_EXEC_MODE:
11937c478bd9Sstevel@tonic-gate 		set_exec_mode();
11947c478bd9Sstevel@tonic-gate 		break;
11957c478bd9Sstevel@tonic-gate 	case CMD_LIST_KERNEL:
11967c478bd9Sstevel@tonic-gate 		if (synch_kernel)
11977c478bd9Sstevel@tonic-gate 			usage();
11987c478bd9Sstevel@tonic-gate 		list_kernel_algs();
11997c478bd9Sstevel@tonic-gate 		break;
12007c478bd9Sstevel@tonic-gate 	default:
12017c478bd9Sstevel@tonic-gate 		if (!synch_kernel)
12027c478bd9Sstevel@tonic-gate 			usage();
12037c478bd9Sstevel@tonic-gate 	}
12047c478bd9Sstevel@tonic-gate 
1205e3320f40Smarkfen 	if (synch_kernel) {
1206e3320f40Smarkfen 		/*
1207e3320f40Smarkfen 		 * This will only work in the global zone or
1208e3320f40Smarkfen 		 * a zone with an exclusive IP stack.
1209e3320f40Smarkfen 		 */
1210e3320f40Smarkfen 		if ((zoneid = getzoneid()) == 0) {
1211e3320f40Smarkfen 			kernel_synch();
1212e3320f40Smarkfen 		} else {
1213e3320f40Smarkfen 			if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
1214e3320f40Smarkfen 			    sizeof (flags)) < 0) {
1215e3320f40Smarkfen 				err(EXIT_FAILURE, gettext(
1216e3320f40Smarkfen 				    "Unable to determine zone IP type"));
1217e3320f40Smarkfen 			}
1218e3320f40Smarkfen 			if (flags & ZF_NET_EXCL) {
1219e3320f40Smarkfen 				kernel_synch();
1220e3320f40Smarkfen 			} else {
1221e3320f40Smarkfen 				(void) printf(gettext("Synchronization with "
1222e3320f40Smarkfen 				    "kernel not appropriate in this zone.\n"));
1223e3320f40Smarkfen 			}
1224e3320f40Smarkfen 		}
1225e3320f40Smarkfen 	}
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	return (EXIT_SUCCESS);
12287c478bd9Sstevel@tonic-gate }
1229