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