xref: /onnv-gate/usr/src/lib/libipsecutil/common/algs.c (revision 10824:c47254a96e5d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51519Sdanmcd  * Common Development and Distribution License (the "License").
61519Sdanmcd  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*10824SMark.Fenwick@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/stat.h>
280Sstevel@tonic-gate #include <ipsec_util.h>
290Sstevel@tonic-gate #include <stdlib.h>
300Sstevel@tonic-gate #include <strings.h>
310Sstevel@tonic-gate #include <netdb.h>
320Sstevel@tonic-gate #include <fcntl.h>
330Sstevel@tonic-gate #include <unistd.h>
340Sstevel@tonic-gate #include <libintl.h>
350Sstevel@tonic-gate #include <errno.h>
360Sstevel@tonic-gate 
370Sstevel@tonic-gate static char *preamble =
380Sstevel@tonic-gate "# /etc/inet/ipsecalgs output from ipsecalgs(1m)\n"
390Sstevel@tonic-gate "#\n"
400Sstevel@tonic-gate "# DO NOT EDIT OR PARSE THIS FILE!\n"
410Sstevel@tonic-gate "#\n"
420Sstevel@tonic-gate "# Use the ipsecalgs(1m) command to change the contents of this file.\n"
43*10824SMark.Fenwick@Sun.COM "# The algorithm descriptions contained in this file are synchronised to the\n"
44*10824SMark.Fenwick@Sun.COM "# kernel with ipsecalgs -s, the kernel validates the entries at this point."
45*10824SMark.Fenwick@Sun.COM "\n\n"
46*10824SMark.Fenwick@Sun.COM "# PROTO|protocol-id|protocol-name|exec-mode\n"
47*10824SMark.Fenwick@Sun.COM "##  NOTE:  Some protocol numbers are well-known and defined in <netdb.h>\n\n"
48*10824SMark.Fenwick@Sun.COM "# ALG|protocol-id|alg-id|name,name,...|ef-id| \n"
49*10824SMark.Fenwick@Sun.COM "#        {default/}{key,key..}or{key-key,inc}|block_size or MAC-size|\n"
50*10824SMark.Fenwick@Sun.COM "#        [parameter,parameter..]|[flags]\n\n"
51*10824SMark.Fenwick@Sun.COM "#\n"
52*10824SMark.Fenwick@Sun.COM "## Note:   Parameters and flags only apply to certain algorithms.\n\n";
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #define	CFG_PERMS S_IRUSR | S_IRGRP | S_IROTH	/* Perms 0444. */
550Sstevel@tonic-gate #define	CFG_OWNER 0	/* root */
560Sstevel@tonic-gate #define	CFG_GROUP 1	/* "other" */
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate  * write_new_algfile() helper macros to check for write errors.
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate 
620Sstevel@tonic-gate #define	FPRINTF_ERR(fcall) if ((fcall) < 0) {	\
630Sstevel@tonic-gate 	rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;	\
640Sstevel@tonic-gate 	goto bail;				\
650Sstevel@tonic-gate }
660Sstevel@tonic-gate 
670Sstevel@tonic-gate #define	FPUT_ERR(fcall) if ((fcall) == EOF) {	\
680Sstevel@tonic-gate 	rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;	\
690Sstevel@tonic-gate 	goto bail;				\
700Sstevel@tonic-gate }
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate  * Helper macros to start and finish a list of entries that were added
740Sstevel@tonic-gate  * as part of a package installation.
750Sstevel@tonic-gate  */
760Sstevel@tonic-gate 
770Sstevel@tonic-gate #define	PKG_SEC_START(pkgname, doing_pkg, cur_pkg) {		\
780Sstevel@tonic-gate 	(void) strcpy((cur_pkg), (pkgname));			\
790Sstevel@tonic-gate 	FPRINTF_ERR(fprintf(f, "%s%s\n",			\
800Sstevel@tonic-gate 	    LIBIPSEC_ALGS_LINE_PKGSTART, (cur_pkg)));		\
810Sstevel@tonic-gate 	(doing_pkg) = B_TRUE;					\
820Sstevel@tonic-gate }
830Sstevel@tonic-gate 
840Sstevel@tonic-gate #define	PKG_SEC_END(doing_pkg, cur_pkg) {			\
850Sstevel@tonic-gate 	if (doing_pkg) {					\
860Sstevel@tonic-gate 		FPRINTF_ERR(fprintf(f, "%s%s\n",		\
870Sstevel@tonic-gate 		    LIBIPSEC_ALGS_LINE_PKGEND, (cur_pkg)));	\
880Sstevel@tonic-gate 		(doing_pkg) = B_FALSE;				\
890Sstevel@tonic-gate 	}							\
900Sstevel@tonic-gate }
910Sstevel@tonic-gate 
920Sstevel@tonic-gate /*
930Sstevel@tonic-gate  * Take a zero-terminated int array and print int1,int2...,intN.
940Sstevel@tonic-gate  * If zero-only, then print a single '0'.
950Sstevel@tonic-gate  * Returns 0 on success, -1 if an error occurred while writing to
960Sstevel@tonic-gate  * the specified file.
970Sstevel@tonic-gate  */
980Sstevel@tonic-gate int
list_ints(FILE * f,int * floater)990Sstevel@tonic-gate list_ints(FILE *f, int *floater)
1000Sstevel@tonic-gate {
1010Sstevel@tonic-gate 	boolean_t executed = B_FALSE;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	while (*floater != 0) {
1040Sstevel@tonic-gate 		executed = B_TRUE;
1050Sstevel@tonic-gate 		if (fprintf(f, "%d", *floater) < 0)
1060Sstevel@tonic-gate 			return (-1);
1070Sstevel@tonic-gate 		if (*(++floater) != 0)
1080Sstevel@tonic-gate 			if (fputc(',', f) == EOF)
1090Sstevel@tonic-gate 				return (-1);
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	if (!executed)
1130Sstevel@tonic-gate 		if (fputc('0', f) == EOF)
1140Sstevel@tonic-gate 			return (-1);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	return (0);
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate /*
1200Sstevel@tonic-gate  * If the specified algorithm was defined within a package section, i.e.
1210Sstevel@tonic-gate  * between the lines "# Start <pkgname>" and "# End <pkgname>", returns
1220Sstevel@tonic-gate  * the value of <pkgname>.
1230Sstevel@tonic-gate  */
1240Sstevel@tonic-gate static char *
alg_has_pkg(ipsec_proto_t * proto,struct ipsecalgent * alg)1250Sstevel@tonic-gate alg_has_pkg(ipsec_proto_t *proto, struct ipsecalgent *alg)
1260Sstevel@tonic-gate {
1270Sstevel@tonic-gate 	int i;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	if (proto->proto_algs_pkgs == NULL)
1300Sstevel@tonic-gate 		return (NULL);
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 	for (i = 0; i < proto->proto_algs_npkgs; i++)
1330Sstevel@tonic-gate 		if (proto->proto_algs_pkgs[i].alg_num == alg->a_alg_num)
1340Sstevel@tonic-gate 			return (proto->proto_algs_pkgs[i].pkg_name);
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	return (NULL);
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate /*
1400Sstevel@tonic-gate  * Writes the package start/end delimiters according to the package
1410Sstevel@tonic-gate  * name associated with the current protocol or algorithm, and
1420Sstevel@tonic-gate  * the state of the packaging information already written to the file.
1430Sstevel@tonic-gate  * Called by write_new_algfile(). Returns 0 on success, one of the
1440Sstevel@tonic-gate  * LIBIPSEC_DIAG codes on failure.
1450Sstevel@tonic-gate  */
1460Sstevel@tonic-gate static int
pkg_section(FILE * f,char * pkg_name,boolean_t * doing_pkg,char * cur_pkg)1470Sstevel@tonic-gate pkg_section(FILE *f, char *pkg_name, boolean_t *doing_pkg, char *cur_pkg)
1480Sstevel@tonic-gate {
1490Sstevel@tonic-gate 	int rc = 0;
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	if (pkg_name != NULL) {
1520Sstevel@tonic-gate 		/* protocol or algorithm is associated with a package */
1530Sstevel@tonic-gate 		if (!*doing_pkg) {
1540Sstevel@tonic-gate 			/* start of a new package section */
1550Sstevel@tonic-gate 			PKG_SEC_START(pkg_name, *doing_pkg, cur_pkg);
1560Sstevel@tonic-gate 		} else {
1570Sstevel@tonic-gate 			/* already in a package section */
1580Sstevel@tonic-gate 			if (strcmp(pkg_name, cur_pkg) != 0) {
1590Sstevel@tonic-gate 				/* different package name */
1600Sstevel@tonic-gate 				PKG_SEC_END(*doing_pkg, cur_pkg);
1610Sstevel@tonic-gate 				PKG_SEC_START(pkg_name, *doing_pkg, cur_pkg);
1620Sstevel@tonic-gate 			}
1630Sstevel@tonic-gate 		}
1640Sstevel@tonic-gate 	} else if (*doing_pkg) {
1650Sstevel@tonic-gate 		/* in a package section when the entry isn't */
1660Sstevel@tonic-gate 		PKG_SEC_END(*doing_pkg, cur_pkg);
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate bail:
1690Sstevel@tonic-gate 	return (rc);
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate /*
1730Sstevel@tonic-gate  * Given a list of protocols and number, write them to a new algorithm file.
1740Sstevel@tonic-gate  * This function takes num_protos + num_protos * dois-per-alg operations.
1750Sstevel@tonic-gate  * Also free the protocol structure.
1760Sstevel@tonic-gate  *
1770Sstevel@tonic-gate  * Note that no locking spans the read/update/write phases that can be
1780Sstevel@tonic-gate  * used by callers of this routine. This could cause this function to suffer
1790Sstevel@tonic-gate  * from the "lost update" problem. Since updates to the IPsec protocols
1800Sstevel@tonic-gate  * and algorithm tables are very infrequent, this should not be a issue in
1810Sstevel@tonic-gate  * practice.
1820Sstevel@tonic-gate  */
1830Sstevel@tonic-gate static int
write_new_algfile(ipsec_proto_t * protos,int num_protos)1840Sstevel@tonic-gate write_new_algfile(ipsec_proto_t *protos, int num_protos)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	FILE *f;
1870Sstevel@tonic-gate 	int fd, i, j, k;
1880Sstevel@tonic-gate 	int rc = 0;
1890Sstevel@tonic-gate 	struct ipsecalgent *alg;
1900Sstevel@tonic-gate 	char cur_pkg[1024];
1910Sstevel@tonic-gate 	boolean_t doing_pkg = B_FALSE;
1920Sstevel@tonic-gate 	char *alg_pkg;
1931519Sdanmcd 	char tmp_name_template[] = INET_IPSECALGSPATH "ipsecalgsXXXXXX";
1940Sstevel@tonic-gate 	char *tmp_name;
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	/*
1970Sstevel@tonic-gate 	 * In order to avoid potentially corrupting the configuration
1980Sstevel@tonic-gate 	 * file on file system failure, write the new configuration info
1990Sstevel@tonic-gate 	 * to a temporary file which is then renamed to the configuration
2000Sstevel@tonic-gate 	 * file (INET_IPSECALGSFILE.)
2010Sstevel@tonic-gate 	 */
2020Sstevel@tonic-gate 	tmp_name = mktemp(tmp_name_template);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	fd = open(tmp_name, O_WRONLY|O_CREAT|O_EXCL, CFG_PERMS);
2050Sstevel@tonic-gate 	if (fd == -1) {
2060Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILEOPEN;
2070Sstevel@tonic-gate 		goto bail;
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	f = fdopen(fd, "w");
2110Sstevel@tonic-gate 	if (f == NULL) {
2120Sstevel@tonic-gate 		(void) close(fd);
2130Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILEFDOPEN;
2140Sstevel@tonic-gate 		goto bail;
2150Sstevel@tonic-gate 	}
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	FPUT_ERR(fputs(preamble, f));
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	/* Write protocol entries. */
2200Sstevel@tonic-gate 	for (i = 0; i < num_protos; i++) {
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 		/* add package section delimiters if needed */
2230Sstevel@tonic-gate 		rc = pkg_section(f, protos[i].proto_pkg, &doing_pkg, cur_pkg);
2240Sstevel@tonic-gate 		if (rc != 0)
2250Sstevel@tonic-gate 			goto bail;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 		FPRINTF_ERR(fprintf(f, "%s%d|%s|",
2280Sstevel@tonic-gate 		    LIBIPSEC_ALGS_LINE_PROTO,
2290Sstevel@tonic-gate 		    protos[i].proto_num, protos[i].proto_name));
2300Sstevel@tonic-gate 		switch (protos[i].proto_exec_mode) {
2310Sstevel@tonic-gate 		case LIBIPSEC_ALGS_EXEC_SYNC:
2320Sstevel@tonic-gate 			FPRINTF_ERR(fprintf(f, "sync\n"));
2330Sstevel@tonic-gate 			break;
2340Sstevel@tonic-gate 		case LIBIPSEC_ALGS_EXEC_ASYNC:
2350Sstevel@tonic-gate 			FPRINTF_ERR(fprintf(f, "async\n"));
2360Sstevel@tonic-gate 			break;
2370Sstevel@tonic-gate 		}
2380Sstevel@tonic-gate 	}
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	/* terminate the package section for the protocols if needed */
2410Sstevel@tonic-gate 	PKG_SEC_END(doing_pkg, cur_pkg);
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	FPUT_ERR(fputs("\n", f));
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	/* Write algorithm entries. */
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	for (i = 0; i < num_protos; i++) {
2480Sstevel@tonic-gate 		for (j = 0; j < protos[i].proto_numalgs; j++) {
2490Sstevel@tonic-gate 			alg = protos[i].proto_algs[j];
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 			/* add package section delimiters if needed */
2520Sstevel@tonic-gate 			alg_pkg = alg_has_pkg(&protos[i], alg);
2530Sstevel@tonic-gate 			rc = pkg_section(f, alg_pkg, &doing_pkg, cur_pkg);
2540Sstevel@tonic-gate 			if (rc != 0)
2550Sstevel@tonic-gate 				goto bail;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 			/* protocol and algorithm numbers */
2580Sstevel@tonic-gate 			FPRINTF_ERR(fprintf(f, "%s%d|%d|",
2590Sstevel@tonic-gate 			    LIBIPSEC_ALGS_LINE_ALG,
2600Sstevel@tonic-gate 			    alg->a_proto_num, alg->a_alg_num));
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 			/* algorithm names */
2630Sstevel@tonic-gate 			for (k = 0; alg->a_names[k] != NULL; k++) {
2640Sstevel@tonic-gate 				FPRINTF_ERR(fprintf(f, "%s", alg->a_names[k]));
2650Sstevel@tonic-gate 				if (alg->a_names[k+1] != NULL)
2660Sstevel@tonic-gate 					FPRINTF_ERR(fprintf(f, ","));
2670Sstevel@tonic-gate 			}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 			/* mechanism name */
2700Sstevel@tonic-gate 			FPRINTF_ERR(fprintf(f, "|%s|", alg->a_mech_name));
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 			/* key sizes */
2730Sstevel@tonic-gate 			if (alg->a_key_increment == 0) {
2740Sstevel@tonic-gate 				/* key sizes defined by enumeration */
2750Sstevel@tonic-gate 				if (list_ints(f, alg->a_key_sizes) == -1) {
2760Sstevel@tonic-gate 					rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;
2770Sstevel@tonic-gate 					goto bail;
2780Sstevel@tonic-gate 				}
2790Sstevel@tonic-gate 			} else {
2800Sstevel@tonic-gate 				/* key sizes defined by range */
2810Sstevel@tonic-gate 				FPRINTF_ERR(fprintf(f, "%d/%d-%d,%d",
2820Sstevel@tonic-gate 				    alg->a_key_sizes[0], alg->a_key_sizes[1],
2830Sstevel@tonic-gate 				    alg->a_key_sizes[2], alg->a_key_increment));
2840Sstevel@tonic-gate 			}
2850Sstevel@tonic-gate 			FPUT_ERR(fputc('|', f));
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 			/* block sizes */
2880Sstevel@tonic-gate 			if (list_ints(f, alg->a_block_sizes) == -1) {
2890Sstevel@tonic-gate 				rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;
2900Sstevel@tonic-gate 				goto bail;
2910Sstevel@tonic-gate 			}
292*10824SMark.Fenwick@Sun.COM 			FPUT_ERR(fputc('|', f));
293*10824SMark.Fenwick@Sun.COM 
294*10824SMark.Fenwick@Sun.COM 			/*
295*10824SMark.Fenwick@Sun.COM 			 * Some algorithms require extra parameters, these
296*10824SMark.Fenwick@Sun.COM 			 * are stored in an array. For algorithms that don't
297*10824SMark.Fenwick@Sun.COM 			 * need these parameters, or flags (below), these
298*10824SMark.Fenwick@Sun.COM 			 * extra fields in the ipsecalgs file must contain a
299*10824SMark.Fenwick@Sun.COM 			 * zero. This fuction will get called if a algorithm
300*10824SMark.Fenwick@Sun.COM 			 * entry is added, at this point the extra fields will
301*10824SMark.Fenwick@Sun.COM 			 * be added to the file.
302*10824SMark.Fenwick@Sun.COM 			 */
303*10824SMark.Fenwick@Sun.COM 			if (list_ints(f, alg->a_mech_params) == -1) {
304*10824SMark.Fenwick@Sun.COM 				rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;
305*10824SMark.Fenwick@Sun.COM 				goto bail;
306*10824SMark.Fenwick@Sun.COM 			}
307*10824SMark.Fenwick@Sun.COM 			/* flags */
308*10824SMark.Fenwick@Sun.COM 			FPRINTF_ERR(fprintf(f, "|%d\n", alg->a_alg_flags));
3090Sstevel@tonic-gate 		}
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	/* terminate the package section for the algorithms if needed */
3130Sstevel@tonic-gate 	PKG_SEC_END(doing_pkg, cur_pkg);
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	if (fchmod(fd, CFG_PERMS) == -1) {
3160Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILECHMOD;
3170Sstevel@tonic-gate 		goto bail;
3180Sstevel@tonic-gate 	}
3190Sstevel@tonic-gate 	if (fchown(fd, CFG_OWNER, CFG_GROUP) == -1) {
3200Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILECHOWN;
3210Sstevel@tonic-gate 		goto bail;
3220Sstevel@tonic-gate 	}
3230Sstevel@tonic-gate 	if (fclose(f) == EOF) {
3240Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILECLOSE;
3250Sstevel@tonic-gate 		goto bail;
3260Sstevel@tonic-gate 	}
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	if (rename(tmp_name, INET_IPSECALGSFILE) == -1)
3290Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILERENAME;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate bail:
3320Sstevel@tonic-gate 	_clean_trash(protos, num_protos);
3330Sstevel@tonic-gate 	return (rc);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate /*
3370Sstevel@tonic-gate  * Return a pointer to the protocol entry corresponding to the specified
3380Sstevel@tonic-gate  * protocol num proto_num. Also builds the list of currently defined
3390Sstevel@tonic-gate  * protocols.
3400Sstevel@tonic-gate  */
3410Sstevel@tonic-gate static ipsec_proto_t *
proto_setup(ipsec_proto_t ** protos,int * num_protos,int proto_num,boolean_t cleanup)3420Sstevel@tonic-gate proto_setup(ipsec_proto_t **protos, int *num_protos, int proto_num,
3430Sstevel@tonic-gate     boolean_t cleanup)
3440Sstevel@tonic-gate {
3450Sstevel@tonic-gate 	int i;
3460Sstevel@tonic-gate 	ipsec_proto_t *current_proto, *ret_proto = NULL;
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	_build_internal_algs(protos, num_protos);
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	if (*protos == NULL)
3510Sstevel@tonic-gate 		return (NULL);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	for (i = 0; i < *num_protos; i++) {
3540Sstevel@tonic-gate 		current_proto = (*protos) + i;
3550Sstevel@tonic-gate 		if (current_proto->proto_num == proto_num) {
3560Sstevel@tonic-gate 			ret_proto = current_proto;
3570Sstevel@tonic-gate 			break;
3580Sstevel@tonic-gate 		}
3590Sstevel@tonic-gate 	}
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	if (ret_proto == NULL) {
3620Sstevel@tonic-gate 		if (cleanup)
3630Sstevel@tonic-gate 			_clean_trash(*protos, *num_protos);
3640Sstevel@tonic-gate 		/* else caller wants parsed /etc/inet/ipsecalgs anyway */
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	return (ret_proto);
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate /*
3710Sstevel@tonic-gate  * Delete the first found algorithm of the specified protocol which
3720Sstevel@tonic-gate  * has the same name as the one specified by alg_name. Deletion of
3730Sstevel@tonic-gate  * the entry takes place only if the delete_it flag is set. If an
3740Sstevel@tonic-gate  * entry was found, return B_TRUE, otherwise return B_FALSE.
3750Sstevel@tonic-gate  */
3760Sstevel@tonic-gate static boolean_t
delipsecalgbyname_common(const char * name,ipsec_proto_t * proto,boolean_t delete_it)3770Sstevel@tonic-gate delipsecalgbyname_common(const char *name, ipsec_proto_t *proto,
3780Sstevel@tonic-gate     boolean_t delete_it)
3790Sstevel@tonic-gate {
3800Sstevel@tonic-gate 	int i;
3810Sstevel@tonic-gate 	char **name_check;
3820Sstevel@tonic-gate 	boolean_t found_match = B_FALSE;
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	for (i = 0; i < proto->proto_numalgs; i++) {
3850Sstevel@tonic-gate 		if (!found_match) {
3860Sstevel@tonic-gate 			for (name_check =
3870Sstevel@tonic-gate 			    proto->proto_algs[i]->a_names;
3880Sstevel@tonic-gate 			    *name_check != NULL; name_check++) {
3890Sstevel@tonic-gate 				/*
3900Sstevel@tonic-gate 				 * Can use strcmp because the algorithm names
3910Sstevel@tonic-gate 				 * are bound.
3920Sstevel@tonic-gate 				 */
3930Sstevel@tonic-gate 				if (strcmp(*name_check, name) == 0) {
3940Sstevel@tonic-gate 					found_match = B_TRUE;
3950Sstevel@tonic-gate 					if (!delete_it)
3960Sstevel@tonic-gate 						return (found_match);
3970Sstevel@tonic-gate 					freeipsecalgent(proto->proto_algs[i]);
3980Sstevel@tonic-gate 					break;
3990Sstevel@tonic-gate 				}
4000Sstevel@tonic-gate 			}
4010Sstevel@tonic-gate 		} else {
4020Sstevel@tonic-gate 			proto->proto_algs[i - 1] = proto->proto_algs[i];
4030Sstevel@tonic-gate 		}
4040Sstevel@tonic-gate 	}
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	if (found_match)
4070Sstevel@tonic-gate 		proto->proto_numalgs--;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	return (found_match);
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate /*
4130Sstevel@tonic-gate  * Returns B_TRUE if the specified 0-terminated lists of key or
4140Sstevel@tonic-gate  * block sizes match, B_FALSE otherwise.
4150Sstevel@tonic-gate  */
4160Sstevel@tonic-gate static boolean_t
sizes_match(int * a1,int * a2)4170Sstevel@tonic-gate sizes_match(int *a1, int *a2)
4180Sstevel@tonic-gate {
4190Sstevel@tonic-gate 	int i;
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	for (i = 0; (a1[i] != 0) && (a2[i] != 0); i++) {
4220Sstevel@tonic-gate 		if (a1[i] != a2[i])
4230Sstevel@tonic-gate 			return (B_FALSE);
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 	if ((a1[i] != 0) || (a2[i] != 0))
4260Sstevel@tonic-gate 		return (B_FALSE);
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	return (B_TRUE);
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate /*
4320Sstevel@tonic-gate  * Returns B_TRUE if an _exact_ equivalent of the specified algorithm
4330Sstevel@tonic-gate  * already exists, B_FALSE otherwise.
4340Sstevel@tonic-gate  */
4350Sstevel@tonic-gate static boolean_t
ipsecalg_exists(struct ipsecalgent * newbie,ipsec_proto_t * proto)4360Sstevel@tonic-gate ipsecalg_exists(struct ipsecalgent *newbie, ipsec_proto_t *proto)
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate 	struct ipsecalgent *curalg;
4390Sstevel@tonic-gate 	char **curname, **newbiename;
4400Sstevel@tonic-gate 	int i;
4410Sstevel@tonic-gate 	boolean_t match;
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	for (i = 0; i < proto->proto_numalgs; i++) {
4440Sstevel@tonic-gate 		curalg = proto->proto_algs[i];
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 		if (curalg->a_alg_num != newbie->a_alg_num)
4470Sstevel@tonic-gate 			continue;
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 		if (curalg->a_key_increment != newbie->a_key_increment)
4500Sstevel@tonic-gate 			continue;
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 		if (strcmp(curalg->a_mech_name, newbie->a_mech_name) != 0)
4530Sstevel@tonic-gate 			continue;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 		curname = curalg->a_names;
4560Sstevel@tonic-gate 		newbiename = newbie->a_names;
4570Sstevel@tonic-gate 		match = B_TRUE;
4580Sstevel@tonic-gate 		while ((*curname != NULL) && (*newbiename != NULL) && match) {
4590Sstevel@tonic-gate 			match = (strcmp(*curname, *newbiename) == 0);
4600Sstevel@tonic-gate 			curname++;
4610Sstevel@tonic-gate 			newbiename++;
4620Sstevel@tonic-gate 		}
4630Sstevel@tonic-gate 		if (!match || (*curname != NULL) || (*newbiename != NULL))
4640Sstevel@tonic-gate 			continue;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 		if (!sizes_match(curalg->a_block_sizes, newbie->a_block_sizes))
4670Sstevel@tonic-gate 			continue;
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 		if (!sizes_match(curalg->a_key_sizes, newbie->a_key_sizes))
4700Sstevel@tonic-gate 			continue;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 		/* we found an exact match */
4730Sstevel@tonic-gate 		return (B_TRUE);
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	return (B_FALSE);
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate /*
4800Sstevel@tonic-gate  * Add a new algorithm to the /etc/inet/ipsecalgs file.  Caller must free
4810Sstevel@tonic-gate  * or otherwise address "newbie".
4820Sstevel@tonic-gate  */
4830Sstevel@tonic-gate int
addipsecalg(struct ipsecalgent * newbie,uint_t flags)4840Sstevel@tonic-gate addipsecalg(struct ipsecalgent *newbie, uint_t flags)
4850Sstevel@tonic-gate {
4860Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
4870Sstevel@tonic-gate 	struct ipsecalgent *clone, **holder;
4880Sstevel@tonic-gate 	int num_protos, i;
4890Sstevel@tonic-gate 	char **name_check;
4900Sstevel@tonic-gate 	boolean_t forced_add = (flags & LIBIPSEC_ALGS_ADD_FORCE) != 0;
4910Sstevel@tonic-gate 	boolean_t found_match;
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos,
4940Sstevel@tonic-gate 	    newbie->a_proto_num, B_TRUE)) == NULL)
4950Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	/*
4980Sstevel@tonic-gate 	 * If an algorithm that matches _exactly_ the new algorithm
4990Sstevel@tonic-gate 	 * already exists, we're done.
5000Sstevel@tonic-gate 	 */
5010Sstevel@tonic-gate 	if (ipsecalg_exists(newbie, current_proto))
5020Sstevel@tonic-gate 		return (0);
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	/*
5050Sstevel@tonic-gate 	 * We don't allow a new algorithm to be created if one of
5060Sstevel@tonic-gate 	 * its names is already defined for an existing algorithm,
5070Sstevel@tonic-gate 	 * unless the operation is forced, in which case existing
5080Sstevel@tonic-gate 	 * algorithm entries that conflict with the new one are
5090Sstevel@tonic-gate 	 * deleted.
5100Sstevel@tonic-gate 	 */
5110Sstevel@tonic-gate 	for (name_check = newbie->a_names; *name_check != NULL; name_check++) {
5120Sstevel@tonic-gate 		found_match = delipsecalgbyname_common(*name_check,
5130Sstevel@tonic-gate 		    current_proto, forced_add);
5140Sstevel@tonic-gate 		if (found_match && !forced_add) {
5150Sstevel@tonic-gate 			/*
5160Sstevel@tonic-gate 			 * Duplicate entry found, but the addition was
5170Sstevel@tonic-gate 			 * not forced.
5180Sstevel@tonic-gate 			 */
5190Sstevel@tonic-gate 			_clean_trash(protos, num_protos);
5200Sstevel@tonic-gate 			return (LIBIPSEC_ALGS_DIAG_ALG_EXISTS);
5210Sstevel@tonic-gate 		}
5220Sstevel@tonic-gate 	}
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	for (i = 0; i < current_proto->proto_numalgs; i++) {
5250Sstevel@tonic-gate 		if (current_proto->proto_algs[i]->a_alg_num ==
5260Sstevel@tonic-gate 		    newbie->a_alg_num) {
5270Sstevel@tonic-gate 			/*
5280Sstevel@tonic-gate 			 * An algorithm with the same protocol number
5290Sstevel@tonic-gate 			 * and algorithm number already exists. Fail
5300Sstevel@tonic-gate 			 * addition unless the operation is forced.
5310Sstevel@tonic-gate 			 */
5320Sstevel@tonic-gate 			if (flags & LIBIPSEC_ALGS_ADD_FORCE) {
5330Sstevel@tonic-gate 				clone = _duplicate_alg(newbie);
5340Sstevel@tonic-gate 				if (clone != NULL) {
5350Sstevel@tonic-gate 					freeipsecalgent(
5360Sstevel@tonic-gate 					    current_proto->proto_algs[i]);
5370Sstevel@tonic-gate 					current_proto->proto_algs[i] = clone;
5380Sstevel@tonic-gate 					return (write_new_algfile(protos,
539*10824SMark.Fenwick@Sun.COM 					    num_protos));
5400Sstevel@tonic-gate 				} else {
5410Sstevel@tonic-gate 					_clean_trash(protos, num_protos);
5420Sstevel@tonic-gate 					return (LIBIPSEC_ALGS_DIAG_NOMEM);
5430Sstevel@tonic-gate 				}
5440Sstevel@tonic-gate 			} else {
5450Sstevel@tonic-gate 				_clean_trash(protos, num_protos);
5460Sstevel@tonic-gate 				return (LIBIPSEC_ALGS_DIAG_ALG_EXISTS);
5470Sstevel@tonic-gate 			}
5480Sstevel@tonic-gate 		}
5490Sstevel@tonic-gate 	}
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	/* append the new algorithm */
5520Sstevel@tonic-gate 	holder = realloc(current_proto->proto_algs,
5530Sstevel@tonic-gate 	    sizeof (struct ipsecalgent *) * (i + 1));
5540Sstevel@tonic-gate 	if (holder == NULL) {
5550Sstevel@tonic-gate 		_clean_trash(protos, num_protos);
5560Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_NOMEM);
5570Sstevel@tonic-gate 	}
5580Sstevel@tonic-gate 	clone = _duplicate_alg(newbie);
5590Sstevel@tonic-gate 	if (clone == NULL) {
5600Sstevel@tonic-gate 		free(holder);
5610Sstevel@tonic-gate 		_clean_trash(protos, num_protos);
5620Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_NOMEM);
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate 	current_proto->proto_numalgs++;
5650Sstevel@tonic-gate 	current_proto->proto_algs = holder;
5660Sstevel@tonic-gate 	current_proto->proto_algs[i] = clone;
5670Sstevel@tonic-gate 	return (write_new_algfile(protos, num_protos));
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate /*
5710Sstevel@tonic-gate  * Delete an algorithm by name & protocol number from /etc/inet/ipsecalgs.
5720Sstevel@tonic-gate  * Only deletes the first encountered instance.
5730Sstevel@tonic-gate  */
5740Sstevel@tonic-gate int
delipsecalgbyname(const char * name,int proto_num)5750Sstevel@tonic-gate delipsecalgbyname(const char *name, int proto_num)
5760Sstevel@tonic-gate {
5770Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
5780Sstevel@tonic-gate 	int num_protos;
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
5810Sstevel@tonic-gate 	    B_TRUE)) == NULL)
5820Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	if (delipsecalgbyname_common(name, current_proto, B_TRUE))
5850Sstevel@tonic-gate 		return (write_new_algfile(protos, num_protos));
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	_clean_trash(protos, num_protos);
5880Sstevel@tonic-gate 	return (LIBIPSEC_ALGS_DIAG_UNKN_ALG);
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate /*
5920Sstevel@tonic-gate  * Delete an algorithm by num + protocol num from /etc/inet/ipsecalgs.
5930Sstevel@tonic-gate  */
5940Sstevel@tonic-gate int
delipsecalgbynum(int alg_num,int proto_num)5950Sstevel@tonic-gate delipsecalgbynum(int alg_num, int proto_num)
5960Sstevel@tonic-gate {
5970Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
5980Sstevel@tonic-gate 	int i, num_protos;
5990Sstevel@tonic-gate 	boolean_t found_match = B_FALSE;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
6020Sstevel@tonic-gate 	    B_TRUE)) == NULL)
6030Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	for (i = 0; i < current_proto->proto_numalgs; i++) {
6060Sstevel@tonic-gate 		if (!found_match) {
6070Sstevel@tonic-gate 			if (current_proto->proto_algs[i]->a_alg_num ==
6080Sstevel@tonic-gate 			    alg_num) {
6090Sstevel@tonic-gate 				found_match = B_TRUE;
6100Sstevel@tonic-gate 				freeipsecalgent(current_proto->proto_algs[i]);
6110Sstevel@tonic-gate 			}
6120Sstevel@tonic-gate 		} else {
6130Sstevel@tonic-gate 			current_proto->proto_algs[i - 1] =
6140Sstevel@tonic-gate 			    current_proto->proto_algs[i];
6150Sstevel@tonic-gate 		}
6160Sstevel@tonic-gate 	}
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	if (found_match) {
6190Sstevel@tonic-gate 		current_proto->proto_numalgs--;
6200Sstevel@tonic-gate 		return (write_new_algfile(protos, num_protos));
6210Sstevel@tonic-gate 	}
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	_clean_trash(protos, num_protos);
6240Sstevel@tonic-gate 	return (LIBIPSEC_ALGS_DIAG_UNKN_ALG);
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate /*
6280Sstevel@tonic-gate  * Remove the specified protocol entry from the list of protocols.
6290Sstevel@tonic-gate  */
6300Sstevel@tonic-gate static void
delipsecproto_common(ipsec_proto_t * protos,int num_protos,ipsec_proto_t * proto)6310Sstevel@tonic-gate delipsecproto_common(ipsec_proto_t *protos, int num_protos,
6320Sstevel@tonic-gate     ipsec_proto_t *proto)
6330Sstevel@tonic-gate {
6340Sstevel@tonic-gate 	int i;
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	/* free protocol storage */
6370Sstevel@tonic-gate 	free(proto->proto_name);
6380Sstevel@tonic-gate 	for (i = 0; i < proto->proto_numalgs; i++)
6390Sstevel@tonic-gate 		freeipsecalgent(proto->proto_algs[i]);
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	/* remove from list of prototocols */
6420Sstevel@tonic-gate 	for (i = (proto - protos + 1); i < num_protos; i++)
6430Sstevel@tonic-gate 		protos[i - 1] = protos[i];
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate /*
6470Sstevel@tonic-gate  * Add an IPsec protocol to /etc/inet/ipsecalgs.
6480Sstevel@tonic-gate  */
6490Sstevel@tonic-gate int
addipsecproto(const char * proto_name,int proto_num,ipsecalgs_exec_mode_t proto_exec_mode,uint_t flags)6500Sstevel@tonic-gate addipsecproto(const char *proto_name, int proto_num,
6510Sstevel@tonic-gate     ipsecalgs_exec_mode_t proto_exec_mode, uint_t flags)
6520Sstevel@tonic-gate {
6530Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto, *new_proto;
6540Sstevel@tonic-gate 	int i, num_protos;
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	/*
6570Sstevel@tonic-gate 	 * NOTE:If build_internal_algs returns NULL for any
6580Sstevel@tonic-gate 	 *	reason, we will end up clobbering /etc/inet/ipsecalgs!
6590Sstevel@tonic-gate 	 */
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	current_proto = proto_setup(&protos, &num_protos, proto_num, B_FALSE);
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	/* check for protocol with duplicate id */
6640Sstevel@tonic-gate 	if (current_proto != NULL) {
6650Sstevel@tonic-gate 		if ((strcmp(proto_name, current_proto->proto_name) == 0) &&
6660Sstevel@tonic-gate 		    (proto_exec_mode == current_proto->proto_exec_mode)) {
6670Sstevel@tonic-gate 			/*
6680Sstevel@tonic-gate 			 * The current protocol being added matches
6690Sstevel@tonic-gate 			 * exactly an existing protocol, we're done.
6700Sstevel@tonic-gate 			 */
6710Sstevel@tonic-gate 			return (0);
6720Sstevel@tonic-gate 		}
6730Sstevel@tonic-gate 		if (!(flags & LIBIPSEC_ALGS_ADD_FORCE))
6740Sstevel@tonic-gate 			return (LIBIPSEC_ALGS_DIAG_PROTO_EXISTS);
6750Sstevel@tonic-gate 		delipsecproto_common(protos, num_protos--, current_proto);
6760Sstevel@tonic-gate 	}
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	/* check for protocol with duplicate name */
6790Sstevel@tonic-gate 	for (i = 0; i < num_protos; i++) {
6800Sstevel@tonic-gate 		if (strcmp(protos[i].proto_name, proto_name) == 0) {
6810Sstevel@tonic-gate 			if (!(flags & LIBIPSEC_ALGS_ADD_FORCE))
6820Sstevel@tonic-gate 				return (LIBIPSEC_ALGS_DIAG_PROTO_EXISTS);
6830Sstevel@tonic-gate 			delipsecproto_common(protos, num_protos--, &protos[i]);
6840Sstevel@tonic-gate 			break;
6850Sstevel@tonic-gate 		}
6860Sstevel@tonic-gate 	}
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	/* add new protocol */
6890Sstevel@tonic-gate 	num_protos++;
6900Sstevel@tonic-gate 	new_proto = realloc(protos, num_protos *
6910Sstevel@tonic-gate 	    sizeof (ipsec_proto_t));
6920Sstevel@tonic-gate 	if (new_proto == NULL) {
6930Sstevel@tonic-gate 		_clean_trash(protos, num_protos - 1);
6940Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_NOMEM);
6950Sstevel@tonic-gate 	}
6960Sstevel@tonic-gate 	protos = new_proto;
6970Sstevel@tonic-gate 	new_proto += (num_protos - 1);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	/* initialize protocol entry */
7000Sstevel@tonic-gate 	new_proto->proto_num = proto_num;
7010Sstevel@tonic-gate 	new_proto->proto_numalgs = 0;
7020Sstevel@tonic-gate 	new_proto->proto_algs = NULL;
7030Sstevel@tonic-gate 	new_proto->proto_name = strdup(proto_name);
7040Sstevel@tonic-gate 	if (new_proto->proto_name == NULL) {
7050Sstevel@tonic-gate 		_clean_trash(protos, num_protos);
7060Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_NOMEM);
7070Sstevel@tonic-gate 	}
7080Sstevel@tonic-gate 	new_proto->proto_pkg = NULL;
7090Sstevel@tonic-gate 	new_proto->proto_algs_pkgs = NULL;
7100Sstevel@tonic-gate 	new_proto->proto_algs_npkgs = 0;
7110Sstevel@tonic-gate 	new_proto->proto_exec_mode = proto_exec_mode;
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	return (write_new_algfile(protos, num_protos));
7140Sstevel@tonic-gate }
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate /*
7170Sstevel@tonic-gate  * Delete an IPsec protocol entry from /etc/inet/ipsecalgs.  This also
7180Sstevel@tonic-gate  * nukes the associated algorithms.
7190Sstevel@tonic-gate  */
7200Sstevel@tonic-gate int
delipsecprotobynum(int proto_num)7210Sstevel@tonic-gate delipsecprotobynum(int proto_num)
7220Sstevel@tonic-gate {
7230Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
7240Sstevel@tonic-gate 	int num_protos;
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
7270Sstevel@tonic-gate 	    B_TRUE)) == NULL)
7280Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	delipsecproto_common(protos, num_protos--, current_proto);
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	return (write_new_algfile(protos, num_protos));
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate int
delipsecprotobyname(const char * proto_name)7360Sstevel@tonic-gate delipsecprotobyname(const char *proto_name)
7370Sstevel@tonic-gate {
7380Sstevel@tonic-gate 	int proto_num;
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	proto_num = getipsecprotobyname(proto_name);
7410Sstevel@tonic-gate 	if (proto_num == -1)
7420Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	return (delipsecprotobynum(proto_num));
7450Sstevel@tonic-gate }
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate /*
7480Sstevel@tonic-gate  * Implement these in libnsl since these are read-only operations.
7490Sstevel@tonic-gate  */
7500Sstevel@tonic-gate int *
getipsecprotos(int * nentries)7510Sstevel@tonic-gate getipsecprotos(int *nentries)
7520Sstevel@tonic-gate {
7530Sstevel@tonic-gate 	return (_real_getipsecprotos(nentries));
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate int *
getipsecalgs(int * nentries,int proto_num)7570Sstevel@tonic-gate getipsecalgs(int *nentries, int proto_num)
7580Sstevel@tonic-gate {
7590Sstevel@tonic-gate 	return (_real_getipsecalgs(nentries, proto_num));
7600Sstevel@tonic-gate }
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate const char *
ipsecalgs_diag(int diag)7630Sstevel@tonic-gate ipsecalgs_diag(int diag)
7640Sstevel@tonic-gate {
7650Sstevel@tonic-gate 	switch (diag) {
7660Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALG_EXISTS:
7674064Smarkfen 		return (dgettext(TEXT_DOMAIN, "Algorithm already exists"));
7680Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_PROTO_EXISTS:
7694064Smarkfen 		return (dgettext(TEXT_DOMAIN, "Protocol already exists"));
7700Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_UNKN_PROTO:
7714064Smarkfen 		return (dgettext(TEXT_DOMAIN, "Unknown protocol"));
7720Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_UNKN_ALG:
7734064Smarkfen 		return (dgettext(TEXT_DOMAIN, "Unknown algorithm"));
7740Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_NOMEM:
7754064Smarkfen 		return (dgettext(TEXT_DOMAIN, "Out of memory"));
7760Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILEOPEN:
7774064Smarkfen 		return (dgettext(TEXT_DOMAIN, "open() failed"));
7780Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILEFDOPEN:
7794064Smarkfen 		return (dgettext(TEXT_DOMAIN, "fdopen() failed"));
7800Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILELOCK:
7814064Smarkfen 		return (dgettext(TEXT_DOMAIN, "lockf() failed"));
7820Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILERENAME:
7834064Smarkfen 		return (dgettext(TEXT_DOMAIN, "rename() failed"));
7840Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE:
7854064Smarkfen 		return (dgettext(TEXT_DOMAIN, "write to file failed"));
7860Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILECHMOD:
7874064Smarkfen 		return (dgettext(TEXT_DOMAIN, "chmod() failed"));
7880Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILECHOWN:
7894064Smarkfen 		return (dgettext(TEXT_DOMAIN, "chown() failed"));
7900Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILECLOSE:
7914064Smarkfen 		return (dgettext(TEXT_DOMAIN, "close() failed"));
7920Sstevel@tonic-gate 	default:
7934064Smarkfen 		return (dgettext(TEXT_DOMAIN, "failed"));
7940Sstevel@tonic-gate 	}
7950Sstevel@tonic-gate }
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate /*
7980Sstevel@tonic-gate  * Get the execution mode corresponding to the specified protocol.
7990Sstevel@tonic-gate  * Returns 0 on success, one of the LIBIPSEC_ALGS_DIAG_* values on
8000Sstevel@tonic-gate  * failure.
8010Sstevel@tonic-gate  */
8020Sstevel@tonic-gate int
ipsecproto_get_exec_mode(int proto_num,ipsecalgs_exec_mode_t * exec_mode)8030Sstevel@tonic-gate ipsecproto_get_exec_mode(int proto_num, ipsecalgs_exec_mode_t *exec_mode)
8040Sstevel@tonic-gate {
8050Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
8060Sstevel@tonic-gate 	int num_protos;
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
8090Sstevel@tonic-gate 	    B_TRUE)) == NULL)
8100Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	*exec_mode = current_proto->proto_exec_mode;
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	_clean_trash(protos, num_protos);
8150Sstevel@tonic-gate 	return (0);
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate /*
8190Sstevel@tonic-gate  * Set the execution mode of the specified protocol. Returns 0 on success,
8200Sstevel@tonic-gate  * or one of the LIBIPSEC_ALGS_DIAG_* values on failure.
8210Sstevel@tonic-gate  */
8220Sstevel@tonic-gate int
ipsecproto_set_exec_mode(int proto_num,ipsecalgs_exec_mode_t exec_mode)8230Sstevel@tonic-gate ipsecproto_set_exec_mode(int proto_num, ipsecalgs_exec_mode_t exec_mode)
8240Sstevel@tonic-gate {
8250Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
8260Sstevel@tonic-gate 	int num_protos;
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
8290Sstevel@tonic-gate 	    B_TRUE)) == NULL)
8300Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	current_proto->proto_exec_mode = exec_mode;
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	return (write_new_algfile(protos, num_protos));
8350Sstevel@tonic-gate }
836