17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
581231665Sdanmcd  * Common Development and Distribution License (the "License").
681231665Sdanmcd  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22628b0c67SMark Fenwick  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/stat.h>
287c478bd9Sstevel@tonic-gate #include <ipsec_util.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <strings.h>
317c478bd9Sstevel@tonic-gate #include <netdb.h>
327c478bd9Sstevel@tonic-gate #include <fcntl.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <libintl.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate static char *preamble =
38*bbf21555SRichard Lowe "# /etc/inet/ipsecalgs output from ipsecalgs(8)\n"
397c478bd9Sstevel@tonic-gate "#\n"
407c478bd9Sstevel@tonic-gate "# DO NOT EDIT OR PARSE THIS FILE!\n"
417c478bd9Sstevel@tonic-gate "#\n"
42*bbf21555SRichard Lowe "# Use the ipsecalgs(8) command to change the contents of this file.\n"
43628b0c67SMark Fenwick "# The algorithm descriptions contained in this file are synchronised to the\n"
44628b0c67SMark Fenwick "# kernel with ipsecalgs -s, the kernel validates the entries at this point."
45628b0c67SMark Fenwick "\n\n"
46628b0c67SMark Fenwick "# PROTO|protocol-id|protocol-name|exec-mode\n"
47628b0c67SMark Fenwick "##  NOTE:  Some protocol numbers are well-known and defined in <netdb.h>\n\n"
48628b0c67SMark Fenwick "# ALG|protocol-id|alg-id|name,name,...|ef-id| \n"
49628b0c67SMark Fenwick "#        {default/}{key,key..}or{key-key,inc}|block_size or MAC-size|\n"
50628b0c67SMark Fenwick "#        [parameter,parameter..]|[flags]\n\n"
51628b0c67SMark Fenwick "#\n"
52628b0c67SMark Fenwick "## Note:   Parameters and flags only apply to certain algorithms.\n\n";
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #define	CFG_PERMS S_IRUSR | S_IRGRP | S_IROTH	/* Perms 0444. */
557c478bd9Sstevel@tonic-gate #define	CFG_OWNER 0	/* root */
567c478bd9Sstevel@tonic-gate #define	CFG_GROUP 1	/* "other" */
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /*
597c478bd9Sstevel@tonic-gate  * write_new_algfile() helper macros to check for write errors.
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #define	FPRINTF_ERR(fcall) if ((fcall) < 0) {	\
637c478bd9Sstevel@tonic-gate 	rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;	\
647c478bd9Sstevel@tonic-gate 	goto bail;				\
657c478bd9Sstevel@tonic-gate }
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #define	FPUT_ERR(fcall) if ((fcall) == EOF) {	\
687c478bd9Sstevel@tonic-gate 	rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;	\
697c478bd9Sstevel@tonic-gate 	goto bail;				\
707c478bd9Sstevel@tonic-gate }
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate /*
737c478bd9Sstevel@tonic-gate  * Helper macros to start and finish a list of entries that were added
747c478bd9Sstevel@tonic-gate  * as part of a package installation.
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate #define	PKG_SEC_START(pkgname, doing_pkg, cur_pkg) {		\
787c478bd9Sstevel@tonic-gate 	(void) strcpy((cur_pkg), (pkgname));			\
797c478bd9Sstevel@tonic-gate 	FPRINTF_ERR(fprintf(f, "%s%s\n",			\
807c478bd9Sstevel@tonic-gate 	    LIBIPSEC_ALGS_LINE_PKGSTART, (cur_pkg)));		\
817c478bd9Sstevel@tonic-gate 	(doing_pkg) = B_TRUE;					\
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate #define	PKG_SEC_END(doing_pkg, cur_pkg) {			\
857c478bd9Sstevel@tonic-gate 	if (doing_pkg) {					\
867c478bd9Sstevel@tonic-gate 		FPRINTF_ERR(fprintf(f, "%s%s\n",		\
877c478bd9Sstevel@tonic-gate 		    LIBIPSEC_ALGS_LINE_PKGEND, (cur_pkg)));	\
887c478bd9Sstevel@tonic-gate 		(doing_pkg) = B_FALSE;				\
897c478bd9Sstevel@tonic-gate 	}							\
907c478bd9Sstevel@tonic-gate }
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * Take a zero-terminated int array and print int1,int2...,intN.
947c478bd9Sstevel@tonic-gate  * If zero-only, then print a single '0'.
957c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 if an error occurred while writing to
967c478bd9Sstevel@tonic-gate  * the specified file.
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate int
list_ints(FILE * f,int * floater)997c478bd9Sstevel@tonic-gate list_ints(FILE *f, int *floater)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	boolean_t executed = B_FALSE;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	while (*floater != 0) {
1047c478bd9Sstevel@tonic-gate 		executed = B_TRUE;
1057c478bd9Sstevel@tonic-gate 		if (fprintf(f, "%d", *floater) < 0)
1067c478bd9Sstevel@tonic-gate 			return (-1);
1077c478bd9Sstevel@tonic-gate 		if (*(++floater) != 0)
1087c478bd9Sstevel@tonic-gate 			if (fputc(',', f) == EOF)
1097c478bd9Sstevel@tonic-gate 				return (-1);
1107c478bd9Sstevel@tonic-gate 	}
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	if (!executed)
1137c478bd9Sstevel@tonic-gate 		if (fputc('0', f) == EOF)
1147c478bd9Sstevel@tonic-gate 			return (-1);
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	return (0);
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /*
1207c478bd9Sstevel@tonic-gate  * If the specified algorithm was defined within a package section, i.e.
1217c478bd9Sstevel@tonic-gate  * between the lines "# Start <pkgname>" and "# End <pkgname>", returns
1227c478bd9Sstevel@tonic-gate  * the value of <pkgname>.
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate static char *
alg_has_pkg(ipsec_proto_t * proto,struct ipsecalgent * alg)1257c478bd9Sstevel@tonic-gate alg_has_pkg(ipsec_proto_t *proto, struct ipsecalgent *alg)
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate 	int i;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	if (proto->proto_algs_pkgs == NULL)
1307c478bd9Sstevel@tonic-gate 		return (NULL);
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	for (i = 0; i < proto->proto_algs_npkgs; i++)
1337c478bd9Sstevel@tonic-gate 		if (proto->proto_algs_pkgs[i].alg_num == alg->a_alg_num)
1347c478bd9Sstevel@tonic-gate 			return (proto->proto_algs_pkgs[i].pkg_name);
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	return (NULL);
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate /*
1407c478bd9Sstevel@tonic-gate  * Writes the package start/end delimiters according to the package
1417c478bd9Sstevel@tonic-gate  * name associated with the current protocol or algorithm, and
1427c478bd9Sstevel@tonic-gate  * the state of the packaging information already written to the file.
1437c478bd9Sstevel@tonic-gate  * Called by write_new_algfile(). Returns 0 on success, one of the
1447c478bd9Sstevel@tonic-gate  * LIBIPSEC_DIAG codes on failure.
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate static int
pkg_section(FILE * f,char * pkg_name,boolean_t * doing_pkg,char * cur_pkg)1477c478bd9Sstevel@tonic-gate pkg_section(FILE *f, char *pkg_name, boolean_t *doing_pkg, char *cur_pkg)
1487c478bd9Sstevel@tonic-gate {
1497c478bd9Sstevel@tonic-gate 	int rc = 0;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	if (pkg_name != NULL) {
1527c478bd9Sstevel@tonic-gate 		/* protocol or algorithm is associated with a package */
1537c478bd9Sstevel@tonic-gate 		if (!*doing_pkg) {
1547c478bd9Sstevel@tonic-gate 			/* start of a new package section */
1557c478bd9Sstevel@tonic-gate 			PKG_SEC_START(pkg_name, *doing_pkg, cur_pkg);
1567c478bd9Sstevel@tonic-gate 		} else {
1577c478bd9Sstevel@tonic-gate 			/* already in a package section */
1587c478bd9Sstevel@tonic-gate 			if (strcmp(pkg_name, cur_pkg) != 0) {
1597c478bd9Sstevel@tonic-gate 				/* different package name */
1607c478bd9Sstevel@tonic-gate 				PKG_SEC_END(*doing_pkg, cur_pkg);
1617c478bd9Sstevel@tonic-gate 				PKG_SEC_START(pkg_name, *doing_pkg, cur_pkg);
1627c478bd9Sstevel@tonic-gate 			}
1637c478bd9Sstevel@tonic-gate 		}
1647c478bd9Sstevel@tonic-gate 	} else if (*doing_pkg) {
1657c478bd9Sstevel@tonic-gate 		/* in a package section when the entry isn't */
1667c478bd9Sstevel@tonic-gate 		PKG_SEC_END(*doing_pkg, cur_pkg);
1677c478bd9Sstevel@tonic-gate 	}
1687c478bd9Sstevel@tonic-gate bail:
1697c478bd9Sstevel@tonic-gate 	return (rc);
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate /*
1737c478bd9Sstevel@tonic-gate  * Given a list of protocols and number, write them to a new algorithm file.
1747c478bd9Sstevel@tonic-gate  * This function takes num_protos + num_protos * dois-per-alg operations.
1757c478bd9Sstevel@tonic-gate  * Also free the protocol structure.
1767c478bd9Sstevel@tonic-gate  *
1777c478bd9Sstevel@tonic-gate  * Note that no locking spans the read/update/write phases that can be
1787c478bd9Sstevel@tonic-gate  * used by callers of this routine. This could cause this function to suffer
1797c478bd9Sstevel@tonic-gate  * from the "lost update" problem. Since updates to the IPsec protocols
1807c478bd9Sstevel@tonic-gate  * and algorithm tables are very infrequent, this should not be a issue in
1817c478bd9Sstevel@tonic-gate  * practice.
1827c478bd9Sstevel@tonic-gate  */
1837c478bd9Sstevel@tonic-gate static int
write_new_algfile(ipsec_proto_t * protos,int num_protos)1847c478bd9Sstevel@tonic-gate write_new_algfile(ipsec_proto_t *protos, int num_protos)
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate 	FILE *f;
1877c478bd9Sstevel@tonic-gate 	int fd, i, j, k;
1887c478bd9Sstevel@tonic-gate 	int rc = 0;
1897c478bd9Sstevel@tonic-gate 	struct ipsecalgent *alg;
1907c478bd9Sstevel@tonic-gate 	char cur_pkg[1024];
1917c478bd9Sstevel@tonic-gate 	boolean_t doing_pkg = B_FALSE;
1927c478bd9Sstevel@tonic-gate 	char *alg_pkg;
19381231665Sdanmcd 	char tmp_name_template[] = INET_IPSECALGSPATH "ipsecalgsXXXXXX";
1947c478bd9Sstevel@tonic-gate 	char *tmp_name;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	/*
1977c478bd9Sstevel@tonic-gate 	 * In order to avoid potentially corrupting the configuration
1987c478bd9Sstevel@tonic-gate 	 * file on file system failure, write the new configuration info
1997c478bd9Sstevel@tonic-gate 	 * to a temporary file which is then renamed to the configuration
2007c478bd9Sstevel@tonic-gate 	 * file (INET_IPSECALGSFILE.)
2017c478bd9Sstevel@tonic-gate 	 */
2027c478bd9Sstevel@tonic-gate 	tmp_name = mktemp(tmp_name_template);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	fd = open(tmp_name, O_WRONLY|O_CREAT|O_EXCL, CFG_PERMS);
2057c478bd9Sstevel@tonic-gate 	if (fd == -1) {
2067c478bd9Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILEOPEN;
2077c478bd9Sstevel@tonic-gate 		goto bail;
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	f = fdopen(fd, "w");
2117c478bd9Sstevel@tonic-gate 	if (f == NULL) {
2127c478bd9Sstevel@tonic-gate 		(void) close(fd);
2137c478bd9Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILEFDOPEN;
2147c478bd9Sstevel@tonic-gate 		goto bail;
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	FPUT_ERR(fputs(preamble, f));
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/* Write protocol entries. */
2207c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_protos; i++) {
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 		/* add package section delimiters if needed */
2237c478bd9Sstevel@tonic-gate 		rc = pkg_section(f, protos[i].proto_pkg, &doing_pkg, cur_pkg);
2247c478bd9Sstevel@tonic-gate 		if (rc != 0)
2257c478bd9Sstevel@tonic-gate 			goto bail;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 		FPRINTF_ERR(fprintf(f, "%s%d|%s|",
2287c478bd9Sstevel@tonic-gate 		    LIBIPSEC_ALGS_LINE_PROTO,
2297c478bd9Sstevel@tonic-gate 		    protos[i].proto_num, protos[i].proto_name));
2307c478bd9Sstevel@tonic-gate 		switch (protos[i].proto_exec_mode) {
2317c478bd9Sstevel@tonic-gate 		case LIBIPSEC_ALGS_EXEC_SYNC:
2327c478bd9Sstevel@tonic-gate 			FPRINTF_ERR(fprintf(f, "sync\n"));
2337c478bd9Sstevel@tonic-gate 			break;
2347c478bd9Sstevel@tonic-gate 		case LIBIPSEC_ALGS_EXEC_ASYNC:
2357c478bd9Sstevel@tonic-gate 			FPRINTF_ERR(fprintf(f, "async\n"));
2367c478bd9Sstevel@tonic-gate 			break;
2377c478bd9Sstevel@tonic-gate 		}
2387c478bd9Sstevel@tonic-gate 	}
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	/* terminate the package section for the protocols if needed */
2417c478bd9Sstevel@tonic-gate 	PKG_SEC_END(doing_pkg, cur_pkg);
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	FPUT_ERR(fputs("\n", f));
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	/* Write algorithm entries. */
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_protos; i++) {
2487c478bd9Sstevel@tonic-gate 		for (j = 0; j < protos[i].proto_numalgs; j++) {
2497c478bd9Sstevel@tonic-gate 			alg = protos[i].proto_algs[j];
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 			/* add package section delimiters if needed */
2527c478bd9Sstevel@tonic-gate 			alg_pkg = alg_has_pkg(&protos[i], alg);
2537c478bd9Sstevel@tonic-gate 			rc = pkg_section(f, alg_pkg, &doing_pkg, cur_pkg);
2547c478bd9Sstevel@tonic-gate 			if (rc != 0)
2557c478bd9Sstevel@tonic-gate 				goto bail;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 			/* protocol and algorithm numbers */
2587c478bd9Sstevel@tonic-gate 			FPRINTF_ERR(fprintf(f, "%s%d|%d|",
2597c478bd9Sstevel@tonic-gate 			    LIBIPSEC_ALGS_LINE_ALG,
2607c478bd9Sstevel@tonic-gate 			    alg->a_proto_num, alg->a_alg_num));
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 			/* algorithm names */
2637c478bd9Sstevel@tonic-gate 			for (k = 0; alg->a_names[k] != NULL; k++) {
2647c478bd9Sstevel@tonic-gate 				FPRINTF_ERR(fprintf(f, "%s", alg->a_names[k]));
2657c478bd9Sstevel@tonic-gate 				if (alg->a_names[k+1] != NULL)
2667c478bd9Sstevel@tonic-gate 					FPRINTF_ERR(fprintf(f, ","));
2677c478bd9Sstevel@tonic-gate 			}
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 			/* mechanism name */
2707c478bd9Sstevel@tonic-gate 			FPRINTF_ERR(fprintf(f, "|%s|", alg->a_mech_name));
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 			/* key sizes */
2737c478bd9Sstevel@tonic-gate 			if (alg->a_key_increment == 0) {
2747c478bd9Sstevel@tonic-gate 				/* key sizes defined by enumeration */
2757c478bd9Sstevel@tonic-gate 				if (list_ints(f, alg->a_key_sizes) == -1) {
2767c478bd9Sstevel@tonic-gate 					rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;
2777c478bd9Sstevel@tonic-gate 					goto bail;
2787c478bd9Sstevel@tonic-gate 				}
2797c478bd9Sstevel@tonic-gate 			} else {
2807c478bd9Sstevel@tonic-gate 				/* key sizes defined by range */
2817c478bd9Sstevel@tonic-gate 				FPRINTF_ERR(fprintf(f, "%d/%d-%d,%d",
2827c478bd9Sstevel@tonic-gate 				    alg->a_key_sizes[0], alg->a_key_sizes[1],
2837c478bd9Sstevel@tonic-gate 				    alg->a_key_sizes[2], alg->a_key_increment));
2847c478bd9Sstevel@tonic-gate 			}
2857c478bd9Sstevel@tonic-gate 			FPUT_ERR(fputc('|', f));
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 			/* block sizes */
2887c478bd9Sstevel@tonic-gate 			if (list_ints(f, alg->a_block_sizes) == -1) {
2897c478bd9Sstevel@tonic-gate 				rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;
2907c478bd9Sstevel@tonic-gate 				goto bail;
2917c478bd9Sstevel@tonic-gate 			}
292628b0c67SMark Fenwick 			FPUT_ERR(fputc('|', f));
293628b0c67SMark Fenwick 
294628b0c67SMark Fenwick 			/*
295628b0c67SMark Fenwick 			 * Some algorithms require extra parameters, these
296628b0c67SMark Fenwick 			 * are stored in an array. For algorithms that don't
297628b0c67SMark Fenwick 			 * need these parameters, or flags (below), these
298628b0c67SMark Fenwick 			 * extra fields in the ipsecalgs file must contain a
299628b0c67SMark Fenwick 			 * zero. This fuction will get called if a algorithm
300628b0c67SMark Fenwick 			 * entry is added, at this point the extra fields will
301628b0c67SMark Fenwick 			 * be added to the file.
302628b0c67SMark Fenwick 			 */
303628b0c67SMark Fenwick 			if (list_ints(f, alg->a_mech_params) == -1) {
304628b0c67SMark Fenwick 				rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;
305628b0c67SMark Fenwick 				goto bail;
306628b0c67SMark Fenwick 			}
307628b0c67SMark Fenwick 			/* flags */
308628b0c67SMark Fenwick 			FPRINTF_ERR(fprintf(f, "|%d\n", alg->a_alg_flags));
3097c478bd9Sstevel@tonic-gate 		}
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	/* terminate the package section for the algorithms if needed */
3137c478bd9Sstevel@tonic-gate 	PKG_SEC_END(doing_pkg, cur_pkg);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	if (fchmod(fd, CFG_PERMS) == -1) {
3167c478bd9Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILECHMOD;
3177c478bd9Sstevel@tonic-gate 		goto bail;
3187c478bd9Sstevel@tonic-gate 	}
3197c478bd9Sstevel@tonic-gate 	if (fchown(fd, CFG_OWNER, CFG_GROUP) == -1) {
3207c478bd9Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILECHOWN;
3217c478bd9Sstevel@tonic-gate 		goto bail;
3227c478bd9Sstevel@tonic-gate 	}
3237c478bd9Sstevel@tonic-gate 	if (fclose(f) == EOF) {
3247c478bd9Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILECLOSE;
3257c478bd9Sstevel@tonic-gate 		goto bail;
3267c478bd9Sstevel@tonic-gate 	}
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	if (rename(tmp_name, INET_IPSECALGSFILE) == -1)
3297c478bd9Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILERENAME;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate bail:
3327c478bd9Sstevel@tonic-gate 	_clean_trash(protos, num_protos);
3337c478bd9Sstevel@tonic-gate 	return (rc);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate /*
3377c478bd9Sstevel@tonic-gate  * Return a pointer to the protocol entry corresponding to the specified
3387c478bd9Sstevel@tonic-gate  * protocol num proto_num. Also builds the list of currently defined
3397c478bd9Sstevel@tonic-gate  * protocols.
3407c478bd9Sstevel@tonic-gate  */
3417c478bd9Sstevel@tonic-gate static ipsec_proto_t *
proto_setup(ipsec_proto_t ** protos,int * num_protos,int proto_num,boolean_t cleanup)3427c478bd9Sstevel@tonic-gate proto_setup(ipsec_proto_t **protos, int *num_protos, int proto_num,
3437c478bd9Sstevel@tonic-gate     boolean_t cleanup)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	int i;
3467c478bd9Sstevel@tonic-gate 	ipsec_proto_t *current_proto, *ret_proto = NULL;
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	_build_internal_algs(protos, num_protos);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	if (*protos == NULL)
3517c478bd9Sstevel@tonic-gate 		return (NULL);
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	for (i = 0; i < *num_protos; i++) {
3547c478bd9Sstevel@tonic-gate 		current_proto = (*protos) + i;
3557c478bd9Sstevel@tonic-gate 		if (current_proto->proto_num == proto_num) {
3567c478bd9Sstevel@tonic-gate 			ret_proto = current_proto;
3577c478bd9Sstevel@tonic-gate 			break;
3587c478bd9Sstevel@tonic-gate 		}
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	if (ret_proto == NULL) {
3627c478bd9Sstevel@tonic-gate 		if (cleanup)
3637c478bd9Sstevel@tonic-gate 			_clean_trash(*protos, *num_protos);
3647c478bd9Sstevel@tonic-gate 		/* else caller wants parsed /etc/inet/ipsecalgs anyway */
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	return (ret_proto);
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate /*
3717c478bd9Sstevel@tonic-gate  * Delete the first found algorithm of the specified protocol which
3727c478bd9Sstevel@tonic-gate  * has the same name as the one specified by alg_name. Deletion of
3737c478bd9Sstevel@tonic-gate  * the entry takes place only if the delete_it flag is set. If an
3747c478bd9Sstevel@tonic-gate  * entry was found, return B_TRUE, otherwise return B_FALSE.
3757c478bd9Sstevel@tonic-gate  */
3767c478bd9Sstevel@tonic-gate static boolean_t
delipsecalgbyname_common(const char * name,ipsec_proto_t * proto,boolean_t delete_it)3777c478bd9Sstevel@tonic-gate delipsecalgbyname_common(const char *name, ipsec_proto_t *proto,
3787c478bd9Sstevel@tonic-gate     boolean_t delete_it)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	int i;
3817c478bd9Sstevel@tonic-gate 	char **name_check;
3827c478bd9Sstevel@tonic-gate 	boolean_t found_match = B_FALSE;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	for (i = 0; i < proto->proto_numalgs; i++) {
3857c478bd9Sstevel@tonic-gate 		if (!found_match) {
3867c478bd9Sstevel@tonic-gate 			for (name_check =
3877c478bd9Sstevel@tonic-gate 			    proto->proto_algs[i]->a_names;
3887c478bd9Sstevel@tonic-gate 			    *name_check != NULL; name_check++) {
3897c478bd9Sstevel@tonic-gate 				/*
3907c478bd9Sstevel@tonic-gate 				 * Can use strcmp because the algorithm names
3917c478bd9Sstevel@tonic-gate 				 * are bound.
3927c478bd9Sstevel@tonic-gate 				 */
3937c478bd9Sstevel@tonic-gate 				if (strcmp(*name_check, name) == 0) {
3947c478bd9Sstevel@tonic-gate 					found_match = B_TRUE;
3957c478bd9Sstevel@tonic-gate 					if (!delete_it)
3967c478bd9Sstevel@tonic-gate 						return (found_match);
3977c478bd9Sstevel@tonic-gate 					freeipsecalgent(proto->proto_algs[i]);
3987c478bd9Sstevel@tonic-gate 					break;
3997c478bd9Sstevel@tonic-gate 				}
4007c478bd9Sstevel@tonic-gate 			}
4017c478bd9Sstevel@tonic-gate 		} else {
4027c478bd9Sstevel@tonic-gate 			proto->proto_algs[i - 1] = proto->proto_algs[i];
4037c478bd9Sstevel@tonic-gate 		}
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	if (found_match)
4077c478bd9Sstevel@tonic-gate 		proto->proto_numalgs--;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	return (found_match);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate /*
4137c478bd9Sstevel@tonic-gate  * Returns B_TRUE if the specified 0-terminated lists of key or
4147c478bd9Sstevel@tonic-gate  * block sizes match, B_FALSE otherwise.
4157c478bd9Sstevel@tonic-gate  */
4167c478bd9Sstevel@tonic-gate static boolean_t
sizes_match(int * a1,int * a2)4177c478bd9Sstevel@tonic-gate sizes_match(int *a1, int *a2)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate 	int i;
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	for (i = 0; (a1[i] != 0) && (a2[i] != 0); i++) {
4227c478bd9Sstevel@tonic-gate 		if (a1[i] != a2[i])
4237c478bd9Sstevel@tonic-gate 			return (B_FALSE);
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 	if ((a1[i] != 0) || (a2[i] != 0))
4267c478bd9Sstevel@tonic-gate 		return (B_FALSE);
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	return (B_TRUE);
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate /*
4327c478bd9Sstevel@tonic-gate  * Returns B_TRUE if an _exact_ equivalent of the specified algorithm
4337c478bd9Sstevel@tonic-gate  * already exists, B_FALSE otherwise.
4347c478bd9Sstevel@tonic-gate  */
4357c478bd9Sstevel@tonic-gate static boolean_t
ipsecalg_exists(struct ipsecalgent * newbie,ipsec_proto_t * proto)4367c478bd9Sstevel@tonic-gate ipsecalg_exists(struct ipsecalgent *newbie, ipsec_proto_t *proto)
4377c478bd9Sstevel@tonic-gate {
4387c478bd9Sstevel@tonic-gate 	struct ipsecalgent *curalg;
4397c478bd9Sstevel@tonic-gate 	char **curname, **newbiename;
4407c478bd9Sstevel@tonic-gate 	int i;
4417c478bd9Sstevel@tonic-gate 	boolean_t match;
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	for (i = 0; i < proto->proto_numalgs; i++) {
4447c478bd9Sstevel@tonic-gate 		curalg = proto->proto_algs[i];
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 		if (curalg->a_alg_num != newbie->a_alg_num)
4477c478bd9Sstevel@tonic-gate 			continue;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 		if (curalg->a_key_increment != newbie->a_key_increment)
4507c478bd9Sstevel@tonic-gate 			continue;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 		if (strcmp(curalg->a_mech_name, newbie->a_mech_name) != 0)
4537c478bd9Sstevel@tonic-gate 			continue;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 		curname = curalg->a_names;
4567c478bd9Sstevel@tonic-gate 		newbiename = newbie->a_names;
4577c478bd9Sstevel@tonic-gate 		match = B_TRUE;
4587c478bd9Sstevel@tonic-gate 		while ((*curname != NULL) && (*newbiename != NULL) && match) {
4597c478bd9Sstevel@tonic-gate 			match = (strcmp(*curname, *newbiename) == 0);
4607c478bd9Sstevel@tonic-gate 			curname++;
4617c478bd9Sstevel@tonic-gate 			newbiename++;
4627c478bd9Sstevel@tonic-gate 		}
4637c478bd9Sstevel@tonic-gate 		if (!match || (*curname != NULL) || (*newbiename != NULL))
4647c478bd9Sstevel@tonic-gate 			continue;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		if (!sizes_match(curalg->a_block_sizes, newbie->a_block_sizes))
4677c478bd9Sstevel@tonic-gate 			continue;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 		if (!sizes_match(curalg->a_key_sizes, newbie->a_key_sizes))
4707c478bd9Sstevel@tonic-gate 			continue;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		/* we found an exact match */
4737c478bd9Sstevel@tonic-gate 		return (B_TRUE);
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	return (B_FALSE);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate /*
4807c478bd9Sstevel@tonic-gate  * Add a new algorithm to the /etc/inet/ipsecalgs file.  Caller must free
4817c478bd9Sstevel@tonic-gate  * or otherwise address "newbie".
4827c478bd9Sstevel@tonic-gate  */
4837c478bd9Sstevel@tonic-gate int
addipsecalg(struct ipsecalgent * newbie,uint_t flags)4847c478bd9Sstevel@tonic-gate addipsecalg(struct ipsecalgent *newbie, uint_t flags)
4857c478bd9Sstevel@tonic-gate {
4867c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
4877c478bd9Sstevel@tonic-gate 	struct ipsecalgent *clone, **holder;
4887c478bd9Sstevel@tonic-gate 	int num_protos, i;
4897c478bd9Sstevel@tonic-gate 	char **name_check;
4907c478bd9Sstevel@tonic-gate 	boolean_t forced_add = (flags & LIBIPSEC_ALGS_ADD_FORCE) != 0;
4917c478bd9Sstevel@tonic-gate 	boolean_t found_match;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos,
4947c478bd9Sstevel@tonic-gate 	    newbie->a_proto_num, B_TRUE)) == NULL)
4957c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	/*
4987c478bd9Sstevel@tonic-gate 	 * If an algorithm that matches _exactly_ the new algorithm
4997c478bd9Sstevel@tonic-gate 	 * already exists, we're done.
5007c478bd9Sstevel@tonic-gate 	 */
5017c478bd9Sstevel@tonic-gate 	if (ipsecalg_exists(newbie, current_proto))
5027c478bd9Sstevel@tonic-gate 		return (0);
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	/*
5057c478bd9Sstevel@tonic-gate 	 * We don't allow a new algorithm to be created if one of
5067c478bd9Sstevel@tonic-gate 	 * its names is already defined for an existing algorithm,
5077c478bd9Sstevel@tonic-gate 	 * unless the operation is forced, in which case existing
5087c478bd9Sstevel@tonic-gate 	 * algorithm entries that conflict with the new one are
5097c478bd9Sstevel@tonic-gate 	 * deleted.
5107c478bd9Sstevel@tonic-gate 	 */
5117c478bd9Sstevel@tonic-gate 	for (name_check = newbie->a_names; *name_check != NULL; name_check++) {
5127c478bd9Sstevel@tonic-gate 		found_match = delipsecalgbyname_common(*name_check,
5137c478bd9Sstevel@tonic-gate 		    current_proto, forced_add);
5147c478bd9Sstevel@tonic-gate 		if (found_match && !forced_add) {
5157c478bd9Sstevel@tonic-gate 			/*
5167c478bd9Sstevel@tonic-gate 			 * Duplicate entry found, but the addition was
5177c478bd9Sstevel@tonic-gate 			 * not forced.
5187c478bd9Sstevel@tonic-gate 			 */
5197c478bd9Sstevel@tonic-gate 			_clean_trash(protos, num_protos);
5207c478bd9Sstevel@tonic-gate 			return (LIBIPSEC_ALGS_DIAG_ALG_EXISTS);
5217c478bd9Sstevel@tonic-gate 		}
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	for (i = 0; i < current_proto->proto_numalgs; i++) {
5257c478bd9Sstevel@tonic-gate 		if (current_proto->proto_algs[i]->a_alg_num ==
5267c478bd9Sstevel@tonic-gate 		    newbie->a_alg_num) {
5277c478bd9Sstevel@tonic-gate 			/*
5287c478bd9Sstevel@tonic-gate 			 * An algorithm with the same protocol number
5297c478bd9Sstevel@tonic-gate 			 * and algorithm number already exists. Fail
5307c478bd9Sstevel@tonic-gate 			 * addition unless the operation is forced.
5317c478bd9Sstevel@tonic-gate 			 */
5327c478bd9Sstevel@tonic-gate 			if (flags & LIBIPSEC_ALGS_ADD_FORCE) {
5337c478bd9Sstevel@tonic-gate 				clone = _duplicate_alg(newbie);
5347c478bd9Sstevel@tonic-gate 				if (clone != NULL) {
5357c478bd9Sstevel@tonic-gate 					freeipsecalgent(
5367c478bd9Sstevel@tonic-gate 					    current_proto->proto_algs[i]);
5377c478bd9Sstevel@tonic-gate 					current_proto->proto_algs[i] = clone;
5387c478bd9Sstevel@tonic-gate 					return (write_new_algfile(protos,
539628b0c67SMark Fenwick 					    num_protos));
5407c478bd9Sstevel@tonic-gate 				} else {
5417c478bd9Sstevel@tonic-gate 					_clean_trash(protos, num_protos);
5427c478bd9Sstevel@tonic-gate 					return (LIBIPSEC_ALGS_DIAG_NOMEM);
5437c478bd9Sstevel@tonic-gate 				}
5447c478bd9Sstevel@tonic-gate 			} else {
5457c478bd9Sstevel@tonic-gate 				_clean_trash(protos, num_protos);
5467c478bd9Sstevel@tonic-gate 				return (LIBIPSEC_ALGS_DIAG_ALG_EXISTS);
5477c478bd9Sstevel@tonic-gate 			}
5487c478bd9Sstevel@tonic-gate 		}
5497c478bd9Sstevel@tonic-gate 	}
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	/* append the new algorithm */
5527c478bd9Sstevel@tonic-gate 	holder = realloc(current_proto->proto_algs,
5537c478bd9Sstevel@tonic-gate 	    sizeof (struct ipsecalgent *) * (i + 1));
5547c478bd9Sstevel@tonic-gate 	if (holder == NULL) {
5557c478bd9Sstevel@tonic-gate 		_clean_trash(protos, num_protos);
5567c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_NOMEM);
5577c478bd9Sstevel@tonic-gate 	}
5587c478bd9Sstevel@tonic-gate 	clone = _duplicate_alg(newbie);
5597c478bd9Sstevel@tonic-gate 	if (clone == NULL) {
5607c478bd9Sstevel@tonic-gate 		free(holder);
5617c478bd9Sstevel@tonic-gate 		_clean_trash(protos, num_protos);
5627c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_NOMEM);
5637c478bd9Sstevel@tonic-gate 	}
5647c478bd9Sstevel@tonic-gate 	current_proto->proto_numalgs++;
5657c478bd9Sstevel@tonic-gate 	current_proto->proto_algs = holder;
5667c478bd9Sstevel@tonic-gate 	current_proto->proto_algs[i] = clone;
5677c478bd9Sstevel@tonic-gate 	return (write_new_algfile(protos, num_protos));
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate /*
5717c478bd9Sstevel@tonic-gate  * Delete an algorithm by name & protocol number from /etc/inet/ipsecalgs.
5727c478bd9Sstevel@tonic-gate  * Only deletes the first encountered instance.
5737c478bd9Sstevel@tonic-gate  */
5747c478bd9Sstevel@tonic-gate int
delipsecalgbyname(const char * name,int proto_num)5757c478bd9Sstevel@tonic-gate delipsecalgbyname(const char *name, int proto_num)
5767c478bd9Sstevel@tonic-gate {
5777c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
5787c478bd9Sstevel@tonic-gate 	int num_protos;
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
5817c478bd9Sstevel@tonic-gate 	    B_TRUE)) == NULL)
5827c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	if (delipsecalgbyname_common(name, current_proto, B_TRUE))
5857c478bd9Sstevel@tonic-gate 		return (write_new_algfile(protos, num_protos));
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	_clean_trash(protos, num_protos);
5887c478bd9Sstevel@tonic-gate 	return (LIBIPSEC_ALGS_DIAG_UNKN_ALG);
5897c478bd9Sstevel@tonic-gate }
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate /*
5927c478bd9Sstevel@tonic-gate  * Delete an algorithm by num + protocol num from /etc/inet/ipsecalgs.
5937c478bd9Sstevel@tonic-gate  */
5947c478bd9Sstevel@tonic-gate int
delipsecalgbynum(int alg_num,int proto_num)5957c478bd9Sstevel@tonic-gate delipsecalgbynum(int alg_num, int proto_num)
5967c478bd9Sstevel@tonic-gate {
5977c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
5987c478bd9Sstevel@tonic-gate 	int i, num_protos;
5997c478bd9Sstevel@tonic-gate 	boolean_t found_match = B_FALSE;
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
6027c478bd9Sstevel@tonic-gate 	    B_TRUE)) == NULL)
6037c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	for (i = 0; i < current_proto->proto_numalgs; i++) {
6067c478bd9Sstevel@tonic-gate 		if (!found_match) {
6077c478bd9Sstevel@tonic-gate 			if (current_proto->proto_algs[i]->a_alg_num ==
6087c478bd9Sstevel@tonic-gate 			    alg_num) {
6097c478bd9Sstevel@tonic-gate 				found_match = B_TRUE;
6107c478bd9Sstevel@tonic-gate 				freeipsecalgent(current_proto->proto_algs[i]);
6117c478bd9Sstevel@tonic-gate 			}
6127c478bd9Sstevel@tonic-gate 		} else {
6137c478bd9Sstevel@tonic-gate 			current_proto->proto_algs[i - 1] =
6147c478bd9Sstevel@tonic-gate 			    current_proto->proto_algs[i];
6157c478bd9Sstevel@tonic-gate 		}
6167c478bd9Sstevel@tonic-gate 	}
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	if (found_match) {
6197c478bd9Sstevel@tonic-gate 		current_proto->proto_numalgs--;
6207c478bd9Sstevel@tonic-gate 		return (write_new_algfile(protos, num_protos));
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	_clean_trash(protos, num_protos);
6247c478bd9Sstevel@tonic-gate 	return (LIBIPSEC_ALGS_DIAG_UNKN_ALG);
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate /*
6287c478bd9Sstevel@tonic-gate  * Remove the specified protocol entry from the list of protocols.
6297c478bd9Sstevel@tonic-gate  */
6307c478bd9Sstevel@tonic-gate static void
delipsecproto_common(ipsec_proto_t * protos,int num_protos,ipsec_proto_t * proto)6317c478bd9Sstevel@tonic-gate delipsecproto_common(ipsec_proto_t *protos, int num_protos,
6327c478bd9Sstevel@tonic-gate     ipsec_proto_t *proto)
6337c478bd9Sstevel@tonic-gate {
6347c478bd9Sstevel@tonic-gate 	int i;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	/* free protocol storage */
6377c478bd9Sstevel@tonic-gate 	free(proto->proto_name);
6387c478bd9Sstevel@tonic-gate 	for (i = 0; i < proto->proto_numalgs; i++)
6397c478bd9Sstevel@tonic-gate 		freeipsecalgent(proto->proto_algs[i]);
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	/* remove from list of prototocols */
6427c478bd9Sstevel@tonic-gate 	for (i = (proto - protos + 1); i < num_protos; i++)
6437c478bd9Sstevel@tonic-gate 		protos[i - 1] = protos[i];
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate /*
6477c478bd9Sstevel@tonic-gate  * Add an IPsec protocol to /etc/inet/ipsecalgs.
6487c478bd9Sstevel@tonic-gate  */
6497c478bd9Sstevel@tonic-gate int
addipsecproto(const char * proto_name,int proto_num,ipsecalgs_exec_mode_t proto_exec_mode,uint_t flags)6507c478bd9Sstevel@tonic-gate addipsecproto(const char *proto_name, int proto_num,
6517c478bd9Sstevel@tonic-gate     ipsecalgs_exec_mode_t proto_exec_mode, uint_t flags)
6527c478bd9Sstevel@tonic-gate {
6537c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto, *new_proto;
6547c478bd9Sstevel@tonic-gate 	int i, num_protos;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	/*
6577c478bd9Sstevel@tonic-gate 	 * NOTE:If build_internal_algs returns NULL for any
6587c478bd9Sstevel@tonic-gate 	 *	reason, we will end up clobbering /etc/inet/ipsecalgs!
6597c478bd9Sstevel@tonic-gate 	 */
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	current_proto = proto_setup(&protos, &num_protos, proto_num, B_FALSE);
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	/* check for protocol with duplicate id */
6647c478bd9Sstevel@tonic-gate 	if (current_proto != NULL) {
6657c478bd9Sstevel@tonic-gate 		if ((strcmp(proto_name, current_proto->proto_name) == 0) &&
6667c478bd9Sstevel@tonic-gate 		    (proto_exec_mode == current_proto->proto_exec_mode)) {
6677c478bd9Sstevel@tonic-gate 			/*
6687c478bd9Sstevel@tonic-gate 			 * The current protocol being added matches
6697c478bd9Sstevel@tonic-gate 			 * exactly an existing protocol, we're done.
6707c478bd9Sstevel@tonic-gate 			 */
6717c478bd9Sstevel@tonic-gate 			return (0);
6727c478bd9Sstevel@tonic-gate 		}
6737c478bd9Sstevel@tonic-gate 		if (!(flags & LIBIPSEC_ALGS_ADD_FORCE))
6747c478bd9Sstevel@tonic-gate 			return (LIBIPSEC_ALGS_DIAG_PROTO_EXISTS);
6757c478bd9Sstevel@tonic-gate 		delipsecproto_common(protos, num_protos--, current_proto);
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	/* check for protocol with duplicate name */
6797c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_protos; i++) {
6807c478bd9Sstevel@tonic-gate 		if (strcmp(protos[i].proto_name, proto_name) == 0) {
6817c478bd9Sstevel@tonic-gate 			if (!(flags & LIBIPSEC_ALGS_ADD_FORCE))
6827c478bd9Sstevel@tonic-gate 				return (LIBIPSEC_ALGS_DIAG_PROTO_EXISTS);
6837c478bd9Sstevel@tonic-gate 			delipsecproto_common(protos, num_protos--, &protos[i]);
6847c478bd9Sstevel@tonic-gate 			break;
6857c478bd9Sstevel@tonic-gate 		}
6867c478bd9Sstevel@tonic-gate 	}
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	/* add new protocol */
6897c478bd9Sstevel@tonic-gate 	num_protos++;
6907c478bd9Sstevel@tonic-gate 	new_proto = realloc(protos, num_protos *
6917c478bd9Sstevel@tonic-gate 	    sizeof (ipsec_proto_t));
6927c478bd9Sstevel@tonic-gate 	if (new_proto == NULL) {
6937c478bd9Sstevel@tonic-gate 		_clean_trash(protos, num_protos - 1);
6947c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_NOMEM);
6957c478bd9Sstevel@tonic-gate 	}
6967c478bd9Sstevel@tonic-gate 	protos = new_proto;
6977c478bd9Sstevel@tonic-gate 	new_proto += (num_protos - 1);
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	/* initialize protocol entry */
7007c478bd9Sstevel@tonic-gate 	new_proto->proto_num = proto_num;
7017c478bd9Sstevel@tonic-gate 	new_proto->proto_numalgs = 0;
7027c478bd9Sstevel@tonic-gate 	new_proto->proto_algs = NULL;
7037c478bd9Sstevel@tonic-gate 	new_proto->proto_name = strdup(proto_name);
7047c478bd9Sstevel@tonic-gate 	if (new_proto->proto_name == NULL) {
7057c478bd9Sstevel@tonic-gate 		_clean_trash(protos, num_protos);
7067c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_NOMEM);
7077c478bd9Sstevel@tonic-gate 	}
7087c478bd9Sstevel@tonic-gate 	new_proto->proto_pkg = NULL;
7097c478bd9Sstevel@tonic-gate 	new_proto->proto_algs_pkgs = NULL;
7107c478bd9Sstevel@tonic-gate 	new_proto->proto_algs_npkgs = 0;
7117c478bd9Sstevel@tonic-gate 	new_proto->proto_exec_mode = proto_exec_mode;
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	return (write_new_algfile(protos, num_protos));
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate /*
7177c478bd9Sstevel@tonic-gate  * Delete an IPsec protocol entry from /etc/inet/ipsecalgs.  This also
7187c478bd9Sstevel@tonic-gate  * nukes the associated algorithms.
7197c478bd9Sstevel@tonic-gate  */
7207c478bd9Sstevel@tonic-gate int
delipsecprotobynum(int proto_num)7217c478bd9Sstevel@tonic-gate delipsecprotobynum(int proto_num)
7227c478bd9Sstevel@tonic-gate {
7237c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
7247c478bd9Sstevel@tonic-gate 	int num_protos;
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
7277c478bd9Sstevel@tonic-gate 	    B_TRUE)) == NULL)
7287c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 	delipsecproto_common(protos, num_protos--, current_proto);
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	return (write_new_algfile(protos, num_protos));
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate int
delipsecprotobyname(const char * proto_name)7367c478bd9Sstevel@tonic-gate delipsecprotobyname(const char *proto_name)
7377c478bd9Sstevel@tonic-gate {
7387c478bd9Sstevel@tonic-gate 	int proto_num;
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	proto_num = getipsecprotobyname(proto_name);
7417c478bd9Sstevel@tonic-gate 	if (proto_num == -1)
7427c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	return (delipsecprotobynum(proto_num));
7457c478bd9Sstevel@tonic-gate }
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate /*
7487c478bd9Sstevel@tonic-gate  * Implement these in libnsl since these are read-only operations.
7497c478bd9Sstevel@tonic-gate  */
7507c478bd9Sstevel@tonic-gate int *
getipsecprotos(int * nentries)7517c478bd9Sstevel@tonic-gate getipsecprotos(int *nentries)
7527c478bd9Sstevel@tonic-gate {
7537c478bd9Sstevel@tonic-gate 	return (_real_getipsecprotos(nentries));
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate int *
getipsecalgs(int * nentries,int proto_num)7577c478bd9Sstevel@tonic-gate getipsecalgs(int *nentries, int proto_num)
7587c478bd9Sstevel@tonic-gate {
7597c478bd9Sstevel@tonic-gate 	return (_real_getipsecalgs(nentries, proto_num));
7607c478bd9Sstevel@tonic-gate }
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate const char *
ipsecalgs_diag(int diag)7637c478bd9Sstevel@tonic-gate ipsecalgs_diag(int diag)
7647c478bd9Sstevel@tonic-gate {
7657c478bd9Sstevel@tonic-gate 	switch (diag) {
7667c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALG_EXISTS:
767a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "Algorithm already exists"));
7687c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_PROTO_EXISTS:
769a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "Protocol already exists"));
7707c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_UNKN_PROTO:
771a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "Unknown protocol"));
7727c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_UNKN_ALG:
773a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "Unknown algorithm"));
7747c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_NOMEM:
775a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "Out of memory"));
7767c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILEOPEN:
777a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "open() failed"));
7787c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILEFDOPEN:
779a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "fdopen() failed"));
7807c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILELOCK:
781a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "lockf() failed"));
7827c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILERENAME:
783a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "rename() failed"));
7847c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE:
785a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "write to file failed"));
7867c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILECHMOD:
787a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "chmod() failed"));
7887c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILECHOWN:
789a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "chown() failed"));
7907c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILECLOSE:
791a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "close() failed"));
7927c478bd9Sstevel@tonic-gate 	default:
793a7485808Smarkfen 		return (dgettext(TEXT_DOMAIN, "failed"));
7947c478bd9Sstevel@tonic-gate 	}
7957c478bd9Sstevel@tonic-gate }
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate /*
7987c478bd9Sstevel@tonic-gate  * Get the execution mode corresponding to the specified protocol.
7997c478bd9Sstevel@tonic-gate  * Returns 0 on success, one of the LIBIPSEC_ALGS_DIAG_* values on
8007c478bd9Sstevel@tonic-gate  * failure.
8017c478bd9Sstevel@tonic-gate  */
8027c478bd9Sstevel@tonic-gate int
ipsecproto_get_exec_mode(int proto_num,ipsecalgs_exec_mode_t * exec_mode)8037c478bd9Sstevel@tonic-gate ipsecproto_get_exec_mode(int proto_num, ipsecalgs_exec_mode_t *exec_mode)
8047c478bd9Sstevel@tonic-gate {
8057c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
8067c478bd9Sstevel@tonic-gate 	int num_protos;
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
8097c478bd9Sstevel@tonic-gate 	    B_TRUE)) == NULL)
8107c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	*exec_mode = current_proto->proto_exec_mode;
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	_clean_trash(protos, num_protos);
8157c478bd9Sstevel@tonic-gate 	return (0);
8167c478bd9Sstevel@tonic-gate }
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate /*
8197c478bd9Sstevel@tonic-gate  * Set the execution mode of the specified protocol. Returns 0 on success,
8207c478bd9Sstevel@tonic-gate  * or one of the LIBIPSEC_ALGS_DIAG_* values on failure.
8217c478bd9Sstevel@tonic-gate  */
8227c478bd9Sstevel@tonic-gate int
ipsecproto_set_exec_mode(int proto_num,ipsecalgs_exec_mode_t exec_mode)8237c478bd9Sstevel@tonic-gate ipsecproto_set_exec_mode(int proto_num, ipsecalgs_exec_mode_t exec_mode)
8247c478bd9Sstevel@tonic-gate {
8257c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
8267c478bd9Sstevel@tonic-gate 	int num_protos;
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
8297c478bd9Sstevel@tonic-gate 	    B_TRUE)) == NULL)
8307c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	current_proto->proto_exec_mode = exec_mode;
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	return (write_new_algfile(protos, num_protos));
8357c478bd9Sstevel@tonic-gate }
836